Barebox · source analysis

Barebox 빌드 산출물과 PBL image

Kconfig와 linker 단계가 barebox ELF, PBL, DTB와 보드별 images를 만드는 구조를 정리합니다.

표의 버전은 소스 분석 기준이며 최신 보안 버전 권고가 아닙니다. TF-A LTS 2.14.3 이후에는 보안 수정이 있습니다. 제품 적용 시 공식 변경 기록과 사용 플랫폼의 errata를 확인하세요.

Series
01 / 19
Baseline
v2026.06.1
Commit
314c679eea2d
Source
Makefile:1074-1162 (발췌 범위)

Barebox 빌드 산출물과 PBL image 단계에서 실제로 바뀌는 상태는 무엇인가?

barebox 실행 파일과 images/ 아래 ROM 투입 파일을 구분한다. PBL 압축, 헤더, load address가 최종 파일에서 어디에 놓이는지 본다.

ROM용 image의 header, load address, entry와 포함된 PBL/main payload의 위치가 보드 부트 규약과 일치해야 한다. 이 문장을 기준으로 코드를 위에서 아래로 읽으면, 함수 이름을 외우는 대신 어느 시점에 어떤 상태를 신뢰할 수 있는지 판단할 수 있다.

객체와 주소가 놓이는 구조

그림 1. Barebox 빌드 산출물과 PBL image에서 입력, 내부 상태, 출력의 경계
입력과 전제내부 상태외부로 공개되는 결과
01main image
02PBL objects
03embedded DTB
04SoC boot image

barebox: $를 중심에 놓고 왼쪽의 입력이 어떤 검사를 거쳐 오른쪽 결과로 공개되는지 표시했다. 실제 디버깅에서는 각 블록의 주소와 크기를 로그에 대입한다.

실행 흐름

그림 2. 정상 경로의 주요 호출과 상태 전달
Kconfig
built-in objects
barebox ELF
PBL and DTB
images/

화살표는 단순 호출 순서만 뜻하지 않는다. 각 단계가 성공을 반환할 때 다음 단계가 읽을 수 있는 상태가 무엇인지 함께 확인한다. 오류 반환이 발생하면 바로 다음 화살표로 진행하지 않고 해당 단계의 정리 경로를 따라간다.

단계별 입력과 출력

각 단계의 입력과 처리 후 바뀌는 상태를 정리한 표다. 사용 중인 소스 버전에서 다른 필드를 변경한다면 그에 맞춰 표도 수정한다.

