Embedded/이론

[Embedded] 부트 로더(Boot loader)

유제필 2022. 11. 15. 21:51

부트로더란(boot loader)

부트로더란 장치에 생명을 불어넣고 부트 절차를 시작하는 것이다.

즉, 부트로더는 시스템을 시작시키고 운영체제 커널을 로드하는 것이다.

부트로더가 하는 일

임베디드 리눅스 시스템에서 부트로더는 시스템을 기본 수준(basic level)으로 초기화하고 커널을 로드하는 2가지의 주요 작업을 수행한다.

전원을 켜거나 부트로더 코드의 첫 줄이 실행되면 시스템은 아주 최소 상태에 있다.

이때 DRAM 컨트롤러가 시작하지 않았기 때문에 주 메모리에는 접근할 수 없다.

 

마찬가지로 다른 인터페이스도 구성되지 않았기 때문에 NAND 플래시 컨트롤러,

MMC 컨트롤러 등을 통해 접근하는 저장소도 사용할 수 없다.

결과적으로 시스템 부트스트랩은 몇 단계의 코드로 이루어지며, 각각의 시스템의 더 많은 부분을 작동시킨다.

부트로더의 마지막 동작은 커널을 램에 로드하고 그를 위한 실행 환경을 만드는 것이다.

부트로더와 커널 사이의 인터페이스는 아키텍처 별로 다르며, 각각 2가지의 일을 한다.

1. 부트로더는 하드웨어 구성 정보를 담고 있는 구조체의 포인터를 전달한다.

2. 커널 커맨드라인의 포인터를 전달한다.

커널이 실행을 시작하면 부트로더는 더 이상 필요가 없어지고 사용하던 메모리를 회수할 수 있다.

부트로더의 부수작업은 부트 구성을 업데이트하고, 새로운 부트 이미지를 메모리에 로드하고,

진단 기능을 실행하는 유지보수 모드를 제공한다.

임베디드 시스템 부팅 과정

대부분의 임베디드 코어의 ARM, x86/x86_64의 설계는

UEFI(Universal Extensible Firmware Interface) 표준에 기반을 둔 펌웨어를 갖고 있다.

UEFI란 통일 확장 펌웨어 인터페이스로 운영 체제와 플랫폼 펌웨어 사이의 소프트웨어 인터페이스를 정의하는 규격이다.

기존의 BIOS를 대체할 목적으로 개발되었고, BIOS 대신 사용되고 있다.

부트 순서

1. ROM Code

리셋이나 전원을 켠 후, 실행되는 코드는 SoC 칩상에 저장되어야 하는데, 이를 롬 코드 라고 한다.

롬 코드는 제조 시 칩에 프로그램되므로, 비공개이며 오픈소스 대용품으로 대체할 수 없다.

DRAM 구성은 장치별로 매우 달라 메모리 컨트롤러를 초기화하는 코드는 보통 담고 있지 않으므로, 메모리 컨트롤러가 필요 없는 SRAM만 사용할 수 있다.

롬 코드는 소량의 코드를 사전에 프로그램된 몇 개의 위치 중 하나로부터 SRAM으로 로드할 수 있다.

대부분의 임베디드 SoC는 비슷한 방식으로 동작하는 롬 코드를 갖고 있다.

SRAM이 U-Boot 같은 완전한 부트로더를 로드할 정도로 충분히 크지 않은 SoC에는

SPL이라는 중간 로더가 있다.

롬 코드가 끝날 때 쯤 SPL이 SRAM에 존재하고 롬 코드는 SPL 코드의 시작으로 점프한다.

대부분의 임베디드 SoC 설계는 약간의 SRAM을 칩 안에 보유하고 있는데, 4KB 부터 다양한 사이즈가 있다.

2. SPL(Secondary Program Loader)

SPL은 메모리 컨트롤러와 기타 TPL을 DRAM에 로드하기 위해 필요한

시스템의 필수적인 부분들을 시작해야 한다. SPL의 기능은 크기로 인해 제한되어 할 수 없다.

롬 코드처럼 사전에 프로그램된 플래시 장치 시작부터의 오프셋을 이용해 저장 장치로부터 프로그램을 읽을 수 있다.

SPL에 파일시스템 드라이버가 내장되어 있다면, 디스크 파티션에서 u-boot.img 처럼 잘 알려진 파일 이름을 읽을 수 있다.

SPL은 보통 사용자와의 상호작용을 고려하지는 않지만, 버전 정보와 진행 메시지를 콘솔로 출력할 수 있다.

3. TPL(Tertiary Program Loader)

U-Boot나 Barebox 같은 완전한 부트로더를 실행할 수 있다.

새로운 부트/커널 이미지를 플래시 저장소에 로드하고, 커널을 로드하고 부팅하는 등의

유지보수 작업을 수행할 수 있게 하는 간단한 커맨드라인 사용자 인터페이스가 있고,

사용자 개입 없이 커널을 자동으로 로드하는 방법이 있다.

TPL까지의 작업이 끝나면, 커널이 메모리에서 시작되길 기다리고 있다.

임베디드 부트로더는 커널이 실행되면 메모리에서 사라지고,

시스템의 동작에 더 이상 관여하지 않는다.

부트로더와 커널

부트로더가 제어를 커널로 넘길 때 기본 정보를 같이 넘긴다.

1. 기계 번호(machine number) : 장치 트리가 지원되지 않는 파워 PC와 ARM 플랫폼에서 SoC 종류를 식별하기 위해 사용

2. 하드웨어의 세부사항 : 최소한 물리적인 램의 크기와 위치, CPUI Clock 속도 등

3. 커널 커맨드 라인 : 암호화되지 않은 아스키 문자열로

4. 장치 트리 바이너리의 위치와 크기

5. 초기 램 디스크의 위치와 크기

부트로더의 종류

부트로더의 종류는 아키텍처 별로 다르며, 주요 아키텍처 별로 사용할 수 있는 부트로더의 종류가 여러 가지가 있다.

부트로더 이름
지원되는 주요 아키텍처
Das U-Boot
ARC, ARM, Blackfin, Microblaze, MIPS, Nios2, OpenRiec, 파워PC, SH 등
Barebox
ARM, Blackfin, MIPS, Nios2, 파워PC 등
GRUB 2
x86, x86_64
Little Kernel
ARM
RedBoot
ARM, MIPS, 파워PC, SH 등
CFE
브로드컴 MIPS
YAMON
MIPS