들어가며
이전에 포스팅한 글에서 BeagleBone Black의 부팅 시 예상과 다르게 SD카드로 부팅되는 문제의 원인을 찾기 위해서 ROM Boot Loader 부터 시작해서 U-Boot로 넘어가는 부팅 로직을 확인했다. 이 과정이 꽤나 도움이 되는 부분이라고 생각이 들어서, 아예 SPL과 U-Boot 쪽도 쭉 살펴보면서 커널을 올리고 루트파일시스템이 탑재되면서 OS가 시작되는 과정을 살펴보려고 한다. 출발!
ㅤ
우선 큰 그림부터
사용자 서비스가 올라올 때 까지 무슨 일이 일어나는지를 한 번 보자.
- 전원을 공급한다
- 보드에 내장된 ROM Boot Loader를 실행한다
- 이때 어떤 장치에서 부팅할 지 결정함
- Secondary Program Loader를 SRAM으로 옮김
- SPL으로 Jump!
- SRAM에 올라온 Secondary Program Loader를 실행한다
- RAM(메인메모리)을 초기화하는 역할
- U-Boot 이미지를 RAM에 올림
- U-Boot 로 Jump!
- RAM에 올라온 U-Boot를 실행한다
- 페리퍼럴들을 초기화
- 커널 로드 / 디바이스 트리 로드
- 커널로 Jump!
- 리눅스 커널을 시작한다
- 커널의 압축을 해제
- 하드웨어의 초기화
- 루트파일시스템 마운트
- 초기 프로세스 실행
- 사용자 서비스 시작
ㅤ
생각보다 글이 길어져서, 이번 글에서는 2단계인 RBL에 대해서만 살펴본다. 그 다음 단계에 대해서는 다음 글을 기다리시라.
ㅤ
ROM Boot Loader
RBL의 역할은 요러하다.
- SYSBOOT 핀을 읽고 어떤 장치부터 탐색할 지 결정
- 각 장치에서 SPL(MLO)를 탐색하고 내부 SRAM으로 복사
- SPL 코드의 첫 줄로 Jump
ㅤ
그리고 RBL의 특징은 다음과 같다.
- 보드 내부에 제조사가 심어뒀기에 수정이 불가능한 1차 부트로더 (Root of Trust)
- 칩이 켜지는 순간 가장 먼저 CPU가 실행하는 코드
ㅤ
이전에 라즈베리파이를 가지고 공부할 때는 브로드컴의 설계 자체가 GPU 우선이라서 RBL이 GPU에서 도는 쪽으로 설계되고 만들어져있다고 들었었는데, 이번에야말로 CPU에서 돌아가는 부트로더를 살펴볼 수 있게 되었다. 다만 RBL 자체는 취약점의 노출을 막고자 소스코드를 공개하지 않고 있다고 한다. 어차피 얘는 소스코드를 알더라도 수정할 수 없기 때문에 변경 테스트를 못하기도 하고.
ㅤ
그래도 지난 번 글에서 봤던 것처럼 레퍼런스 메뉴얼에 어떤 방식으로 작동하는지 시퀀스를 다이어그램으로 알려준 게 있다. 요걸 보고 대략적인 동작에 대해서 파악할 수 있다. RBL은 아래 다이어그램에서 볼 수 있는 Start up 과정과 Booting 과정 모두를 포함한다.
ㅤ
블럭 다이어그램 상에서 RBL이 하는 일을 살펴보자면
크게 보자면 아래의 컬러링 된 부분에서 역할을 수행한다.
- 프로세서 내부 ROM에 들어있는 내장된 RBL을 CPU가 실행하면서
- MMC / SD 카드에 들어있는 SPL을 가져와서 프로세스 내부 SRAM에 올리고 실행하기