#단계진입 시 신뢰할 상태성공 뒤 남아야 할 상태다음 소비자
01Kconfig빌드 시점main imagebuilt-in objects
02built-in objectsKconfig 완료 상태PBL objectsbarebox ELF
03barebox ELFbuilt-in objects 완료 상태embedded DTBPBL and DTB
04PBL and DTBbarebox ELF 완료 상태SoC boot imageimages/
05images/PBL and DTB 완료 상태SoC boot image최종 barebox, barebox.bin, PBL, images/* 또는 다음 stage

분석 범위의 전제와 비교해, 다음 단계에 잘못된 입력을 넘긴 부분부터 조사한다.

주소와 객체의 이동을 그림으로 읽기

아래 그림은 주소, 객체를 사용하는 기간, 제어권을 넘기는 시점을 중심으로 정리했다. 실제 주소와 크기는 사용 중인 보드의 bdinfo, 맵 파일과 링커 심벌로 확인한다.

그림 3. Kconfig에서 ROM용 images 산출물까지

호출 이름만 나열하지 않고, 각 단계가 다음 단계에 넘기는 상태를 기준으로 실행 순서를 표시한다.

01defconfig·Kconfig
02built-in object
03barebox ELF
04PBL object subset
05compression·embedded DTB
06SoC image header
07images/*
그림 4. 빌드 산출물의 입력과 소비자

왼쪽 생산자가 가운데 상태를 완성하고, 오른쪽 소비자가 그 상태를 처음 사용하는 관계다.

01KconfigCONFIG_PBL_IMAGEPBL objects
02linker scriptbarebox symbolsbarebox ELF
03DTBboard identificationPBL image
04compressionpacked main payloadPBL decompressor
05imagetoolROM headerBoot ROM

원본 코드

아래 코드는 Barebox v2026.06.1의 Makefile에서 1074-1162줄을 그대로 가져온 것이다. 설명을 위해 실제 코드를 가짜 의사 코드로 바꾸지 않았다.

commit314c679eea2d0ca847c64d1b646a1cf91225c0ecanchor · L1098barebox: $(BAREBOX_LDS)
1074# This target has pytest select the YAML env matching CONFIG_NAME if available.
1075# Use pytest --lg-env $labgrid_env_yaml directly if you need more than that.
1076
1077labgrid-env := $(srctree)/test/$(SRCARCH)/$(CONFIG_NAME).yaml
1078
1079check:
1080ifeq ($(CONFIG_NAME),"")
1081	@echo "error: can't autoload labgrid env with CONFIG_NAME unset!" >&2
1082	@exit 1
1083endif
1084	@if [ ! -r "$(labgrid-env)" ]; then \
1085		echo "error: No Labgrid environment at $(labgrid-env)!" >&2; \
1086		echo "Choose a different config (or change CONFIG_NAME)" >&2; \
1087		echo "that can be automatically tested" >&2; \
1088		exit 1; \
1089	fi
1090	@echo
1091	@# This is intentionally not @suppressed, to make it easier to reproduce
1092	(cd $(srctree); KBUILD_OUTPUT=$(abs_objtree) $(PYTEST))
1093
1094PHONY += check
1095
1096# barebox image
1097# ---------------------------------------------------------------------------
1098barebox: $(BAREBOX_LDS) $(BAREBOX_OBJS) $(kallsyms.o) FORCE
1099	$(call if_changed_rule,barebox__)
1100ifeq ($(BAREBOX_PROPER),barebox)
1101	$(Q)rm -f .old_version
1102endif
1103
1104barebox.fit: images/barebox-$(CONFIG_ARCH_LINUX_NAME).fit
1105	$(Q)ln -fsn $< $@
1106
1107barebox.srec: barebox
1108	$(OBJCOPY) -O srec $< $@
1109
1110OBJCOPYFLAGS_vmbarebox = $(call objcopy-option,--strip-section-headers,--strip-all)  \
1111			 --remove-section=.comment \
1112			 --remove-section=.note* \
1113			 --remove-section=.gnu.hash
1114
1115vmbarebox: barebox FORCE
1116	$(call if_changed,objcopy)
1117
1118quiet_cmd_barebox_proper__ = CC      $@
1119      cmd_barebox_proper__ = $(CC) -r -o $@ -Wl,--whole-archive $(BAREBOX_OBJS)
1120
1121.tmp_barebox.o: $(BAREBOX_OBJS) $(kallsyms.o) FORCE
1122	$(if $(CONFIG_KALLSYMS),,+$(call cmd,barebox_version))
1123	$(call cmd,barebox_proper__)
1124	$(Q)echo 'savedcmd_$@ := $(cmd_barebox_proper__)' > $(@D)/.$(@F).cmd
1125	$(Q)rm -f .old_version
1126
1127barebox.o: .tmp_barebox.o FORCE
1128	$(call if_changed,objcopy)
1129
1130# The actual objects are generated when descending,
1131# make sure no implicit rule kicks in
1132$(sort $(BAREBOX_OBJS)) $(BAREBOX_LDS) $(BAREBOX_PBL_OBJS): $(barebox-dirs) ;
1133
1134# Handle descending into subdirectories listed in $(barebox-dirs)
1135# Preset locale variables to speed up the build process. Limit locale
1136# tweaks to this spot to avoid wrong language settings when running
1137# make menuconfig etc.
1138# Error messages still appears in the original language
1139
1140PHONY += $(barebox-dirs)
1141$(barebox-dirs): prepare scripts
1142	$(Q)$(MAKE) $(build)=$@
1143
1144# Store (new) KERNELRELASE string in include/config/kernel.release
1145localversion = $(shell $(srctree)/scripts/setlocalversion $(srctree))
1146include/config/kernel.release: FORCE
1147	$(Q)rm -f $@
1148	$(Q)echo $(KERNELVERSION)$(localversion) > $@
1149
1150# Additional helpers built in scripts/
1151# Carefully list dependencies so we do not try to build scripts twice
1152# in parallel
1153PHONY += scripts
1154scripts: scripts_basic scripts_dtc include/generated/utsrelease.h
1155	$(Q)$(MAKE) $(build)=$(@)
1156
1157# Things we need to do before we recursively start building the kernel
1158# or the modules are listed in "prepare".
1159# A multi level approach is used. prepareN is processed before prepareN-1.
1160# archprepare is used in arch Makefiles and when processed asm symlink,
1161# version.h and scripts_basic is processed / created.
1162

발췌 범위와 읽기 기준

원문 1074-1162줄에는 앞뒤 문맥이 포함됩니다. 기준 구문 barebox: $(BAREBOX_LDS)은 L1098에 있습니다. 발췌 첫 줄을 함수 정의의 시작으로 해석하지 않습니다.

barebox 실행 파일과 images/ 아래 ROM 투입 파일을 구분한다. PBL 압축, 헤더, load address가 최종 파일에서 어디에 놓이는지 본다.

함께 읽어야 하는 원본 코드

첫 코드 조각만으로 동작이 완성되지 않는 경우 호출 매크로, 객체 정의와 실제 실행 목록을 같은 페이지에 묶었다. 각 조각은 같은 기준 commit에서 가져왔다.

01. PBL ELF와 binary image를 링크하는 규칙

images/Makefile 61-137줄이다.

fileimages/Makefileanchor · L79$(obj)/%.pbl:
61else
62BAREBOX_PIGGY_OBJS = $(obj)/../$(BAREBOX_PROPER)
63endif
64
65quiet_cmd_elf__ ?= LD      $@
66      cmd_elf__ ?= $(LD) $(LDFLAGS_$(patsubst .%,%,$(suffix $(@F)))) 	\
67		-e $(2) -Map $@.map $(LDFLAGS_$(@F)) -o $@		\
68		--gc-sections --defsym=__pbl_board_entry=$(2)  		\
69		-T $(pbl-lds)						\
70		--whole-archive $(BAREBOX_PBL_OBJS) $(BAREBOX_PIGGY_OBJS) \
71
72PBL_CPPFLAGS	+= -fdata-sections -ffunction-sections
73
74define rule_elf
75	$(call cmd,elf__,$(*F))
76	$(call cmd,prelink__)
77endef
78
79$(obj)/%.pbl: $(pbl-lds) $(BAREBOX_PBL_OBJS) $(BAREBOX_PIGGY_OBJS) FORCE
80	$(call if_changed_rule,elf)
81
82$(obj)/%.elf: $(pbl-lds) $(BAREBOX_PBL_OBJS) $(BAREBOX_PIGGY_OBJS) FORCE
83	$(call if_changed_rule,elf)
84
85
86# Convert the ELF into a linear binary, check for missing firmware
87# and verify file sizes:
88#
89# For each start symbol create three variables containing the
90# relevant sizes in the image:
91# PBL_CODE_SIZE_$(symbol)   - contains the pure code size of the image
92# PBL_MEMORY_SIZE_$(symbol) - contains the code size + bss size of the
93#                             image
94# PBL_IMAGE_SIZE_$(symbol)  - contains the full image size including the
95#                             compressed payload
96#
97# if MAX_PBL_xxx_SIZE_$(symbol) is defined it contains the maximum size the
98# code/memory/image for this PBL may get. Check these values.
99define rule_pblb
100	$(call cmd,objcopy_bin,$(*F))
101	$(call cmd,check_missing_fw,$@,$<)
102	$(call cmd,check_file_size,$@,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE))
103
104	$(if $(MAX_PBL_CODE_SIZE_$*), \
105		$(call cmd,check_size,$(PBL_CODE_SIZE_$*),$(MAX_PBL_CODE_SIZE_$*)) \
106	)
107
108	$(if $(MAX_PBL_MEMORY_SIZE_$*), \
109		$(call cmd,check_size,$(PBL_MEMORY_SIZE_$*),$(MAX_PBL_MEMORY_SIZE_$*)) \
110	)
111
112	$(if $(MAX_PBL_IMAGE_SIZE_$*), \
113		$(call cmd,check_size,$(PBL_IMAGE_SIZE_$*),$(MAX_PBL_IMAGE_SIZE_$*)) \
114	)
115endef
116
117$(obj)/%.pblb: $(obj)/%.pbl FORCE
118	$(eval PBL_CODE_SIZE_$* = \
119		$(shell $(srctree)/scripts/extract_symbol_offset pbl_code_size $^))
120	$(eval PBL_MEMORY_SIZE_$*= \
121		$(shell $(srctree)/scripts/extract_symbol_offset pbl_memory_size $^))
122	$(eval PBL_IMAGE_SIZE_$*= \
123		$(shell $(srctree)/scripts/extract_symbol_offset pbl_image_size $^))
124
125	$(call if_changed_rule,pblb)
126
127$(obj)/%.s: $(obj)/% FORCE
128	$(call if_changed,disasm)
129
130quiet_cmd_itb = FIT.ITS $@
131cmd_itb = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) \
132	-D'$(subst -,_,$(*F))_dts=1' $(foreach f,$< $(2),-include '$(f)') /dev/null ; \
133	$(MKIMAGE) -f $(dtc-tmp) $@ -E \
134	cat $(depfile).pre $(depfile).dtc > $(depfile)
135
136$(obj)/%.itb: $(obj)/%.its FORCE
137	$(call if_changed,itb)

내부 동작을 더 깊게 읽기

01

진입 조건을 먼저 고정한다

Kconfig에서 들어온 실행은 빌드 시점에 놓여 있다. 이때 interrupt, MMU/cache, stack, heap 중 무엇이 이미 준비되었는지 소스의 호출자까지 올라가 확인한다. 같은 함수라도 SPL, relocation 전후, app thread처럼 호출 문맥이 달라지면 허용되는 API와 지연 시간이 달라진다.

barebox 실행 파일과 images/ 아래 ROM 투입 파일을 구분한다. PBL 압축, 헤더, load address가 최종 파일에서 어디에 놓이는지 본다.

02

중심 객체의 생성과 공개를 나눈다

이 글의 중심 객체는 barebox: $다. 메모리를 확보한 시점, 필드를 채운 시점, 전역 list나 다른 subsystem에 공개한 시점을 구분한다. 공개 뒤 오류가 발생한다면 목록에서 제거하고 child, buffer, reference를 역순으로 정리하는지 확인한다.

빌드 산출물 관점에서는 barebox, barebox.bin, PBL, images/* 안에 해당 symbol과 section이 실제로 포함되었는지도 map과 objdump로 검증한다.

03

주소, 크기와 정렬을 계산한다

부트 코드에서는 주소 계산 오류를 주의해야 한다. 원본과 목적지의 주소 범위, 헤더에 기록된 데이터 크기, 블록·페이지 단위를 표로 정리하고 각 구간의 끝 주소를 계산한다. 끝 주소가 start + size - 1처럼 마지막 바이트를 가리키는지, 구간 바로 다음 주소를 가리키는지는 API 규약에서 확인한다.

04

성공 flag와 실제 완료 시점을 맞춘다

built-in objects → barebox ELF → PBL and DTB 구간에서는 부분 초기화 상태가 생길 수 있다. flag, list insertion, callback 등록, storage write 완료 중 무엇이 성공의 기준인지 찾는다. hardware write나 DMA가 포함되면 함수 반환과 장치 완료가 같은 시점인지도 확인한다.

다른 CPU, 인터럽트 처리기, USB 완료 콜백, 셸 명령에서도 이 상태를 읽는다면 메모리 접근 순서와 잠금 범위를 함께 확인한다.

05

제어권을 넘기기 전에 확인할 조건을 정리한다

정상 경로는 images/에서 끝난다. 이 단계가 함수 반환인지, scheduler 전환인지, 다른 image로의 비복귀 분기인지 구분한다. 비복귀 handoff라면 cache clean/invalidate, interrupt disable, 장치 quiesce, argument register와 FDT 또는 image address가 최종 점검 항목이다.

호출한 함수로 돌아오는 경로라면 오류와 일부 처리만 완료된 상태를 구분하는지 확인한다. 이어서 다음 후보를 시도할지, 복구 절차를 실행할지 살펴본다.

구현을 읽을 때 놓치기 쉬운 부분

01

PBL과 full barebox는 서로 다른 실행 환경을 가진다

PBL은 Boot ROM이 제공한 SRAM과 제한된 stack에서 DDR 또는 다음 image를 준비한다. full barebox의 driver, malloc, shell API가 source tree에 있다고 PBL에서 호출할 수 있는 것은 아니며 __PBL__ 조건과 PBL object 목록을 확인해야 한다.

같은 함수 이름도 PBL용 구현과 runtime 구현이 따로 선택될 수 있다.

02

링크 주소와 image packing 단계를 분리한다

PBL ELF의 text 주소, raw payload offset, SoC header가 선언한 load/entry 주소가 모두 맞아야 ROM에서 첫 instruction에 도달한다. piggydata로 full image를 포함하면 압축 data의 source와 decompression destination도 memory map에 추가한다.

map, objdump, final image hexdump에서 각 boundary를 같은 표로 대조한다.

03

크기 제한은 section과 기능 단위로 관리한다

SRAM 제한을 넘으면 header 생성은 성공해도 runtime stack이나 decompressor 영역이 겹칠 수 있다. text/data/BSS, embedded DT와 stack의 최대치를 따로 계산한다.

feature toggle 전후 section delta와 PBL call graph를 기록해 full-only code가 끌려 들어온 원인을 찾는다.

객체와 수명

대상만들어지는 시점유효 범위확인할 조건
barebox: $built-in objectsimages/ 또는 오류 정리 완료까지진입 전제와 상태 계약
입력 buffer / metadataKconfigparse와 검증이 끝날 때까지길이, 정렬, 소유권, 변조 가능성
등록된 list / descriptorbarebox ELF하위 시스템을 종료하거나 다음 이미지에 제어권을 넘길 때까지중복 등록, 해제된 객체를 가리키는 포인터, 오류 후 자원 정리
hardware 또는 persistent state실제 write/probe가 완료된 뒤reset 또는 명시적 해제·갱신까지쓰기 완료, 시간 초과, 전원 차단, 이전 상태 복원
barebox, barebox.bin, PBL, images/*link/image 생성 시점다음 stage가 새 image로 교체할 때까지적재 주소, 진입점, 섹션, 헤더의 일치 여부

실패 지점과 증상

#조건관찰되는 증상먼저 볼 단계
01잘못된 image targetROM header 없음built-in objects
02PBL/main address overlap압축 해제 손상barebox ELF
03DTB 미포함보드 식별 실패PBL and DTB

로그가 끊긴 함수뿐 아니라 그 함수에 주소, 크기, 플래그를 전달한 앞 단계도 조사한다. 오류 처리 후 등록된 객체나 하드웨어 설정이 그대로 남아 있는지도 확인한다.

소스 밖에서 확인할 증거

소스에서 파악한 동작을 실제 빌드 결과와 대상 보드의 로그로 확인한다. 아래 명령의 보드 이름과 툴체인 접두사는 사용 중인 빌드 환경에 맞게 바꾼다.

#목적명령 또는 계측판정 기준
01빌드 구성make <board>_defconfig && make V=1Kconfig, linker section과 최종 barebox image 생성 명령을 보관한다.
02symbol과 section${CROSS_COMPILE}nm -n barebox | grep 'barebox'initcall, command, driver descriptor가 image에 남았는지 확인한다.
03주소와 resourceiomemimage, malloc, stack, device resource와 reserved 영역의 겹침을 확인한다.
04device 상태devinfo; drvinfo; of_dumpDT node 생성, device 등록, driver probe를 서로 구분한다.
05boot 정책boot -d -v; state -dentry 탐색 결과와 persistent state가 실제 선택에 미친 영향을 확인한다.

직접 확인할 실험

  1. 01
    make V=1로 PBL과 main 링크 명령 분리

    built-in objects 진입 전후에 main image의 주소·크기·반환값과 timestamp를 함께 남긴다.

  2. 02
    readelf와 barebox.map 주소 대조

    barebox ELF 진입 전후에 PBL objects의 주소·크기·반환값과 timestamp를 함께 남긴다.

  3. 03
    images/*.imx 또는 *.img 헤더 도구로 검사

    PBL and DTB 진입 전후에 embedded DTB의 주소·크기·반환값과 timestamp를 함께 남긴다.

원문과 다음 글