임베디드 리눅스 부팅 과정, 부트로더부터 유저랜드까지
임베디드 리눅스 부팅은 부트로더가 RAM과 디바이스 트리를 준비한 뒤 커널을 호출하고, 커널이 하드웨어를 서술한 뒤 유저랜드 init을 실행하는 순서로 진행됩니다. 이 글은 U-Boot와 커널 공식 문서를 기준으로 그 단계를 정리합니다.
이 글은 U-Boot와 리눅스 커널 공식 문서를 기준으로 한 일반 부팅 순서 안내이며, SoC ROM 코드와 보드 BSP, 배포판 init에 따라 세부 단계는 달라질 수 있습니다.
임베디드 리눅스 부팅은 어떤 단계로 나뉘나?
한 줄 답: SoC ROM이 다음 로더를 시작한 뒤 xPL, U-Boot proper, 커널, 유저랜드 init으로 제어가 이어지며, 세부 ROM 단계는 SoC마다 다릅니다.
리셋 뒤에는 SoC ROM 또는 first-stage가 다음 로더를 적재하고 시작합니다. 이 ROM 코드는 제조사별 구현이며 리눅스 커널 문서가 전체 단계를 규정하지 않습니다. 이후 xPL과 U-Boot proper가 커널 Image·DTB·선택적 initrd를 준비하고 커널로 제어를 넘깁니다. 다음 표는 특정 보드 로그가 아닌 일반적인 런타임 부팅 순서를 나타냅니다.
| 단계 | 일반적인 역할 |
|---|---|
| ROM | SoC ROM 또는 first-stage가 다음 로더를 적재하고 시작합니다. |
| xPL | 선택적인 TPL·VPL·SPL 단계가 초기 하드웨어를 준비하고 다음 이미지를 적재합니다. |
| U-Boot proper | 명령행과 부팅 로직으로 커널 Image·DTB·선택적 initrd를 준비합니다. |
| kernel | 전달받은 RAM과 디바이스 트리를 기준으로 커널 초기화를 수행합니다. |
| init | 커널이 유저랜드의 init을 실행해 사용자 공간으로 제어를 넘깁니다. |
ROM 단계의 구체적인 코드와 세부 순서는 SoC 제조사에 따라 달라집니다. 표의 단계는 ROM에서 xPL, U-Boot proper, 커널, init으로 이어지는 일반적인 순서를 보여 줍니다.
보드가 전용 컴퓨터라는 개념은 임베디드 시스템이란에서 확인할 수 있습니다.
U-Boot TPL·SPL과 U-Boot proper는 무엇을 하나?
한 줄 답: xPL의 선택 단계는 초기 하드웨어 준비와 다음 이미지 적재를 맡고, SPL은 SDRAM을 준비해 U-Boot proper를 적재하며 U-Boot proper는 명령행과 부팅 로직을 제공합니다.
U-Boot Generic xPL은 TPL·VPL·SPL을 필요에 따라 선택하는 초기 로더 단계로 설명합니다. 많은 보드는 SPL을 사용하지만 TPL을 사용하는 보드는 더 적습니다. 따라서 모든 보드가 TPL을 거치거나 같은 xPL 조합을 거친다고 볼 수 없습니다.
TPL은 매우 이른 초기화를 가능한 작게 수행한 뒤 SPL을 적재합니다. VPL이 활성화된 경우 TPL은 VPL을 적재할 수 있습니다. VPL은 A/B 검증 부팅이 활성화된 경우 여러 SPL 바이너리 중 하나를 선택할 수 있는 선택적 검증 단계이며, 구현은 현재 진행 중이고 현재는 SPL로 부팅합니다.
SPL은 SDRAM을 설정하고 U-Boot proper를 적재합니다. 또한 다른 펌웨어를 적재할 수 있습니다. 다른 사용례로는 ARM Trusted Firmware의 BL31을 시작한 뒤 BL31이 BL33으로서 main U-Boot를 호출하게 하는 경우, EDK II·리눅스 커널을 시작하는 경우, RISC-V OpenSBI를 시작해 main U-Boot를 호출하게 하는 경우가 있습니다.
U-Boot proper는 명령행과 부팅 로직을 제공합니다. U-Boot Standard Boot 개요의 Standard Boot는 사용자 지정 스크립트 없이 운영체제를 부팅하는 U-Boot의 내장 방식입니다.
bootdev는 배포판을 저장하거나 접근할 수 있는 장치이며 MMC와 Ethernet 등이 예시입니다. bootmeth는 bootdev를 스캔해 bootflow를 찾는 방법이고, bootflow는 부팅 방법을 설명하는 정보입니다. 대표 명령은 bootflow scan -lb입니다.
부팅 경로에서는 커널 Image와 DTB, 선택적 initrd를 적재한 뒤 커널 진입점으로 제어를 넘깁니다. 커널은 이때 부트로더가 준비한 RAM과 디바이스 트리를 전달받습니다.
U-Boot의 Devicetree Control은 flattened devicetree를 이용해 U-Boot의 런타임 구성을 정하는 방식입니다. 이 control DT는 U-Boot의 펌웨어 DT이며 커널에 넘기는 DTB와 다르고, x0로 전달되는 커널 DTB를 대신하지 않습니다. SPL에서 사용하는 DT는 필터링된 부분집합으로, /alias·/chosen·/config가 필수로 남고 bootph-all 또는 bootph-pre-ram이 붙은 노드도 포함됩니다.
커널은 디바이스 트리를 어떻게 받나?
한 줄 답: AArch64 부트로더는 RAM과 DT를 준비해 Image를 호출하며, 주 CPU의 x0에는 시스템 RAM에 있는 DTB의 물리 주소를 전달합니다.
부트로더는 시스템 RAM을 설정하고 초기화하며 디바이스 트리를 준비한 뒤 커널 Image를 호출해야 합니다. 커널 이미지의 압축 해제는 선택 사항입니다. Booting AArch64 Linux는 AArch64 커널이 현재 자체 압축 해제기를 제공하지 않으므로 Image.gz를 사용할 때 부트로더가 압축을 풀어야 하며, 비압축 Image도 사용할 수 있다고 설명합니다.
주 CPU가 커널을 호출할 때 x0에는 시스템 RAM에 있는 DTB의 물리 주소를 넣고 x1·x2·x3은 0으로 설정합니다. 이때 MMU는 꺼져 있어야 합니다. Image 헤더의 매직 값은 리틀엔디언 0x644d5241이며, 바이트 표현은 ARM\x64입니다.
DTB는 8바이트 경계에 놓여야 하며 2MB를 초과할 수 없습니다. initrd 또는 initramfs를 전달하는 경우에는 해당 이미지가 커널 Image 전체를 포함하는 1GB 정렬 물리 메모리 창 안에 완전히 있어야 하며, 그 창의 크기는 최대 32GB입니다.
Linux and the Devicetree에 따르면 리눅스는 디바이스 트리를 플랫폼 식별, 런타임 구성, 디바이스 생성이라는 세 가지 목적으로 사용합니다. compatible은 정확한 머신 이름으로 시작하고 더 일반적인 SoC 문자열이 뒤따르는 목록이며, 가장 구체적인 항목부터 가장 일반적인 항목 순으로 정렬합니다.
/chosen 노드는 부팅 인자와 initrd 정보를 전달하는 위치입니다. bootargs에는 커널 부팅 인자를 담고, initrd-start와 initrd-end는 initrd 범위를 나타내며 initrd-end는 initrd 이미지 다음의 첫 주소입니다.
FDT는 부팅 시 전달하고 수정할 수 있는 평탄화된 디바이스 트리 표현이며, DTB는 그 바이너리 형태입니다. 역사적으로 U-Boot, kexec 및 다른 부트로더는 DTB를 전달하고 부팅 시 dtb를 수정하도록 변경되었습니다.
커널 초기화 이후 유저랜드는 어떻게 시작되나?
한 줄 답: 커널은 초기화를 마친 뒤 보통 /sbin/init을 실행하며, initramfs가 있으면 실제 루트 파일시스템을 마운트하기 전에 그 안의 /init이 먼저 실행될 수 있습니다.
커널은 초기화를 마친 뒤 유저랜드의 init을 실행하며, 경로는 흔히 /sbin/init입니다. systemd 또는 BusyBox init을 선택하는 것은 배포판의 구성이고, 커널이 특정 init 구현을 요구하는 사항은 아닙니다.
initramfs가 전달된 경우에는 실제 루트 파일시스템을 마운트하기 전에 initramfs가 초기 루트 역할을 할 수 있으며, 그 안의 /init이 먼저 실행될 수 있습니다. 이는 선택적인 경로이므로 모든 보드에서 initramfs가 필수인 것은 아닙니다.
부팅에 올라가는 이미지가 빌드 산출물일 때의 배경은 Yocto/Poky에서 확인할 수 있습니다.
부팅이 멈추면 어느 단계를 먼저 보나?
한 줄 답: 마지막으로 확인되는 경계에 따라 ROM·xPL, U-Boot의 적재 경로, 커널의 DT·rootfs·init, 유저랜드의 init·rootfs 순으로 범위를 좁힙니다.
UART 출력 자체가 나오기 전에 멈추거나 U-Boot 프롬프트 이전에서 멈추면 ROM·TPL·SPL·클록·DRAM 초기화 구간을 먼저 확인합니다. 이 범위는 아직 U-Boot 명령행에 도달하기 전의 단계입니다.
U-Boot 프롬프트는 보이지만 커널로 넘어가지 않으면 커널 Image·DTB의 적재 경로와 주소, DTB 전달 조건을 확인합니다. 커널이 유저랜드로 넘어가기 전에 패닉하면 디바이스 트리·rootfs·init을 확인 대상으로 좁힙니다.
유저랜드에서 실패하면 init과 rootfs를 우선 확인합니다. 이 방법은 특정 보드 로그를 전제하지 않고 마지막으로 확인된 단계와 다음 단계 사이를 나누어 보는 일반적인 분리 방법입니다.
FAQ에서 부팅 단계는 무엇을 보면 되나?
한 줄 답: TPL과 SPL의 역할 차이, AArch64 x0의 DTB 전달, /chosen, 선택적 initramfs, init 실행 순서만 짧게 확인합니다.
| 질문 | 답변 |
|---|---|
| TPL과 SPL은 어떻게 다른가? | TPL은 매우 이른 초기화를 작게 수행하고 SPL 또는 VPL을 적재하며, SPL은 SDRAM을 설정하고 U-Boot proper를 적재합니다. |
| AArch64에서 DTB는 어떻게 전달되는가? | 주 CPU의 x0에 시스템 RAM 내 DTB의 물리 주소를 넣고 x1·x2·x3은 0으로 설정합니다. |
/chosen 노드에는 무엇이 들어가는가? | bootargs, initrd-start, initrd-end로 부팅 인자와 initrd 범위를 전달합니다. |
| initramfs는 필수인가? | 아닙니다. 선택적 초기 루트로서 실제 루트 파일시스템을 마운트하기 전에 /init을 실행할 수 있습니다. |
| init은 무엇인가? | 커널이 실행하는 유저랜드 시작 프로그램이며 흔히 /sbin/init입니다. systemd 또는 BusyBox init 여부는 배포판의 선택입니다. |
관련 글은 무엇을 보면 되나?
한 줄 답: 전용 컴퓨터라는 개념은 정의 글에서, 부팅 이미지의 빌드 배경은 Yocto/Poky 글에서 확인합니다.
- 임베디드 시스템이란 — 보드가 전용 컴퓨터라는 정의를 확인하는 관련 글입니다.
- Yocto/Poky — 부팅에 올라가는 이미지가 빌드 산출물일 때의 배경을 확인하는 관련 글입니다.