어떻게 RBL의 코드를 CPU가 실행하기 시작하지
그렇다면 RBL은 누가 실행시켜주는거지? 에 대해서는 전기적으로 미리 심어져있는 대로 동작하는 것이다. 따로 소프트웨어가 처리해주는 것이 아니라 하드웨어 로직 (게이트의 동작)에 의해서 수행된다. 단순히 PC를 특정 위치에 세팅하고 CPU 파이프라인을 가동시키면 뚝딱뚝딱 돌아가기 시작한다.
ㅤ
신뢰의 시작점(Root of Trust)이란?
앞서 ROM Boot Loader를 Root of Trust 라고 소개한다. RBL을 신뢰의 시작점으로 보는 이유는 RBL은 남이 수정할 수 없기 때문에 믿을 수 있는 영역이라고 보는 것이다.
ㅤ
내 리눅스 환경이 지금 믿을 수 있는가? 에 대해서 답하기 위해서는 리눅스를 실행시킬 때 완전무결하게 실행했는가를 판단해야한다. 그렇다면 그 리눅스의 Booting 환경이 믿을 수 있는지를 보려면 커널의 실행을 믿을 수 있어야 하고, U-Boot를 믿을 수 있어야 하고, SPL을 믿을 수 있어야 한다. 이렇게 쭉 내려가다 보면 결국 전원이 들어왔을 때 가장 처음 실행되는 프로그램인 RBL을 믿을 수 있어야 한다.
ㅤ
이때 RBL은 프로세서에 탑재되어 있는 프로그램이고, 누가 함부로 수정할 수 없다. 그렇기에 이 RBL은 언제나 믿을 수 있는 프로그램이며 신뢰의 시작점이 되는 것이다.
ㅤ
RBL의 실행 이후에 U-Boot를 실행하기 위한 SPL(Secondary Program Loader)을 가져오는 과정에서 이 파일을 믿을 수 있는지 검사하기 위해서 Secure Boot 단계를 거친다. 이 검증 단계를 통해서 “RBL 이후의 SPL 단계를 믿을 수 있다”고 보면서 신뢰 사슬(Chain of Trust)를 만들어간다. 그리고 그게 쭉 이어지면 커널의 실행 환경을 믿을 수 있다고 볼 수 있다.
ㅤ
ROM Code Start-Up

Start Up 과정에서는 CPU의 기본적인 설정들을 초기화하는 동작을 수행한다. 이때 이 보드에서 사용하는 CPU가 Cortex-A 를 기반으로 구성이 되어있기 때문에 AP의 TrustZone Architecture를 따른다. 그래서 처음 부팅이 될 때 CPU가 바로 RBL의 코드로 넘어가는게 아니라 Secure Boot 과정을 거치게 된다. 이 시점에 앞으로 실행하려는 ROM에 저장된 RBL 코드가 변조되거나 손상되지 않았는지를 검사한다.
ㅤ
지금 사용하는 보드에서는 여기에 특별히 Secure를 위한 로직이 들어있지는 않다. 평가보드라서 이를 철저하게 검사할 필요가 없기 때문에 돈을 더 쓰지는 않은 것으로 생각된다. 보통은 회사에서 보안 기능을 필요로 할 때 비용을 써서 여기에 Secure Boot를 위한 검사 로직을 추가하는 방식으로 기능을 구성한다고 이해했다. 우리의 BBB 환경에서는 프로세서 아키텍처의 구성 상 무조건 Secure Mode를 거치긴 하지만, 크게 하는 작업 없이 RBL Code을 향해 넘어간다고 생각하면 된다.
ㅤ

