13. FDT 바이너리 포맷 (Flattened Device Tree)
FDT(Flattened Device Tree)는 우리가 텍스트로 작성한 .dts 파일을 dtc(컴파일러)가 기계가 읽기 좋게 한 줄로 쫙 펴서 만든 바이너리 포맷(.dtb)을 의미합니다.
부트로더(U-Boot 등)가 커널을 올릴 때 메모리 특정 주소에 이 DTB를 딱 던져주면, 커널은 이 0과 1의 덩어리를 해석해서 하드웨어 구성을 파악하죠. 이 바이너리가 내부적으로 어떻게 생겼는지 핵심을 짚어드릴게요.
13.1 FDT의 전체 레이아웃 (Layout)
FDT 바이너리는 크게 4가지 영역으로 나뉩니다. 데이터의 효율성과 빠른 탐색을 위해 설계되었습니다.
| 영역 | 설명 |
| fdt_header | 바이너리의 전체 지도. 버전, 각 블록의 위치(offset)와 크기 정보가 담겨 있음. |
| Memory Reservation Block | 커널이 건드리면 안 되는 보호된 메모리 영역 목록. |
| Structure Block | 노드와 프로퍼티의 트리 구조를 선형적으로 펼쳐놓은 본체. |
| Strings Block | 프로퍼티 이름(compatible, reg 등)을 모아놓은 문자열 저장소. |
13.2 헤더 (Header) 구조
바이너리의 맨 앞부분입니다. 커널은 가장 먼저 magic 숫자를 보고 "아, 이게 진짜 디바이스 트리구나!"라고 확신합니다.
struct fdt_header {
uint32_t magic; /* 0xd00dfeed (그 유명한 먹이주기 매직넘버) */
uint32_t totalsize; /* DTB 전체 크기 */
uint32_t off_dt_struct; /* Structure Block 시작 위치 */
uint32_t off_dt_strings; /* Strings Block 시작 위치 */
uint32_t off_mem_rsvmap; /* Memory Reservation Block 시작 위치 */
uint32_t version; /* FDT 포맷 버전 */
uint32_t last_comp_version; /* 호환 가능한 최소 버전 */
/* ... 기타 사양 정보 ... */
};
💡위트: FDT의 매직 넘버는 0xd00dfeed (DOOD FEED)입니다. "하드웨어 정보를 커널에게 먹여준다"는 위트가 담겨 있죠.
13.3 구조 블록 (Structure Block)의 토큰
이 블록은 트리를 전위 순회(Pre-order traversal) 방식으로 펼쳐놓았습니다. 데이터는 **토큰(Token)**이라는 32비트 단위로 구분됩니다.
- FDT_BEGIN_NODE (0x00000001): 새로운 노드의 시작 (노드 이름이 뒤따름).
- FDT_PROP (0x00000003): 프로퍼티의 시작 (데이터 크기, 이름 위치, 실제 데이터가 뒤따름).
- FDT_END_NODE (0x00000002): 현재 노드의 끝.
- FDT_END (0x00000009): 전체 트리의 끝.
13.4 왜 문자열 블록(Strings Block)은 따로 있나요?
공간을 아끼기 위해서입니다! 예를 들어 100개의 노드가 각각 status = "okay"라는 프로퍼티를 가진다면, status라는 글자를 100번 저장하는 건 낭비죠. 그래서 status라는 글자는 문자열 블록에 딱 한 번만 저장하고, 구조 블록에서는 그 문자열이 있는 위치(Offset) 번호만 적어둡니다. 일종의 데이터 압축 기술인 셈입니다.
13.5 주요 특징 (Technical Details)
- 엔디안(Endianness): 모든 수치는 빅 엔디안(Big-endian)으로 저장됩니다. (Open Firmware의 전통)
- 정렬(Alignment): 모든 데이터 조각은 4바이트(32비트) 단위로 정렬되어야 합니다. 빈 공간은 0으로 채워집니다.
- 속도: FDT는 순차적으로 읽기에 최적화되어 있어, 부팅 시 커널이 아주 빠르게 트리를 파싱할 수 있습니다.
DTS가 사람이 읽는 설명서라면, FDT(DTB)는 커널이 한 눈에 읽어 내려갈 수 있도록 최적화된 바이너리 리포트입니다.
DTB 파일은 Flattened Device Tree(FDT) 바이너리 포맷으로 저장됩니다. 부트로더가 이 바이너리를 메모리에 로드하고, 커널의 unflatten_device_tree()가 파싱하여 struct device_node 트리를 구축합니다.

