사용자 공간 응용 프로그램에 대한 질문이지만 들으십시오!
기능적으로 리눅스 배포판을 부팅하려면 세 가지 “응용 프로그램”이 필요합니다.
-
부트 로더-내장 된 경우 일반적으로 U-Boot이지만 어려운 요구 사항은 아닙니다.
-
커널-매우 간단합니다.
-
루트 파일 시스템-셸없이 부팅 할 수 없습니다. 커널이 부팅되는 파일 시스템과
init
형식을 포함합니다.
내 질문은 # 3과 관련이 있습니다. 누군가가 최소한의 rootfs를 만들고 싶었다면 (이 질문에서는 GUI가없고 쉘만이라고합시다) 쉘로 부팅하기 위해 어떤 파일 / 프로그램이 필요합니까?
답변
그것은 전적으로 장치에서 어떤 서비스를 원하느냐에 달려 있습니다.
프로그램들
Linux를 쉘로 직접 부팅 할 수 있습니다 . 셸을 갖고 싶어하는 프로덕션 환경에서는 그다지 유용하지 않지만 대화 형 부트 로더가있는 경우 개입 메커니즘으로 유용 init=/bin/sh
합니다. 커널 명령 줄로 전달 하십시오. 모든 Linux 시스템 (및 모든 유닉스 시스템)에는 Bourne / POSIX 스타일 쉘이 /bin/sh
있습니다.
쉘 유틸리티 세트가 필요하다 . BusyBox 는 매우 일반적인 선택입니다. 이 파일을 텍스트 조작 (대한 쉘 및 일반 유틸리티가 포함되어 cp
, grep
설치, 네트워킹, …) ( ping
, ifconfig
, …), 프로세스 조작 ( ps
, nice
, …), 및 기타 다양한 시스템 도구 ( fdisk
, mount
, syslogd
, …). BusyBox는 매우 구성이 가능합니다. 컴파일 타임에 원하는 도구와 개별 기능을 선택하여 응용 프로그램에 적합한 크기 / 기능 저하를 얻을 수 있습니다. 외에도에서 sh
, 당신은 정말없이 아무것도 할 수있는 최소한의 mount
, umount
그리고 halt
, 그러나 또한이없는 것이 전형적인 것 cat
, cp
, mv
, rm
,mkdir
, rmdir
, 각 유틸리티에 대한 심볼릭 링크가 있습니다.ps
, sync
그리고 몇 가지 더. BusyBox는 단일 바이너리로 설치됩니다.busybox
일반적인 유닉스 시스템의 첫 번째 프로세스를라고 init
합니다. 그 임무는 다른 서비스를 시작하는 것입니다. BusyBox에는 초기화 시스템이 포함되어 있습니다. init
바이너리 (보통에 위치 /sbin
) 외에도 시작해야 할 서비스를 나타내는 구성 파일 (보통 /etc/inittab
— 현대적인 일부 대체 파일은 해당 파일로 대체되지만 소형 임베디드 시스템에서는 찾을 수 없음)이 필요합니다. 그리고 언제. BusyBox의 경우 /etc/inittab
선택 사항입니다. 누락 된 경우 콘솔과 스크립트에 루트 쉘이 있습니다./etc/init.d/rcS
이 표시되고 부팅시 (기본 위치)가 실행됩니다.
물론 장치가 유용한 기능을 수행 할 수있는 프로그램 이외에도 필요한 모든 것입니다. 예를 들어 OpenWrt 변형을 실행하는 내 홈 라우터 에서 유일한 프로그램은 BusyBox입니다.nvram
(NVRAM의 설정을 읽고 변경하기위한)와 네트워킹 유틸리티입니다.
모든 실행 파일이 정적으로 링크하지 않는 한, 당신은 (동적 로더가 필요합니다 ld.so
libc의의와 프로세서 아키텍처의 선택에 따라 다른 이름으로 호출 할 수 있습니다) 모든 동적 라이브러리 ( /lib/lib*.so
이들의 일부를 아마를, /usr/lib
에서 요구하는) 이러한 실행 파일.
디렉토리 구조
파일 시스템 계층 구조 표준 리눅스 시스템의 공통의 디렉토리 구조를 설명합니다. 데스크탑 및 서버 설치에 적합합니다. 임베디드 시스템에서는 많은 부분을 생략 할 수 있습니다. 일반적인 최소값은 다음과 같습니다.
/bin
: 실행 프로그램 (일부/usr/bin
대신 있을 수 있음 )./dev
: 장치 노드 (아래 참조)/etc
: 구성 파일/lib
: 동적 로더를 포함한 공유 라이브러리 (모든 실행 파일이 정적으로 링크되지 않은 경우)/proc
: proc 파일 시스템의 마운트 지점/sbin
: 실행 가능한 프로그램. 와 구별/bin
IS/sbin
시스템 관리자 만에게 유용한 프로그램이지만,이 구별은 임베디드 디바이스에 의미가 없습니다. 에/sbin
대한 심볼릭 링크를 만들 수 있습니다/bin
./mnt
: 유지 관리 중 스크래치 마운트 지점으로 읽기 전용 루트 파일 시스템에 편리/sys
: sysfs 파일 시스템의 마운트 지점/tmp
: 임시 파일의 위치 (종종tmpfs
마운트)/usr
: 서브 디렉토리를 포함하고bin
,lib
하고sbin
./usr
루트 파일 시스템에없는 추가 파일에 대해 존재합니다. 이것이 없으면/usr
루트 디렉토리에 심볼릭 링크를 만들 수 있습니다 .
장치 파일
다음은 최소한의 일반적인 항목입니다 /dev
.
console
full
(쓰기는 항상 “장치에 남은 공간 없음”을보고합니다)log
(syslogd
BuyBox와 같은) 데몬이 읽는 경우 (프로그램이 로그 항목을 보내는 데 사용하는 소켓 )null
(항상 비어있는 파일처럼 작동)ptmx
그리고pts
디렉토리 , 당신은 사용하려면 의사 단자를 (콘솔에 비해 즉 어떤 터미널 다른) – 장치가 네트워크에 연결되어 예를 들어, 경우에 당신은 텔넷 또는 ssh에서 원하는random
(임의의 바이트를 반환, 블로킹의 위험이 있습니다)tty
(항상 프로그램 터미널을 지정합니다)urandom
(임의의 바이트를 반환하고 차단하지는 않지만 새로 부팅 한 장치에서는 무작위가 아닐 수 있음)zero
(무한한 null 바이트 시퀀스를 포함합니다)
/dev
직렬 포트, 스토리지 등 하드웨어에 대한 항목이 필요합니다 (네트워크 인터페이스 제외 ).
임베디드 장치의 경우 일반적으로 루트 파일 시스템에서 직접 장치 항목을 작성합니다. 고급 시스템에는 항목 MAKEDEV
을 작성하기 위해 호출되는 스크립트가 /dev
있지만 내장 시스템에서 스크립트는 종종 이미지에 번들로 제공되지 않습니다. 일부 하드웨어를 핫 플러그 할 수있는 경우 (예 : 장치에 USB 호스트 포트가있는 경우) udev/dev
로 관리해야합니다 (루트 파일 시스템에 최소 세트가있을 수 있음).
부팅시 작업
루트 파일 시스템 외에도 정상적인 작동을 위해 몇 가지를 더 마운트해야합니다.
- procfs on
/proc
(거의 없어서는 안될) - sysfs on
/sys
(거의 필수 불가결) tmpfs
파일 시스템 켜기/tmp
(플래시 또는 읽기 전용 일 수있는 루트 파일 시스템이 아닌 RAM에있는 임시 파일을 프로그램이 만들 수 있도록)/dev
동적 인 경우 tmpfs, devfs 또는 devtmpfs (위의“장치 파일”의 udev 참조)- devpts 에
/dev/pts
당신이 [의사 터미널을 사용하려면 (약 발언 참조pts
위)
당신은 할 수 있습니다 /etc/fstab
파일 및 전화를 mount -a
하거나 실행 mount
수동.
시작 시스템 로그 (물론 데몬 klogd
경우 생성을위한 커널 로그를 syslogd
당신이 쓰기 로그에 어떤 장소가있는 경우, 프로그램이 알아서하지 않습니다).
그런 다음 장치는 응용 프로그램 별 서비스를 시작할 수 있습니다.
루트 파일 시스템을 만드는 방법
이것은 길고 다양한 이야기이므로 여기서 할 것은 몇 가지 지침을 제시하는 것입니다.
루트 파일 시스템은 RAM (ROM 또는 플래시의 (일반적으로 압축 된) 이미지에서로드 된) 또는 디스크 기반 파일 시스템 (ROM 또는 플래시에 저장된)에서 유지되거나 네트워크에서로드 될 수 있습니다 (종종 TFTP를 통해 ) . 루트 파일 시스템이 RAM에 있으면 부트시 내용이 생성되는 RAM 파일 시스템 인 initramfs로 설정하십시오 .
임베디드 시스템의 루트 이미지를 조립하기위한 많은 프레임 워크가 존재합니다. BusyBox FAQ 에는 몇 가지 지침이 있습니다 . Buildroot 는 널리 사용되는 것으로 Linux 커널 및 BusyBox와 유사한 설정으로 전체 루트 이미지를 작성할 수 있습니다. OpenEmbedded 는 또 다른 프레임 워크입니다.
Wikipedia에는 널리 사용되는 임베디드 Linux 배포판 의 (불완전한) 목록이 있습니다 . 가까이에있을 수있는 임베디드 Linux의 예로는 네트워크 장치 용 OpenWrt 운영 체제 제품군 (팅커의 홈 라우터에서 인기 있음)이 있습니다. 경험을 통해 배우고 싶다면 Scratch 에서 Linux를 사용해 볼 수 있지만 임베디드 장치가 아닌 취미를 위해 데스크탑 시스템에 맞춰져 있습니다.
Linux vs Linux 커널에 대한 참고 사항
Linux 커널에 구워진 유일한 동작은 부팅시 시작된 첫 번째 프로그램입니다. ( 여기서 initrd 및 initramfs의 미묘한 부분 은 다루지 않을 것입니다 .) 전통적으로 init 라고하는이 프로그램 에는 프로세스 ID 1이 있으며 특정 권한 ( KILL 신호에 대한 면역 ) 및 책임 ( 고아 제거 )이 있습니다. 당신은 리눅스 커널 시스템을 실행하고 첫 번째 과정으로 원하는대로 시작,하지만 당신이해야하는 것은 리눅스 커널을 기반으로 운영 체제이며, 일반적으로 “리눅스”라고하지 무엇을 할 수 – 리눅스 에서 상식 용어의하는 것입니다 유닉스 , 그 커널을가 -like 운영 체제 Linux 커널. 예를 들어, Android는 Unix와는 다르지만 Linux 커널을 기반으로하는 운영 체제입니다.
답변
파일 시스템에 배치 된 하나의 정적으로 링크 된 실행 파일 만 있으면됩니다. 다른 파일이 필요하지 않습니다. 그 실행 파일은 init 프로세스입니다. busybox 일 수 있습니다. 그것은 당신에게 쉘과 다른 유틸리티를 제공합니다. busybox에서 수동으로 명령을 실행하여 루트 파일 시스템 읽기-쓰기를 마운트하고, / dev 노드를 작성하고, 실제 초기화를 실행하는 등의 방법으로 완전한 기능을 수행 할 수 있습니다.
답변
쉘 유틸리티가 필요하지 않으면 정적으로 링크 된 mksh
바이너리 (예 : Linux / i386의 klibc – 130K)가 필요합니다. 당신은 필요 /linuxrc
하거나 /init
또는 /sbin/init
스크립트를 그 바로 호출 mksh -l -T!/dev/tty1
루프에서 :
#!/bin/mksh
while true; do
/bin/mksh -l -T!/dev/tty1
done
이 -T!$tty
옵션은 최근에 추가 된 것으로 mksh
, 주어진 터미널에서 새로운 쉘을 생성하고 기다립니다. (그 전에는 -T-
프로그램 -T$tty
을 실행하고 터미널에서 스폰 할 때까지 기다리지 않고 기다릴 수는 없었습니다. 그리 좋지 않았습니다.)이 -l
옵션은 단순히 로그인 쉘 ( /etc/profile
, ~/.profile
및 ~/.mkshrc
) 을 실행하도록 지시합니다 .
이것은 귀하의 터미널이 /dev/tty1
대체 라고 가정합니다 . (더 많은 마법을 사용하면 터미널을 자동으로 찾을 수 있습니다. /dev/console
모든 작업 제어를 제공하지 않습니다.)
/dev
이 작업을 수행하려면 몇 개의 파일이 필요합니다 .
- / dev / console
- / dev / null
- / dev / tty
- / dev / tty1
커널 옵션으로 부팅하면 채우지 devtmpfs.mount=1
않아도 /dev
되며, 빈 디렉토리 (마운트 포인트로 사용하기에 적합)로 만드십시오.
일반적으로 klibc, busybox, beastiebox, toybox 또는 toolbox의 일부 유틸리티를 원하지만 실제로는 필요하지 않습니다.
~/.mkshrc
$ PS1 및 일부 기본 쉘 별명 및 기능을 설정 하는 파일 을 추가 할 수 있습니다 .
mksh (및 샘플 mkshrc 파일)와 klibc-utils 만 사용하여 Linux / m68k에 대해 171K 압축 (371K 비 압축) initrd를 한 번 만들었습니다. (이것은 -T! 이전에 쉘에 추가되었으므로 /dev/tty2
대신 로그인 쉘을 생성 하고 사용자에게 터미널을 전환하라는 메시지를 콘솔에 에코했습니다.) 정상적으로 작동합니다.
이것은 실제로 최소한의 설정입니다. 다른 답변은 다소 기능이 뛰어난 시스템에 대한 훌륭한 조언을 제공합니다. 이것은 특별한 경우입니다.
면책 조항 : 저는 mksh 개발자입니다.
답변
최소한의 init hello world 프로그램 단계별
무한 루프로 끝나는 종속성없이 hello world를 컴파일하십시오. init.S
:
.global _start
_start:
mov $1, %rax
mov $1, %rdi
mov $message, %rsi
mov $message_len, %rdx
syscall
jmp .
message: .ascii "FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n"
.equ message_len, . - message
우리는 sys_exit
커널 패닉을 사용할 수 없습니다 .
그때:
mkdir d
as --64 -o init.o init.S
ld -o init d/init.o
cd d
find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz
ROOTFS_PATH="$(pwd)/../rootfs.cpio.gz"
이것은 hello world at에서 파일 시스템을 생성하는데 /init
, 이것은 커널이 실행되는 최초의 userland 프로그램입니다. 또한 파일을 더 추가 d/
할 수 /init
있으며 커널이 실행될 때 프로그램 에서 액세스 할 수 있습니다 .
그런 다음 cd
Linux 커널 트리에 빌드는 평소와 같이 QEMU에서 실행됩니다.
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.9
make mrproper
make defconfig
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd "$ROOTFS_PATH"
그리고 당신은 라인을 볼 수 있습니다 :
FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR
에뮬레이터 화면에서! 마지막 줄이 아니므로 조금 더 살펴 봐야합니다.
C 프로그램을 정적으로 연결하면 C 프로그램을 사용할 수도 있습니다.
#include <stdio.h>
#include <unistd.h>
int main() {
printf("FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n");
sleep(0xFFFFFFFF);
return 0;
}
와:
gcc -static init.c -o init
USB가 켜진 상태에서 실제 하드웨어에서 실행할 수 있습니다 /dev/sdX
.
make isoimage FDINITRD="$ROOTFS_PATH"
sudo dd if=arch/x86/boot/image.iso of=/dev/sdX
이 주제에 대한 훌륭한 소스 : http://landley.net/writing/rootfs-howto.html 또한 gen_initramfs_list.sh
프로세스를 자동화하는 데 도움이되는 Linux 커널 소스 트리의 스크립트 인 사용법도 설명합니다 .
다음 단계 : 시스템과 상호 작용할 수 있도록 BusyBox 설정 : https://github.com/cirosantilli/runlinux
Ubuntu 16.10, QEMU 2.6.1에서 테스트되었습니다.