그 이후에는 작성된 코드가 실행될 수 있는 최소한의 환경을 구성하는 것이 목표이다. Initialization 과정에서 Stack Setup, Scatter Loading, Vector Table 구성, CLK과 워치독 설정이 수행된다.
- Stack Setup : SRAM의 끝 부분을 Stack Pointer 로 지정해서 메모리에서 Stack을 사용할 수 있도록 하기
- Scatter Loading : ROM에 있는 코드를 실행하기 위해서 변수, 전역변수 등을 특정한 위치에 박아넣는 작업. 단순히 적혀있는 순서대로 쭈르륵 배정하는게 아니라 구역을 나눠서 정리해넣기 때문에 scatter라고 부르는 것 같다. 다만 RBL의 소스코드는 변경이 되지 않기 때문에 그대로 ROM에 두고 실행한다. (XIP)
- Vector Table 구성 : 예외가 발생했을 때 어디로 이동할 지 Vector Table을 등록. 이후 Booting 과정에서 로딩 실패 시 Dead Loop로 빠지는 등의 작업을 위함인 듯
- System CLK 설정 : 부팅하려는 장치에 적합한 CLK으로 속도를 높인다. 이때 CLK은
SYSBOOT핀의 입력 값을 기반으로 결정한다. 만약 이 값 설정을 안하면 SRAM에 SPL 코드를 올리는데 시간이 매우 오래 걸린다. (가능한 속도의 1/200 으로 주행 중)
ㅤ
CPU는 왜 저렇게 느린 CLK으로 시작하는거지?
처음에 CPU가 부팅되고 나면 매우 느린 CLK을 사용한다. 전원의 공급과 함께 들어오는 전압이 처음에는 불안정할 수 있기에 전원의 공급을 관리하는 PMIC는 낮고 안정된 전압을 제공한다. 이때 CPU의 CLK이 높아버리면 충분한 전압 제공이 어려워 에러가 발생할 수 있다. 그래서 처음에는 낮은 CLK으로 부팅이 된다.
ㅤ
이 시점에는 보드에 부착된 기본 오실레이터에서 들어오는 24MHz의 주파수로 CPU가 동작을 하고있다. 이후에 SYSBOOT 값을 기반으로 어떤 CLK을 타겟으로 하는지를 결정하고 PLL(Phase-Locked Loop) 의 설정값들을 세팅해 원하는 CLK을 만들게 된다.
ㅤ
기본적으로 BBB 보드는 24MHz를 사용한다.

나는 여기에서 기본 CLK을
SYSBOOT[15:14]의 값을 기반으로 설정하는 거라고 생각했다. 그런데 그게 아니였다. 보드에 크리스탈을 달아두고 이게 CPU에게 기본 CLK 신호로 들어가는데, 현재 클럭이 어떤 주파수로 들어오는지를 보드에게SYSBOOT으로 알려주면 이 CLK을 기준으로 체배, 분주를 하여 원하는 CLK을 만들어내는 방식이였다. 즉, 요건 외부 크리스탈이 몇 Hz인지 알려주기 위한 2 Bit.
ㅤ
실제로 이렇게 SYSBOOT 값을 넣어주는 회로도를 살펴보면, SYS_BOOT14, SYS_BOOT15 에 각각 VCC, GND가 연결되어 있는 것을 볼 수 있다. (DNI는 Do Not Install → 납땜이 안되어있다는 의미) 그래서 01b 가 이 신호로 들어와서 24MHz가 기본 크리스탈의 주파수라고 알려준다.

ㅤ
우리의 BBB는 이제 요 CLK을 기반으로 해서 각각의 Source에 필요한 CLK을 만들어내기 위해 PLL 값을 조정하게 된다.

ㅤ
ROM Code Booting
위 Start up 과정에서 CLK과 RBL에 대한 실행 준비를 완료했다면 이제 Booting 단계에 들어간다. 여기에서는 SYSBOOT 핀의 값을 기준으로 부팅 장치를 선택하고, 이걸 RAM(프로세스 내부의 SRAM)에 올려 실행할 준비를 하는게 목표이다. 부팅 과정은 아래처럼 구성된다.

위 다이어그램에서 볼 수 있듯이, SYSBOOT 의 후보 장치가 여럿 있고 각 장치에 순서대로 부팅을 시도한다. 부팅에 실패하면 다음 장치로 넘어가며, 모든 장치의 부팅에 실패하면 Dead Loop 상태로 넘어가게 된다.
ㅤ
여기에서 어떤 장치를 사용할 지는 SYSBOOT[4:0]에 따라 결정되며, 미리 그 테이블이 결정되어있다.

BBB의 회로도 상에서 살펴보면 기본값으로 SYSBOOT[4:0]의 값이 11100b 으로 되어있고, S2 버튼(BOOT 버튼)을 누르면 11000b 으로 값이 들어가도록 되어있다. 이에 따라 각각 다른 장치에 대해 순서대로 부팅을 시도하게 된다.