13.6 FDT 실전: boot-early stage
코드는 리눅스 커널이 부팅될 때, 부트로더로부터 넘겨받은 FDT(Flattened Device Tree) 바이너리 덩어리를 어떻게 해석하고 자신의 데이터 구조로 변환하는지를 보여주는 핵심 로직입니다.
단순한 데이터 구조를 넘어, 리눅스 커널 부팅의 "Early Stage(초기 단계)"가 어떻게 돌아가는지 조목조목 짚어드릴게요.
1. FDT 헤더: "바이너리 지도의 범례"
fdt_header는 DTB 파일의 맨 앞부분입니다. 여기서 가장 중요한 것은 오프셋(Offset) 정보입니다.
- Magic Number (0xD00DFEED): 커널이 "이 데이터는 가짜가 아니다"라고 확신하는 지점입니다.
- Endianness: FDT는 무조건 Big-endian입니다. ARM64 같은 Little-endian 아키텍처에서도 데이터를 읽을 때 반드시 fdt32_to_cpu() 같은 함수로 뒤집어서 읽어야 합니다.
2. 프로퍼티 인코딩: "공간 절약의 묘미"
예시로 들어주신 compatible과 reg 인코딩 부분은 FDT가 얼마나 효율적으로 데이터를 압축하는지 보여줍니다.
- String List: compatible처럼 여러 문자열이 올 때는 각 문자열 끝에 \0을 붙여서 쭉 이어 붙입니다.
- Strings Block: "compatible", "reg" 같은 속성 이름들은 별도의 저장소(Strings Block)에 한 번만 저장하고, nameoff라는 인덱스 값으로 가리키게 하여 중복 저장을 막습니다.
3. Memory Reservation Block vs reserved-memory 노드
코드 주석에도 나와 있듯이, 이 둘은 "누가 처리하느냐"의 차이입니다.
- Reservation Block: 커널이 채 부팅되기도 전, 매우 초기 단계에서 "여긴 절대 건드리지 마!"라고 물리 메모리 영역을 못 박는 용도입니다. (예: DTB가 놓인 자리)
- reserved-memory 노드: 커널의 메모리 관리 시스템(CMA 등)이 올라온 뒤, 특정 용도(드라이버용 전용 메모리 등)를 위해 예약하는 논리적 설정입니다.
4. 커널의 2단계 처리 과정
1단계: Early Scan (early_init_dt_scan_nodes)
커널이 전체 트리를 메모리에 올리기엔 너무 이른 시점(MMU도 켜지기 전 등)에 수행합니다.
- chosen: "어떤 콘솔을 쓸까?", "부팅 인자(bootargs)는 뭐지?"를 먼저 파악합니다.
- memory: "내가 쓸 수 있는 RAM이 어디서부터 어디까지지?"를 알아내어 Memblock 시스템에 등록합니다.
2단계: Unflatten (unflatten_device_tree)
바이너리 형태인 FDT를 커널 내부의 링크드 리스트 구조인 struct device_node로 바꾸는 "변신" 과정입니다.
- Pass 1: 필요한 메모리 양을 미리 계산합니다.
- Pass 2: 계산된 만큼 메모리를 한 번에 할당받아 트리를 구성합니다.
- 이 과정이 끝나면 우리가 흔히 보는 /proc/device-tree를 통해 텍스트 형태로 하드웨어 정보를 확인할 수 있게 됩니다.
💡 핵심 요약
이 코드는 "바이너리(DTB) → 초기 스캔(Early Scan) → 객체화(Unflatten)"로 이어지는 커널의 하드웨어 인식 파이프라인을 설명하고 있습니다.
결국 커널은 이 과정을 거쳐야만 "아, 내 주위에 UART가 있고, 메모리가 이만큼 있구나!"라고 자아를 성찰하게 되는 것이죠.
참고: https://www.minzkn.com/linuxkernel/pages/device-tree.html#dt-compile
'Embedded : : Linux > : : Device Tree' 카테고리의 다른 글
| [Device Tree] 14. struct device_node / struct property 내부 구조 (0) | 2026.03.04 |
|---|---|
| [Device Tree] 12. Device Tree 디버깅 (0) | 2026.03.04 |
| [Device Tree] 11. 특수 노드와 고급 패턴 (0) | 2026.03.04 |
| [Device Tree] 10. Device Tree + Platform Driver 통합 (0) | 2026.03.04 |
| [Device Tree] 9. 커널 OF(Open Firmware) API (0) | 2026.03.04 |