ㅤ
eMMC, SD카드에서 RAM으로 MLO Copy 하기
위 Booting Sequence Diagram을 살펴보면 부팅 방식이 2가지—Memory Booting, Peripheral Booting—로 나뉘어있다. NOR, NAND, MMC or SPI-EEPROM 등은 Memeory Booting으로 진행되고 USB 등으로 연결되어 부팅이 되는 방식이면 Peripheral Booting으로 분류된다. 내가 BBB 보드에서 시도하는 방식인 eMMC, SD카드 부팅은 둘 다 Memory Booting 방식이므로 여기에 대해서 한 번 살펴보자. 고맙게도(?) 레퍼런스 메뉴얼에 여기에 대한 설명이 작성되어있었다.

혹시 현재 연결된 장치가 RBL 처럼 RAM에 올리지 않고 그대로 실행이 가능한 코드인지 확인한다. 그래서 copy 할 필요가 없다면 그대로 초기화를 시작하며, 만약 RAM으로 옮길 필요가 있는 코드라면 Copy 후 초기화를 시작한다. 일반적으로 XIP가 가능한 장치는 NOR 플래시이고, 우리의 MMC는 여기에 해당하지 않아 복사가 필요하다. 이 복사 과정을 Image Shadowing 이라고 하며, 아래의 다이어그램이 이미지를 복사하는 과정을 설명한다.

ㅤ
SD카드와 eMMCD에는 최대 4개의 파티션을 가지고 부팅 이미지를 가지고 있을 수 있기 때문에, 각각의 파티션에 대해서 차례대로 시도해본다.
ㅤ
여기에서 SD카드와 eMMC로부터의 Initialization을 위해서는 아래의 다이어그램을 따른다.

ㅤ
ROM Boot Loader 에서 아래의 과정으로 eMMC, SD카드 부팅을 시도하게 된다.
- 먼저 MMC 인터페이스에 연결된 장치가 있는지를 확인한다. 없다면 끝.
- 이 과정에서 SD카드인지, 아니면 eMMC 장치인지 구분한다.
- 이걸 위해서는 CMD1 and ACMD41 명령어를 사용하는데, 각각의 장치가 반응 여부가 다르다. 만약 두 명령어에 반응하는 장치가 하나도 없었다면 아무런 장치가 연결되지 않음으로 간주.
- 아래의 Figure 26-23 다이어그램을 확인하자.
- eMMC, SD카드는 Raw Mode와 Booting File 방식을 둘 다 사용한다 (보통 FAT_file allocation table 시스템 → Booting File을 가져와야한다)
- 저장 장치의 첫 번째 sector에서 Master Boot Record 를 찾는다. 이게 있다면 장치를 파티션 해서 쓴다는 것. (MBR을 찾는 과정은 문서에 또 작성되어있었다. 매직넘버들이 박혀있어서, 너무 딥한가 싶어서 넘어감.)
- FAT 형식이 맞는지 체크한다. (요것도 문서에 있었음)
- 루트 디렉토리에서
MLO라는 이름을 가지고 있는 부팅 파일을 찾는다. - 요 파일을 이제 SRAM으로 복사한다.
- 아래의 Figure 26-24 다이어그램을 확인하자.
ㅤ



나는 이 파티션에서 단순히 “몇 번째 메모리주소부터 복사하기” 등의 방식으로 프로그램 코드를 가져갈 것이라 생각했는데, 의외로 실제로 ‘MLO’ 라는 파일 이름으로 코드를 찾아서 가져가고 있다. 이 이름은 매직넘버처럼 코드에 상수로 박혀있는 이름이기 때문에 다른 이름으로 변경하면 부팅이 실패한다고 한다.
ㅤ
그런데 맙소사, Raw Mode 였다
실제로 파티션에 MLO라는 파일이 있는지 찾아보고 싶어서 SD카드를 열어보고 있었다. 그런데, 여기 내부에는 u-boot.img와 MLO라는 파일이 둘 다 없었다.
sungmin@bagseongmin-ui-maegbug ~ % ls -la /Volumes/BOOT
total 29
drwx------@ 1 sungmin staff 0 3월 6 22:39 .
drwxr-xr-x 6 root wheel 192 3월 15 22:34 ..
drwx------ 1 sungmin staff 512 3월 15 22:33 .fseventsd
-rwx------ 1 sungmin staff 3072 1월 1 1970 FSCK0000.REC
-rwx------ 1 sungmin staff 3072 1월 1 1970 FSCK0001.REC
-rwx------ 1 sungmin staff 3072 1월 1 1970 FSCK0002.REC
-rwx------ 1 sungmin staff 52 2월 12 20:33 ID.txt
drwx------ 1 sungmin staff 512 2월 12 20:33 services
-rwx------ 1 sungmin staff 204 2월 12 20:33 START.HTM
-rwx------ 1 sungmin staff 2599 3월 12 07:41 sysconf.txt
ㅤ
여기에 대해서 이 아티클에서는 최근(이라 하기에는 5년이 넘었지만) 사용자들이 실수로 MLO를 지우는 등의 문제를 방지하기 위해서 Raw Mode로 MLO 파일을 숨기는 방식으로 변경되었다고 말한다. “Today, you’ll find, MLO and u-boot.img in the first “1MB” of the media, in the “hole” at the start of the partition.” 라고 한다.
ㅤ
dd 명령어로 이 파티션의 첫 번째 1MB에서 MLO 를 찾아보면 이렇게 내용이 들어있는 것을 볼 수 있다.
sungmin@bagseongmin-ui-maegbug ~ % sudo dd if=/dev/disk18 bs=1k count=1024 | hexdump -C | grep "MLO"
000c38c0 74 66 73 20 70 61 72 74 20 31 20 32 3b 4d 4c 4f |tfs part 1 2;MLO|
000c38d0 20 66 61 74 20 31 20 31 3b 4d 4c 4f 2e 72 61 77 | fat 1 1;MLO.raw|
000c39e0 66 73 20 70 61 72 74 20 30 20 32 3b 4d 4c 4f 20 |fs part 0 2;MLO |
000c39f0 66 61 74 20 30 20 31 3b 4d 4c 4f 2e 72 61 77 20 |fat 0 1;MLO.raw |
1024+0 records in
1024+0 records out
1048576 bytes transferred in 0.325963 secs (3216856 bytes/sec)
ㅤ
Raw mode 에서는 특정 주소에서부터 바이너리로 읽어서 SPL을 찾아 복사하게 된다.
머쓱;; 😉
ㅤ
Secondary Program Loader의 시작
위 ROM Boot Loader의 실행 덕분에 이제 SRAM에 Memory LOader(SPL)가 Copy되어 들어가있는 상태이다. 이제 요걸 실행하게 되면 U-Boot를 시스템에 올리고 커널과 초기 세팅을 올릴 준비가 되는 것이다.
2단계에서 사용되는 부트로더의 이름을 Memory Loader (MLO) 라고 부를 것이냐, 아니면 Secondary Program Loader (SPL) 이라고 부를 것이냐를 하나로 결정하고 싶었는데, 계속해서 두 이름이 번갈아 나오고 있다. 문서에서는 기본적으로 SPL 이라고 부르기는 하는데, 공식 파일 명칭으로는 MLO를 사용한다고 하니, 둘 다 병기하는게 맞는 듯 하다.
ㅤ
이 SPL 단계에서부터는 문서에서 다루고 있지 않은데, SPL부터는 이제 개발 보드의 코드가 아니라 U-Boot의 코드이기 때문이다. SPL은 U-Boot 프로그램을 실행할 준비를 하기 위해 실행하는 것이고, 보드에 맞게 U-Boot 환경을 구성해야한다. 그래서 U-Boot를 빌드할 때 이 MLO 파일이 함께 튀어나온다. (최근 버전에서는 요 파일들이 숨겨지나봄. 이전에 라즈베리파이에서 u-boot 실습을 할 때는 u-boot.img 파일을 본 기억이 있는 것 같은데, 여긴 없네 ^,^;)
ㅤ
왜 U-Boot를 실행할 준비를 RBL에서는 못하고 SPL에서 하냐? 에 대해서는 다음 SPL 이 하는 일에서 작성할 예정이다. 그 전에 잠시 찾아본 내용으로 맛만 보자면 요런 이유다.
- RBL은 프로세서 내부에 박혀있는 코드임 + 사이즈가 아주 작음
- U-Boot의 실행을 위해서는 DDR RAM(메인메모리)의 활성화가 필요함
- 근데 외부 DRAM으로 어떤 장치를 쓸 줄 미리 알고 RBL에 이걸 박아둘 순 없음. RBL은 자기 프로세서에 대한 정보만 알고있음.
- 그렇다고 프로세서 내부에 있는 SRAM은 사이즈가 아주 작아서 U-Boot나 커널을 여기에 넣을 수 없음.
- 그러면 어떻게 DRAM을 살려서 U-Boot와 커널을 올리고 초기화할 수 있을까?
- SPL에 하드웨어에 대한 정보를 하드코딩해서 넣고 빌드하기(DDR RAM의 클럭, 용량, 타이밍 등 정보를 박아넣음)
- 그러면 RBL 이 호출한 SPL이 이제 외부 페리퍼럴 들의 설정값을 알고 있기 때문에 메인 메모리 등을 살려서 U-Boot나 커널을 메모리에 올릴 수 있음.
ㅤ
wrap up
나는 처음에 요 ROM Boot Loader의 경우에는 소스코드가 보안이라 공개되어있지 않다고 설명되어있기에 많은 정보를 얻을 수 없을 것이라 생각했다. 그런데 에고머니나, 테크니컬 레퍼런스 메뉴얼에 생각보다 상세하게 input-output과 절차에 대해서 다이어그램으로 정리해둔걸 보고 놀랐다. 덕분에 예전에 라즈베리파이의 부팅을 분석할 때 생각하지 못했던 부분들을 한 번 살펴볼 수 있었던 것 같다. 역시 이건 마법이 아니라 기술이였어. 이걸 다 사람들이 생각하고 구성해놨다고..? 와우…
ㅤ
확실히 소스코드를 내가 가지고 있다고 해서 프로세서의 ROM에 수정해서 넣어볼 수 있는 것도 아니고 + 이 소스코드를 유출하면 보안적인 문제가 생길 수 있으니깐 공개를 안하는 점에 대해서는 공감을 했다. 비글본 보드를 선택하면 다양한 내부 소스코드 같은게 오픈되어있다고 이야기를 듣긴 했는데, 이 프로세서의 설계와 구현은 비글보드가 아니라 TI 에서 한걸 사온거니깐. 그리고 이 코드들도 C로 써져있다고 내가 원활하게 읽을 수 있다는 장댬도 못하긴 해 ㅋㅋㅎ.
ㅤ
가능하다면 여기에서 Secure Boot 과정을 조금 더 살펴보고 싶긴 한데, 부팅 시퀀스에 대한 시리즈를 한 번 쭉 정리하고 나서 내가 여기에 대해 찾아볼 수 있는 내용들이 있는지 다시 한 번 열어볼 생각이다. 가능하다면!
'Embedded System > Embedded Linux' 카테고리의 다른 글
| [Embedded Linux] BeagleBone Black의 부팅과정 (2) - Secondary Program Loader (1) | 2026.03.18 |
|---|---|
| [Embedded Linux] BeagleBone Black에서 왜 BOOT 버튼을 안눌러도 SD카드로 바로 부팅이 될까 (0) | 2026.03.14 |
| [Embedded Linux] M1 Mac에서 비글본 블랙 SSH 연결하기 (0) | 2026.03.09 |
| [Embedded Linux] M1 Mac에서의 비글본 블랙 부팅하기 (0) | 2026.03.09 |
| [Embedded Linux] 독학용 리눅스 개발 보드 고르기, BeagleBone Black (1) | 2026.02.24 |