QUESTION
OP-TEE OS 빌드 산출물 단계에서 실제로 바뀌는 상태는 무엇인가?
하나의 tee.bin만 보지 말고 pager가 켜진 구성과 v2 split image에서 각 파일의 load address와 runtime owner가 어떻게 달라지는지 확인한다.
header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다. 이 문장을 기준으로 코드를 위에서 아래로 읽으면, 함수 이름을 외우는 대신 어느 시점에 어떤 상태를 신뢰할 수 있는지 판단할 수 있다.
STRUCTURE
객체와 주소가 놓이는 구조
header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다.
tee.elf / tee.bin v2 segments를 중심에 놓고 왼쪽의 입력이 어떤 검사를 거쳐 오른쪽 결과로 공개되는지 표시했다. 실제 디버깅에서는 각 블록의 주소와 크기를 로그에 대입한다.
CALL PATH
실행 흐름
화살표는 단순 호출 순서만 뜻하지 않는다. 각 단계가 성공을 반환할 때 다음 단계가 읽을 수 있는 상태가 무엇인지 함께 확인한다. 오류 반환이 발생하면 바로 다음 화살표로 진행하지 않고 해당 단계의 정리 경로를 따라간다.
STATE LEDGER
단계별 입력과 출력
호출 순서를 함수 이름으로만 외우지 않고, 각 단계가 무엇을 받아 무엇을 공개하는지 적은 표다. 실제 소스에서 생산 필드가 다르면 표를 고치는 방식으로 사용한다.
| # | 단계 | 진입 시 신뢰할 상태 | 성공 뒤 남아야 할 상태 | 다음 소비자 |
|---|---|---|---|---|
| 01 | core objects | host build and TF-A packaging boundary | tee.elf sections | linker script |
| 02 | linker script | core objects 완료 상태 | tee-pager.bin | tee.elf |
| 03 | tee.elf | linker script 완료 상태 | tee-pageable.bin | gen_tee_bin.py |
| 04 | gen_tee_bin.py | tee.elf 완료 상태 | tee-header_v2.bin | pager/pageable/header |
| 05 | pager/pageable/header | gen_tee_bin.py 완료 상태 | tee-header_v2.bin | 최종 tee.elf, tee.bin, pager/pageable images 또는 다음 stage |
공통 불변 조건: header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다. 한 단계의 출력이 다음 단계의 입력 조건을 만족하지 않으면 오류가 실제로 드러난 위치보다 앞의 생산 단계부터 조사한다.
VISUAL WALKTHROUGH
주소와 객체의 이동을 그림으로 읽기
아래 그림은 호출 이름보다 주소, 객체 수명과 handoff 경계를 먼저 볼 수 있도록 구성했다. 실제 주소와 크기는 사용 중인 보드의 bdinfo, map과 linker symbol을 대입한다.
각 칸은 제어권이 다음 단계로 넘어가기 전에 확정되어야 하는 상태를 나타낸다.
크기는 개념 비율이다. 실제 시작·끝 주소는 platform map과 linker symbol로 대조한다.
UPSTREAM SOURCE
원본 코드
아래 코드는 OP-TEE OS 4.10.0의 core/arch/arm/kernel/link.mk에서 133-221줄을 그대로 가져온 것이다. 설명을 위해 실제 코드를 가짜 의사 코드로 바꾸지 않았다.
133link-script-extra-deps += $(link-out-dir)/rodata_init.ld.S
134link-script-extra-deps += $(conf-file)
135cleanfiles += $(link-script-pp) $(link-script-dep)
136$(link-script-pp): $(link-script) $(link-script-extra-deps)
137 @$(cmd-echo-silent) ' CPP $@'
138 @mkdir -p $(dir $@)
139 $(q)$(CPPcore) -P -MT $@ -MD -MP -MF $(link-script-dep) \
140 $(link-script-cppflags) $< -o $@
141
142$(link-out-dir)/version.o:
143 $(call gen-version-o)
144
145-include $(link-out-dir)/.tee.elf.cmd
146define check-link-objs
147$(if $(strip $(filter-out $(link-objs), $(old-link-objs))
148 $(filter-out $(old-link-objs), $(link-objs))), FORCE_LINK := FORCE)
149endef
150$(eval $(call check-link-objs))
151
152all: $(link-out-dir)/tee.elf
153cleanfiles += $(link-out-dir)/tee.elf $(link-out-dir)/tee.map
154cleanfiles += $(link-out-dir)/version.o
155cleanfiles += $(link-out-dir)/.buildcount
156cleanfiles += $(link-out-dir)/.tee.elf.cmd
157$(link-out-dir)/tee.elf: $(link-objs) $(libdeps) $(link-script-pp) $(FORCE_LINK)
158 @echo "old-link-objs := $(link-objs)" >$(link-out-dir)/.tee.elf.cmd
159 @$(cmd-echo-silent) ' LD $@'
160 $(q)$(LDcore) $(ldargs-tee.elf) -o $@
161
162all: $(link-out-dir)/tee.dmp
163cleanfiles += $(link-out-dir)/tee.dmp
164$(link-out-dir)/tee.dmp: $(link-out-dir)/tee.elf
165 @$(cmd-echo-silent) ' OBJDUMP $@'
166 $(q)$(OBJDUMPcore) -l -x -d $< > $@
167
168cleanfiles += $(link-out-dir)/tee-pager.bin
169$(link-out-dir)/tee-pager.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py
170 @echo Warning: $@ is deprecated
171 @$(cmd-echo-silent) ' GEN $@'
172 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pager_bin $@
173
174cleanfiles += $(link-out-dir)/tee-pageable.bin
175$(link-out-dir)/tee-pageable.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py
176 @echo Warning: $@ is deprecated
177 @$(cmd-echo-silent) ' GEN $@'
178 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pageable_bin $@
179
180all: $(link-out-dir)/tee.bin
181cleanfiles += $(link-out-dir)/tee.bin
182$(link-out-dir)/tee.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py
183 @$(cmd-echo-silent) ' GEN $@'
184 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_bin $@
185
186all: $(link-out-dir)/tee-header_v2.bin
187cleanfiles += $(link-out-dir)/tee-header_v2.bin
188$(link-out-dir)/tee-header_v2.bin: $(link-out-dir)/tee.elf \
189 scripts/gen_tee_bin.py
190 @$(cmd-echo-silent) ' GEN $@'
191 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_header_v2 $@
192
193all: $(link-out-dir)/tee-pager_v2.bin
194cleanfiles += $(link-out-dir)/tee-pager_v2.bin
195$(link-out-dir)/tee-pager_v2.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py
196 @$(cmd-echo-silent) ' GEN $@'
197 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pager_v2 $@
198
199all: $(link-out-dir)/tee-pageable_v2.bin
200cleanfiles += $(link-out-dir)/tee-pageable_v2.bin
201$(link-out-dir)/tee-pageable_v2.bin: $(link-out-dir)/tee.elf \
202 scripts/gen_tee_bin.py
203 @$(cmd-echo-silent) ' GEN $@'
204 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pageable_v2 $@
205
206all: $(link-out-dir)/tee.symb_sizes
207cleanfiles += $(link-out-dir)/tee.symb_sizes
208$(link-out-dir)/tee.symb_sizes: $(link-out-dir)/tee.elf
209 @$(cmd-echo-silent) ' GEN $@'
210 $(q)$(NMcore) --print-size --reverse-sort --size-sort $< > $@
211
212cleanfiles += $(link-out-dir)/tee.mem_usage
213ifneq ($(filter mem_usage,$(MAKECMDGOALS)),)
214mem_usage: $(link-out-dir)/tee.mem_usage
215
216$(link-out-dir)/tee.mem_usage: $(link-out-dir)/tee.elf
217 @$(cmd-echo-silent) ' GEN $@'
218 $(q)$(PYTHON3) ./scripts/mem_usage.py $< > $@
219endif
220
221all: $(link-out-dir)/tee-raw.bin
LINE BY LINE
133-221줄 해설
원본에 보이는 모든 줄을 순서대로 설명한다. 빈 줄도 block 경계로 남겨, 코드와 설명의 위치가 어긋나지 않게 했다.
link-script-extra-deps += $(link-out-dir)/rodata_init.ld.S원본 133번 줄의 link-script-extra-deps += $(link-out-dir)/rodata_init.ld.S는 앞의 이전 block 경계 결과를 받아 다음 link-script-extra-deps += $(conf-file)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
link-script-extra-deps += $(conf-file)원본 134번 줄의 link-script-extra-deps += $(conf-file)는 앞의 link-script-extra-deps += $(link-out-dir)/rodata_init.ld.S 결과를 받아 다음 cleanfiles += $(link-script-pp) $(link-script-dep)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-script-pp) $(link-script-dep)원본 135번 줄의 cleanfiles += $(link-script-pp) $(link-script-dep)는 앞의 link-script-extra-deps += $(conf-file) 결과를 받아 다음 $(link-script-pp): $(link-script) $(link-script-extra-deps)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-script-pp): $(link-script) $(link-script-extra-deps)원본 136번 줄의 $(link-script-pp): $(link-script) $(link-script-extra-deps)는 앞의 cleanfiles += $(link-script-pp) $(link-script-dep) 결과를 받아 다음 @$(cmd-echo-silent) ' CPP $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' CPP $@'원본 137번 줄의 @$(cmd-echo-silent) ' CPP $@'는 앞의 $(link-script-pp): $(link-script) $(link-script-extra-deps) 결과를 받아 다음 @mkdir -p $(dir $@)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@mkdir -p $(dir $@)원본 138번 줄의 @mkdir -p $(dir $@)는 앞의 @$(cmd-echo-silent) ' CPP $@' 결과를 받아 다음 $(q)$(CPPcore) -P -MT $@ -MD -MP -MF $(link-script-dep) \로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(CPPcore) -P -MT $@ -MD -MP -MF $(link-script-dep) \원본 139번 줄의 $(q)$(CPPcore) -P -MT $@ -MD -MP -MF $(link-script-dep) \는 앞의 @mkdir -p $(dir $@) 결과를 받아 다음 $(link-script-cppflags) $< -o $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-script-cppflags) $< -o $@원본 140번 줄의 $(link-script-cppflags) $< -o $@는 앞의 $(q)$(CPPcore) -P -MT $@ -MD -MP -MF $(link-script-dep) \ 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(link-script-cppflags) $< -o $@까지의 동작과 $(link-out-dir)/version.o:에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
$(link-out-dir)/version.o:원본 142번 줄의 $(link-out-dir)/version.o:는 앞의 이전 block 경계 결과를 받아 다음 $(call gen-version-o)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(call gen-version-o)원본 143번 줄의 $(call gen-version-o)는 앞의 $(link-out-dir)/version.o: 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(call gen-version-o)까지의 동작과 -include $(link-out-dir)/.tee.elf.cmd에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
-include $(link-out-dir)/.tee.elf.cmd원본 145번 줄의 -include $(link-out-dir)/.tee.elf.cmd는 앞의 이전 block 경계 결과를 받아 다음 define check-link-objs로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
define check-link-objs원본 146번 줄의 define check-link-objs는 앞의 -include $(link-out-dir)/.tee.elf.cmd 결과를 받아 다음 $(if $(strip $(filter-out $(link-objs), $(old-link-objs))로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(if $(strip $(filter-out $(link-objs), $(old-link-objs))원본 147번 줄의 $(if $(strip $(filter-out $(link-objs), $(old-link-objs))는 앞의 define check-link-objs 결과를 받아 다음 $(filter-out $(old-link-objs), $(link-objs))), FORCE_LINK := FORCE)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(filter-out $(old-link-objs), $(link-objs))), FORCE_LINK := FORCE)원본 148번 줄의 $(filter-out $(old-link-objs), $(link-objs))), FORCE_LINK := FORCE)는 앞의 $(if $(strip $(filter-out $(link-objs), $(old-link-objs)) 결과를 받아 다음 endef로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
endef원본 149번 줄의 endef는 앞의 $(filter-out $(old-link-objs), $(link-objs))), FORCE_LINK := FORCE) 결과를 받아 다음 $(eval $(call check-link-objs))로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(eval $(call check-link-objs))원본 150번 줄의 $(eval $(call check-link-objs))는 앞의 endef 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(eval $(call check-link-objs))까지의 동작과 all: $(link-out-dir)/tee.elf에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
all: $(link-out-dir)/tee.elf원본 152번 줄의 all: $(link-out-dir)/tee.elf는 앞의 이전 block 경계 결과를 받아 다음 cleanfiles += $(link-out-dir)/tee.elf $(link-out-dir)/tee.map로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/tee.elf $(link-out-dir)/tee.map원본 153번 줄의 cleanfiles += $(link-out-dir)/tee.elf $(link-out-dir)/tee.map는 앞의 all: $(link-out-dir)/tee.elf 결과를 받아 다음 cleanfiles += $(link-out-dir)/version.o로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/version.o원본 154번 줄의 cleanfiles += $(link-out-dir)/version.o는 앞의 cleanfiles += $(link-out-dir)/tee.elf $(link-out-dir)/tee.map 결과를 받아 다음 cleanfiles += $(link-out-dir)/.buildcount로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/.buildcount원본 155번 줄의 cleanfiles += $(link-out-dir)/.buildcount는 앞의 cleanfiles += $(link-out-dir)/version.o 결과를 받아 다음 cleanfiles += $(link-out-dir)/.tee.elf.cmd로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/.tee.elf.cmd원본 156번 줄의 cleanfiles += $(link-out-dir)/.tee.elf.cmd는 앞의 cleanfiles += $(link-out-dir)/.buildcount 결과를 받아 다음 $(link-out-dir)/tee.elf: $(link-objs) $(libdeps) $(link-script-pp) $(FORCE_LINK)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee.elf: $(link-objs) $(libdeps) $(link-script-pp) $(FORCE_LINK)원본 157번 줄의 $(link-out-dir)/tee.elf: $(link-objs) $(libdeps) $(link-script-pp) $(FORCE_LINK)는 앞의 cleanfiles += $(link-out-dir)/.tee.elf.cmd 결과를 받아 다음 @echo "old-link-objs := $(link-objs)" >$(link-out-dir)/.tee.elf.cmd로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@echo "old-link-objs := $(link-objs)" >$(link-out-dir)/.tee.elf.cmd원본 158번 줄의 @echo "old-link-objs := $(link-objs)" >$(link-out-dir)/.tee.elf.cmd는 앞의 $(link-out-dir)/tee.elf: $(link-objs) $(libdeps) $(link-script-pp) $(FORCE_LINK) 결과를 받아 다음 @$(cmd-echo-silent) ' LD $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' LD $@'원본 159번 줄의 @$(cmd-echo-silent) ' LD $@'는 앞의 @echo "old-link-objs := $(link-objs)" >$(link-out-dir)/.tee.elf.cmd 결과를 받아 다음 $(q)$(LDcore) $(ldargs-tee.elf) -o $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(LDcore) $(ldargs-tee.elf) -o $@원본 160번 줄의 $(q)$(LDcore) $(ldargs-tee.elf) -o $@는 앞의 @$(cmd-echo-silent) ' LD $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(LDcore) $(ldargs-tee.elf) -o $@까지의 동작과 all: $(link-out-dir)/tee.dmp에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
all: $(link-out-dir)/tee.dmp원본 162번 줄의 all: $(link-out-dir)/tee.dmp는 앞의 이전 block 경계 결과를 받아 다음 cleanfiles += $(link-out-dir)/tee.dmp로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/tee.dmp원본 163번 줄의 cleanfiles += $(link-out-dir)/tee.dmp는 앞의 all: $(link-out-dir)/tee.dmp 결과를 받아 다음 $(link-out-dir)/tee.dmp: $(link-out-dir)/tee.elf로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee.dmp: $(link-out-dir)/tee.elf원본 164번 줄의 $(link-out-dir)/tee.dmp: $(link-out-dir)/tee.elf는 앞의 cleanfiles += $(link-out-dir)/tee.dmp 결과를 받아 다음 @$(cmd-echo-silent) ' OBJDUMP $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' OBJDUMP $@'원본 165번 줄의 @$(cmd-echo-silent) ' OBJDUMP $@'는 앞의 $(link-out-dir)/tee.dmp: $(link-out-dir)/tee.elf 결과를 받아 다음 $(q)$(OBJDUMPcore) -l -x -d $< > $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(OBJDUMPcore) -l -x -d $< > $@원본 166번 줄의 $(q)$(OBJDUMPcore) -l -x -d $< > $@는 앞의 @$(cmd-echo-silent) ' OBJDUMP $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(OBJDUMPcore) -l -x -d $< > $@까지의 동작과 cleanfiles += $(link-out-dir)/tee-pager.bin에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
cleanfiles += $(link-out-dir)/tee-pager.bin원본 168번 줄의 cleanfiles += $(link-out-dir)/tee-pager.bin는 앞의 이전 block 경계 결과를 받아 다음 $(link-out-dir)/tee-pager.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee-pager.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py원본 169번 줄의 $(link-out-dir)/tee-pager.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py는 앞의 cleanfiles += $(link-out-dir)/tee-pager.bin 결과를 받아 다음 @echo Warning: $@ is deprecated로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@echo Warning: $@ is deprecated원본 170번 줄의 @echo Warning: $@ is deprecated는 앞의 $(link-out-dir)/tee-pager.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py 결과를 받아 다음 @$(cmd-echo-silent) ' GEN $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' GEN $@'원본 171번 줄의 @$(cmd-echo-silent) ' GEN $@'는 앞의 @echo Warning: $@ is deprecated 결과를 받아 다음 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pager_bin $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pager_bin $@원본 172번 줄의 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pager_bin $@는 앞의 @$(cmd-echo-silent) ' GEN $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pager_bin $@까지의 동작과 cleanfiles += $(link-out-dir)/tee-pageable.bin에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
cleanfiles += $(link-out-dir)/tee-pageable.bin원본 174번 줄의 cleanfiles += $(link-out-dir)/tee-pageable.bin는 앞의 이전 block 경계 결과를 받아 다음 $(link-out-dir)/tee-pageable.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee-pageable.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py원본 175번 줄의 $(link-out-dir)/tee-pageable.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py는 앞의 cleanfiles += $(link-out-dir)/tee-pageable.bin 결과를 받아 다음 @echo Warning: $@ is deprecated로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@echo Warning: $@ is deprecated원본 176번 줄의 @echo Warning: $@ is deprecated는 앞의 $(link-out-dir)/tee-pageable.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py 결과를 받아 다음 @$(cmd-echo-silent) ' GEN $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' GEN $@'원본 177번 줄의 @$(cmd-echo-silent) ' GEN $@'는 앞의 @echo Warning: $@ is deprecated 결과를 받아 다음 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pageable_bin $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pageable_bin $@원본 178번 줄의 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pageable_bin $@는 앞의 @$(cmd-echo-silent) ' GEN $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_pageable_bin $@까지의 동작과 all: $(link-out-dir)/tee.bin에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
all: $(link-out-dir)/tee.bin원본 180번 줄의 all: $(link-out-dir)/tee.bin는 앞의 이전 block 경계 결과를 받아 다음 cleanfiles += $(link-out-dir)/tee.bin로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/tee.bin원본 181번 줄의 cleanfiles += $(link-out-dir)/tee.bin는 앞의 all: $(link-out-dir)/tee.bin 결과를 받아 다음 $(link-out-dir)/tee.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py원본 182번 줄의 $(link-out-dir)/tee.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py는 앞의 cleanfiles += $(link-out-dir)/tee.bin 결과를 받아 다음 @$(cmd-echo-silent) ' GEN $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' GEN $@'원본 183번 줄의 @$(cmd-echo-silent) ' GEN $@'는 앞의 $(link-out-dir)/tee.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py 결과를 받아 다음 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_bin $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_bin $@원본 184번 줄의 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_bin $@는 앞의 @$(cmd-echo-silent) ' GEN $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_tee_bin $@까지의 동작과 all: $(link-out-dir)/tee-header_v2.bin에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
all: $(link-out-dir)/tee-header_v2.bin원본 186번 줄의 all: $(link-out-dir)/tee-header_v2.bin는 앞의 이전 block 경계 결과를 받아 다음 cleanfiles += $(link-out-dir)/tee-header_v2.bin로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/tee-header_v2.bin원본 187번 줄의 cleanfiles += $(link-out-dir)/tee-header_v2.bin는 앞의 all: $(link-out-dir)/tee-header_v2.bin 결과를 받아 다음 $(link-out-dir)/tee-header_v2.bin: $(link-out-dir)/tee.elf \로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee-header_v2.bin: $(link-out-dir)/tee.elf \원본 188번 줄의 $(link-out-dir)/tee-header_v2.bin: $(link-out-dir)/tee.elf \는 앞의 cleanfiles += $(link-out-dir)/tee-header_v2.bin 결과를 받아 다음 scripts/gen_tee_bin.py로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
scripts/gen_tee_bin.py원본 189번 줄의 scripts/gen_tee_bin.py는 앞의 $(link-out-dir)/tee-header_v2.bin: $(link-out-dir)/tee.elf \ 결과를 받아 다음 @$(cmd-echo-silent) ' GEN $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' GEN $@'원본 190번 줄의 @$(cmd-echo-silent) ' GEN $@'는 앞의 scripts/gen_tee_bin.py 결과를 받아 다음 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_header_v2 $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_header_v2 $@원본 191번 줄의 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_header_v2 $@는 앞의 @$(cmd-echo-silent) ' GEN $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_header_v2 $@까지의 동작과 all: $(link-out-dir)/tee-pager_v2.bin에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
all: $(link-out-dir)/tee-pager_v2.bin원본 193번 줄의 all: $(link-out-dir)/tee-pager_v2.bin는 앞의 이전 block 경계 결과를 받아 다음 cleanfiles += $(link-out-dir)/tee-pager_v2.bin로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/tee-pager_v2.bin원본 194번 줄의 cleanfiles += $(link-out-dir)/tee-pager_v2.bin는 앞의 all: $(link-out-dir)/tee-pager_v2.bin 결과를 받아 다음 $(link-out-dir)/tee-pager_v2.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee-pager_v2.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py원본 195번 줄의 $(link-out-dir)/tee-pager_v2.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py는 앞의 cleanfiles += $(link-out-dir)/tee-pager_v2.bin 결과를 받아 다음 @$(cmd-echo-silent) ' GEN $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' GEN $@'원본 196번 줄의 @$(cmd-echo-silent) ' GEN $@'는 앞의 $(link-out-dir)/tee-pager_v2.bin: $(link-out-dir)/tee.elf scripts/gen_tee_bin.py 결과를 받아 다음 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pager_v2 $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pager_v2 $@원본 197번 줄의 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pager_v2 $@는 앞의 @$(cmd-echo-silent) ' GEN $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pager_v2 $@까지의 동작과 all: $(link-out-dir)/tee-pageable_v2.bin에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
all: $(link-out-dir)/tee-pageable_v2.bin원본 199번 줄의 all: $(link-out-dir)/tee-pageable_v2.bin는 앞의 이전 block 경계 결과를 받아 다음 cleanfiles += $(link-out-dir)/tee-pageable_v2.bin로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/tee-pageable_v2.bin원본 200번 줄의 cleanfiles += $(link-out-dir)/tee-pageable_v2.bin는 앞의 all: $(link-out-dir)/tee-pageable_v2.bin 결과를 받아 다음 $(link-out-dir)/tee-pageable_v2.bin: $(link-out-dir)/tee.elf \로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee-pageable_v2.bin: $(link-out-dir)/tee.elf \원본 201번 줄의 $(link-out-dir)/tee-pageable_v2.bin: $(link-out-dir)/tee.elf \는 앞의 cleanfiles += $(link-out-dir)/tee-pageable_v2.bin 결과를 받아 다음 scripts/gen_tee_bin.py로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
scripts/gen_tee_bin.py원본 202번 줄의 scripts/gen_tee_bin.py는 앞의 $(link-out-dir)/tee-pageable_v2.bin: $(link-out-dir)/tee.elf \ 결과를 받아 다음 @$(cmd-echo-silent) ' GEN $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' GEN $@'원본 203번 줄의 @$(cmd-echo-silent) ' GEN $@'는 앞의 scripts/gen_tee_bin.py 결과를 받아 다음 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pageable_v2 $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pageable_v2 $@원본 204번 줄의 $(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pageable_v2 $@는 앞의 @$(cmd-echo-silent) ' GEN $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(PYTHON3) scripts/gen_tee_bin.py --input $< --out_pageable_v2 $@까지의 동작과 all: $(link-out-dir)/tee.symb_sizes에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
all: $(link-out-dir)/tee.symb_sizes원본 206번 줄의 all: $(link-out-dir)/tee.symb_sizes는 앞의 이전 block 경계 결과를 받아 다음 cleanfiles += $(link-out-dir)/tee.symb_sizes로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
cleanfiles += $(link-out-dir)/tee.symb_sizes원본 207번 줄의 cleanfiles += $(link-out-dir)/tee.symb_sizes는 앞의 all: $(link-out-dir)/tee.symb_sizes 결과를 받아 다음 $(link-out-dir)/tee.symb_sizes: $(link-out-dir)/tee.elf로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(link-out-dir)/tee.symb_sizes: $(link-out-dir)/tee.elf원본 208번 줄의 $(link-out-dir)/tee.symb_sizes: $(link-out-dir)/tee.elf는 앞의 cleanfiles += $(link-out-dir)/tee.symb_sizes 결과를 받아 다음 @$(cmd-echo-silent) ' GEN $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' GEN $@'원본 209번 줄의 @$(cmd-echo-silent) ' GEN $@'는 앞의 $(link-out-dir)/tee.symb_sizes: $(link-out-dir)/tee.elf 결과를 받아 다음 $(q)$(NMcore) --print-size --reverse-sort --size-sort $< > $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(NMcore) --print-size --reverse-sort --size-sort $< > $@원본 210번 줄의 $(q)$(NMcore) --print-size --reverse-sort --size-sort $< > $@는 앞의 @$(cmd-echo-silent) ' GEN $@' 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)$(q)$(NMcore) --print-size --reverse-sort --size-sort $< > $@까지의 동작과 cleanfiles += $(link-out-dir)/tee.mem_usage에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
cleanfiles += $(link-out-dir)/tee.mem_usage원본 212번 줄의 cleanfiles += $(link-out-dir)/tee.mem_usage는 앞의 이전 block 경계 결과를 받아 다음 ifneq ($(filter mem_usage,$(MAKECMDGOALS)),)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
ifneq ($(filter mem_usage,$(MAKECMDGOALS)),)ifneq($(filter mem_usage,$(MAKECMDGOALS)),)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
mem_usage: $(link-out-dir)/tee.mem_usage원본 214번 줄의 mem_usage: $(link-out-dir)/tee.mem_usage는 앞의 ifneq ($(filter mem_usage,$(MAKECMDGOALS)),) 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)mem_usage: $(link-out-dir)/tee.mem_usage까지의 동작과 $(link-out-dir)/tee.mem_usage: $(link-out-dir)/tee.elf에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
$(link-out-dir)/tee.mem_usage: $(link-out-dir)/tee.elf원본 216번 줄의 $(link-out-dir)/tee.mem_usage: $(link-out-dir)/tee.elf는 앞의 이전 block 경계 결과를 받아 다음 @$(cmd-echo-silent) ' GEN $@'로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
@$(cmd-echo-silent) ' GEN $@'원본 217번 줄의 @$(cmd-echo-silent) ' GEN $@'는 앞의 $(link-out-dir)/tee.mem_usage: $(link-out-dir)/tee.elf 결과를 받아 다음 $(q)$(PYTHON3) ./scripts/mem_usage.py $< > $@로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
$(q)$(PYTHON3) ./scripts/mem_usage.py $< > $@원본 218번 줄의 $(q)$(PYTHON3) ./scripts/mem_usage.py $< > $@는 앞의 @$(cmd-echo-silent) ' GEN $@' 결과를 받아 다음 endif로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
endif원본 219번 줄의 endif는 앞의 $(q)$(PYTHON3) ./scripts/mem_usage.py $< > $@ 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)endif까지의 동작과 all: $(link-out-dir)/tee-raw.bin에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
all: $(link-out-dir)/tee-raw.bin원본 221번 줄의 all: $(link-out-dir)/tee-raw.bin는 앞의 이전 block 경계 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
RELATED SOURCE
함께 읽어야 하는 원본 코드
첫 코드 조각만으로 동작이 완성되지 않는 경우 호출 매크로, 객체 정의와 실제 실행 목록을 같은 페이지에 묶었다. 각 조각은 같은 기준 commit에서 가져왔다.
01. tee.elf section을 pager/pageable image로 변환
scripts/gen_tee_bin.py 365-412줄이다.
365 required=False, type=argparse.FileType('wb'),
366 help='The output tee_pageable.bin')
367
368 parser.add_argument('--out_header_v2',
369 required=False, type=argparse.FileType('wb'),
370 help='The output tee_header_v2.bin')
371
372 parser.add_argument('--out_pager_v2',
373 required=False, type=argparse.FileType('wb'),
374 help='The output tee_pager_v2.bin')
375
376 parser.add_argument('--out_pageable_v2',
377 required=False, type=argparse.FileType('wb'),
378 help='The output tee_pageable_v2.bin')
379
380 return parser.parse_args()
381
382
383def main():
384 args = get_args()
385
386 elffile = ELFFile(args.input)
387
388 if args.out_tee_raw_bin:
389 output_raw_bin(elffile, args.out_tee_raw_bin)
390
391 if args.out_tee_bin:
392 output_header_v1(elffile, args.out_tee_bin)
393
394 if args.out_tee_pager_bin:
395 output_pager_bin(elffile, args.out_tee_pager_bin)
396
397 if args.out_tee_pageable_bin:
398 output_pageable_bin(elffile, args.out_tee_pageable_bin)
399
400 if args.out_header_v2:
401 output_header_v2(elffile, args.out_header_v2)
402
403 if args.out_pager_v2:
404 output_pager_v2(elffile, args.out_pager_v2)
405
406 if args.out_pageable_v2:
407 output_pageable_v2(elffile, args.out_pageable_v2)
408
409
410if __name__ == "__main__":
411 main()
412
365-412줄 해설
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee.elf sections 항목과 대조한다.
help='The output tee_pageable.bin')원본 366번 줄의 help='The output tee_pageable.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_pageable.bin')까지의 동작과 parser.add_argument('--out_header_v2',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-pageable.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_header_v2',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee_header_v2.bin')원본 370번 줄의 help='The output tee_header_v2.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_header_v2.bin')까지의 동작과 parser.add_argument('--out_pager_v2',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_pager_v2',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee_pager_v2.bin')원본 374번 줄의 help='The output tee_pager_v2.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_pager_v2.bin')까지의 동작과 parser.add_argument('--out_pageable_v2',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_pageable_v2',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee_pageable_v2.bin')원본 378번 줄의 help='The output tee_pageable_v2.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_pageable_v2.bin')까지의 동작과 return parser.parse_args()에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
return parser.parse_args()parser.parse_args()를 호출자에게 반환한다. caller가 이 값을 검사한 뒤 부분 초기화된 tee.elf / tee.bin v2 segments를 정리하거나 다음 단계로 진행하는지 확인한다.
(빈 줄)return parser.parse_args()까지의 동작과 다음 block 경계에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
(빈 줄)이전 block 경계까지의 동작과 def main():에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
def main():main(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
args = get_args()get_args(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)args = get_args()까지의 동작과 elffile = ELFFile(args.input)에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
elffile = ELFFile(args.input)ELFFile(args.input)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)elffile = ELFFile(args.input)까지의 동작과 if args.out_tee_raw_bin:에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
if args.out_tee_raw_bin:원본 388번 줄의 if args.out_tee_raw_bin:는 앞의 이전 block 경계 결과를 받아 다음 output_raw_bin(elffile, args.out_tee_raw_bin)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
output_raw_bin(elffile, args.out_tee_raw_bin)output_raw_bin(elffile, args.out_tee_raw_bin)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)output_raw_bin(elffile, args.out_tee_raw_bin)까지의 동작과 if args.out_tee_bin:에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
if args.out_tee_bin:원본 391번 줄의 if args.out_tee_bin:는 앞의 이전 block 경계 결과를 받아 다음 output_header_v1(elffile, args.out_tee_bin)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
output_header_v1(elffile, args.out_tee_bin)output_header_v1(elffile, args.out_tee_bin)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)output_header_v1(elffile, args.out_tee_bin)까지의 동작과 if args.out_tee_pager_bin:에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
if args.out_tee_pager_bin:원본 394번 줄의 if args.out_tee_pager_bin:는 앞의 이전 block 경계 결과를 받아 다음 output_pager_bin(elffile, args.out_tee_pager_bin)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
output_pager_bin(elffile, args.out_tee_pager_bin)output_pager_bin(elffile, args.out_tee_pager_bin)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)output_pager_bin(elffile, args.out_tee_pager_bin)까지의 동작과 if args.out_tee_pageable_bin:에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
if args.out_tee_pageable_bin:원본 397번 줄의 if args.out_tee_pageable_bin:는 앞의 이전 block 경계 결과를 받아 다음 output_pageable_bin(elffile, args.out_tee_pageable_bin)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
output_pageable_bin(elffile, args.out_tee_pageable_bin)output_pageable_bin(elffile, args.out_tee_pageable_bin)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)output_pageable_bin(elffile, args.out_tee_pageable_bin)까지의 동작과 if args.out_header_v2:에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
if args.out_header_v2:원본 400번 줄의 if args.out_header_v2:는 앞의 이전 block 경계 결과를 받아 다음 output_header_v2(elffile, args.out_header_v2)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
output_header_v2(elffile, args.out_header_v2)output_header_v2(elffile, args.out_header_v2)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)output_header_v2(elffile, args.out_header_v2)까지의 동작과 if args.out_pager_v2:에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
if args.out_pager_v2:원본 403번 줄의 if args.out_pager_v2:는 앞의 이전 block 경계 결과를 받아 다음 output_pager_v2(elffile, args.out_pager_v2)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
output_pager_v2(elffile, args.out_pager_v2)output_pager_v2(elffile, args.out_pager_v2)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)output_pager_v2(elffile, args.out_pager_v2)까지의 동작과 if args.out_pageable_v2:에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
if args.out_pageable_v2:원본 406번 줄의 if args.out_pageable_v2:는 앞의 이전 block 경계 결과를 받아 다음 output_pageable_v2(elffile, args.out_pageable_v2)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
output_pageable_v2(elffile, args.out_pageable_v2)output_pageable_v2(elffile, args.out_pageable_v2)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)output_pageable_v2(elffile, args.out_pageable_v2)까지의 동작과 다음 block 경계에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
(빈 줄)이전 block 경계까지의 동작과 if __name__ == "__main__":에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
if __name__ == "__main__":원본 410번 줄의 if __name__ == "__main__":는 앞의 이전 block 경계 결과를 받아 다음 main()로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
main()main(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)main()까지의 동작과 다음 block 경계에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
02. v2 image header와 segment descriptor를 출력
scripts/gen_tee_bin.py 293-377줄이다.
293 magic = 0x4554504f # 'OPTE'
294 version = 1
295 flags = 0
296 outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags,
297 init_size, init_load_addr[0], init_load_addr[1],
298 init_mem_usage, paged_size))
299 outf.write(pager_bin)
300 outf.write(pageable_bin[:init_bin_size])
301 outf.write(embdata_bin)
302 outf.write(pageable_bin[init_bin_size:])
303
304
305def output_header_v2(elffile, outf):
306 arch_id = get_arch_id(elffile)
307 init_load_addr = get_init_load_addr(elffile)
308 init_bin_size = get_symbol(elffile, '__init_size')['st_value']
309 pager_bin_size = len(get_pager_bin(elffile))
310 paged_area_size = len(get_pageable_bin(elffile))
311 embdata_bin_size = len(get_embdata_bin(elffile))
312
313 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
314 embdata_bin_size)
315 paged_size = paged_area_size - min(init_bin_size, paged_area_size)
316
317 magic = 0x4554504f # 'OPTE'
318 version = 2
319 flags = 0
320 nb_images = 1 if paged_size == 0 else 2
321 outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,
322 nb_images))
323 outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],
324 0, init_size))
325 if nb_images == 2:
326 outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))
327
328
329def output_pager_v2(elffile, outf):
330 init_bin_size = get_symbol(elffile, '__init_size')['st_value']
331 pager_bin = get_pager_bin(elffile)
332 pageable_bin = get_pageable_bin(elffile)
333 embdata_bin = get_embdata_bin(elffile)
334
335 outf.write(pager_bin)
336 outf.write(pageable_bin[:init_bin_size])
337 outf.write(embdata_bin)
338
339
340def output_pageable_v2(elffile, outf):
341 init_bin_size = get_symbol(elffile, '__init_size')['st_value']
342 outf.write(get_pageable_bin(elffile)[init_bin_size:])
343
344
345def get_args():
346 parser = argparse.ArgumentParser()
347
348 parser.add_argument('--input',
349 required=True, type=argparse.FileType('rb'),
350 help='The input tee.elf')
351
352 parser.add_argument('--out_tee_bin',
353 required=False, type=argparse.FileType('wb'),
354 help='The output tee.bin')
355
356 parser.add_argument('--out_tee_raw_bin',
357 required=False, type=argparse.FileType('wb'),
358 help='The output tee_raw.bin')
359
360 parser.add_argument('--out_tee_pager_bin',
361 required=False, type=argparse.FileType('wb'),
362 help='The output tee_pager.bin')
363
364 parser.add_argument('--out_tee_pageable_bin',
365 required=False, type=argparse.FileType('wb'),
366 help='The output tee_pageable.bin')
367
368 parser.add_argument('--out_header_v2',
369 required=False, type=argparse.FileType('wb'),
370 help='The output tee_header_v2.bin')
371
372 parser.add_argument('--out_pager_v2',
373 required=False, type=argparse.FileType('wb'),
374 help='The output tee_pager_v2.bin')
375
376 parser.add_argument('--out_pageable_v2',
377 required=False, type=argparse.FileType('wb'),
293-377줄 해설
magic = 0x4554504f # 'OPTE'원본 293번 줄의 magic = 0x4554504f # 'OPTE'는 앞의 이전 block 경계 결과를 받아 다음 version = 1로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
version = 1원본 294번 줄의 version = 1는 앞의 magic = 0x4554504f # 'OPTE' 결과를 받아 다음 flags = 0로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
flags = 0원본 295번 줄의 flags = 0는 앞의 version = 1 결과를 받아 다음 outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags,로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags,pack(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
init_size, init_load_addr[0], init_load_addr[1],원본 297번 줄의 init_size, init_load_addr[0], init_load_addr[1],는 앞의 outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags, 결과를 받아 다음 init_mem_usage, paged_size))로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
init_mem_usage, paged_size))원본 298번 줄의 init_mem_usage, paged_size))는 앞의 init_size, init_load_addr[0], init_load_addr[1], 결과를 받아 다음 outf.write(pager_bin)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
outf.write(pager_bin)write(pager_bin)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
outf.write(pageable_bin[:init_bin_size])write(pageable_bin[:init_bin_size])를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
outf.write(embdata_bin)write(embdata_bin)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
outf.write(pageable_bin[init_bin_size:])write(pageable_bin[init_bin_size:])를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)outf.write(pageable_bin[init_bin_size:])까지의 동작과 다음 block 경계에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
(빈 줄)이전 block 경계까지의 동작과 def output_header_v2(elffile, outf):에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
def output_header_v2(elffile, outf):output_header_v2(elffile, outf)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
arch_id = get_arch_id(elffile)get_arch_id(elffile)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
init_load_addr = get_init_load_addr(elffile)get_init_load_addr(elffile)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
init_bin_size = get_symbol(elffile, '__init_size')['st_value']get_symbol(elffile, '__init_size')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
pager_bin_size = len(get_pager_bin(elffile))get_pager_bin(elffile))를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
paged_area_size = len(get_pageable_bin(elffile))get_pageable_bin(elffile))를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
embdata_bin_size = len(get_embdata_bin(elffile))get_embdata_bin(elffile))를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)embdata_bin_size = len(get_embdata_bin(elffile))까지의 동작과 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +min(init_bin_size, paged_area_size)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
embdata_bin_size)원본 314번 줄의 embdata_bin_size)는 앞의 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) + 결과를 받아 다음 paged_size = paged_area_size - min(init_bin_size, paged_area_size)로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
paged_size = paged_area_size - min(init_bin_size, paged_area_size)min(init_bin_size, paged_area_size)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)paged_size = paged_area_size - min(init_bin_size, paged_area_size)까지의 동작과 magic = 0x4554504f # 'OPTE'에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
magic = 0x4554504f # 'OPTE'원본 317번 줄의 magic = 0x4554504f # 'OPTE'는 앞의 이전 block 경계 결과를 받아 다음 version = 2로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
version = 2원본 318번 줄의 version = 2는 앞의 magic = 0x4554504f # 'OPTE' 결과를 받아 다음 flags = 0로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
flags = 0원본 319번 줄의 flags = 0는 앞의 version = 2 결과를 받아 다음 nb_images = 1 if paged_size == 0 else 2로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
nb_images = 1 if paged_size == 0 else 2원본 320번 줄의 nb_images = 1 if paged_size == 0 else 2는 앞의 flags = 0 결과를 받아 다음 outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,pack(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
nb_images))원본 322번 줄의 nb_images))는 앞의 outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags, 결과를 받아 다음 outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],pack(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
0, init_size))원본 324번 줄의 0, init_size))는 앞의 outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1], 결과를 받아 다음 if nb_images == 2:로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
if nb_images == 2:원본 325번 줄의 if nb_images == 2:는 앞의 0, init_size)) 결과를 받아 다음 outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))까지의 동작과 다음 block 경계에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
(빈 줄)이전 block 경계까지의 동작과 def output_pager_v2(elffile, outf):에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
def output_pager_v2(elffile, outf):output_pager_v2(elffile, outf)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
init_bin_size = get_symbol(elffile, '__init_size')['st_value']get_symbol(elffile, '__init_size')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
pager_bin = get_pager_bin(elffile)get_pager_bin(elffile)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
pageable_bin = get_pageable_bin(elffile)get_pageable_bin(elffile)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
embdata_bin = get_embdata_bin(elffile)get_embdata_bin(elffile)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)embdata_bin = get_embdata_bin(elffile)까지의 동작과 outf.write(pager_bin)에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
outf.write(pager_bin)write(pager_bin)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
outf.write(pageable_bin[:init_bin_size])write(pageable_bin[:init_bin_size])를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
outf.write(embdata_bin)write(embdata_bin)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)outf.write(embdata_bin)까지의 동작과 다음 block 경계에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
(빈 줄)이전 block 경계까지의 동작과 def output_pageable_v2(elffile, outf):에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
def output_pageable_v2(elffile, outf):output_pageable_v2(elffile, outf)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
init_bin_size = get_symbol(elffile, '__init_size')['st_value']get_symbol(elffile, '__init_size')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
outf.write(get_pageable_bin(elffile)[init_bin_size:])get_pageable_bin(elffile)[init_bin_size:])를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)outf.write(get_pageable_bin(elffile)[init_bin_size:])까지의 동작과 다음 block 경계에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
(빈 줄)이전 block 경계까지의 동작과 def get_args():에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
def get_args():get_args(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
parser = argparse.ArgumentParser()ArgumentParser(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
(빈 줄)parser = argparse.ArgumentParser()까지의 동작과 parser.add_argument('--input',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--input',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=True, type=argparse.FileType('rb'),FileType('rb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The input tee.elf')원본 350번 줄의 help='The input tee.elf')는 앞의 required=True, type=argparse.FileType('rb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The input tee.elf')까지의 동작과 parser.add_argument('--out_tee_bin',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_tee_bin',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee.bin')원본 354번 줄의 help='The output tee.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee.bin')까지의 동작과 parser.add_argument('--out_tee_raw_bin',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_tee_raw_bin',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee_raw.bin')원본 358번 줄의 help='The output tee_raw.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_raw.bin')까지의 동작과 parser.add_argument('--out_tee_pager_bin',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_tee_pager_bin',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee_pager.bin')원본 362번 줄의 help='The output tee_pager.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_pager.bin')까지의 동작과 parser.add_argument('--out_tee_pageable_bin',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_tee_pageable_bin',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee_pageable.bin')원본 366번 줄의 help='The output tee_pageable.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_pageable.bin')까지의 동작과 parser.add_argument('--out_header_v2',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_header_v2',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee_header_v2.bin')원본 370번 줄의 help='The output tee_header_v2.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_header_v2.bin')까지의 동작과 parser.add_argument('--out_pager_v2',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_pager_v2',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
help='The output tee_pager_v2.bin')원본 374번 줄의 help='The output tee_pager_v2.bin')는 앞의 required=False, type=argparse.FileType('wb'), 결과를 받아 다음 다음 block 경계로 넘기는 중간 연산이다. 이 줄이 바꾸는 register·field·list link를 찾고, 변경 뒤에도 'header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다' 조건이 유지되는지 확인한다.
(빈 줄)help='The output tee_pager_v2.bin')까지의 동작과 parser.add_argument('--out_pageable_v2',에서 시작하는 동작을 나누는 빈 줄이다. 앞 블록이 만든 tee-header_v2.bin 상태가 아래 블록의 입력으로 사용되는 경계다.
parser.add_argument('--out_pageable_v2',add_argument(인자 없음)를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
required=False, type=argparse.FileType('wb'),FileType('wb')를 호출한다. 반환값을 직접 사용하지 않으므로 이 함수가 실패를 내부 처리하는지 확인해야 한다. pointer 인자는 tee.elf / tee.bin v2 segments의 소유권을 넘기는지 호출 동안만 빌리는지 구분하고, 호출 뒤 공개되는 상태를 tee-header_v2.bin 항목과 대조한다.
DETAILS
내부 동작을 더 깊게 읽기
진입 조건을 먼저 고정한다
core objects에서 들어온 실행은 host build and TF-A packaging boundary에 놓여 있다. 이때 interrupt, MMU/cache, stack, heap 중 무엇이 이미 준비되었는지 소스의 호출자까지 올라가 확인한다. 같은 함수라도 SPL, relocation 전후, app thread처럼 호출 문맥이 달라지면 허용되는 API와 지연 시간이 달라진다.
하나의 tee.bin만 보지 말고 pager가 켜진 구성과 v2 split image에서 각 파일의 load address와 runtime owner가 어떻게 달라지는지 확인한다.
중심 객체의 생성과 공개를 나눈다
이 글의 중심 객체는 tee.elf / tee.bin v2 segments다. 메모리를 확보한 시점, 필드를 채운 시점, 전역 list나 다른 subsystem에 공개한 시점을 구분한다. 공개 뒤 오류가 발생한다면 목록에서 제거하고 child, buffer, reference를 역순으로 정리하는지 확인한다.
빌드 산출물 관점에서는 tee.elf, tee.bin, pager/pageable images 안에 해당 symbol과 section이 실제로 포함되었는지도 map과 objdump로 검증한다.
주소, 크기와 정렬을 계산한다
부트 코드의 오류는 논리보다 주소 계산에서 먼저 드러나는 경우가 많다. source range, destination range, header가 말하는 payload size, block 또는 page 단위를 표로 적고 각 구간의 끝 주소를 직접 계산한다. 끝 주소는 start + size - 1인지 exclusive end인지 API 계약을 확인한다.
header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다.
성공 flag와 실제 완료 시점을 맞춘다
linker script → tee.elf → gen_tee_bin.py 구간에서는 부분 초기화 상태가 생길 수 있다. flag, list insertion, callback 등록, storage write 완료 중 무엇이 성공의 기준인지 찾는다. hardware write나 DMA가 포함되면 함수 반환과 장치 완료가 같은 시점인지도 확인한다.
다른 CPU, interrupt handler, USB completion 또는 shell command가 상태를 관찰할 수 있다면 memory ordering과 lock 범위도 함께 읽는다.
마지막 handoff의 계약을 적는다
정상 경로는 pager/pageable/header에서 끝난다. 이 단계가 함수 반환인지, scheduler 전환인지, 다른 image로의 비복귀 분기인지 구분한다. 비복귀 handoff라면 cache clean/invalidate, interrupt disable, 장치 quiesce, argument register와 FDT 또는 image address가 최종 점검 항목이다.
반환하는 경로라면 caller가 오류와 부분 성공을 구분하고 다음 후보 또는 복구 경로를 선택하는지 확인한다.
IMPLEMENTATION NOTES
구현을 읽을 때 놓치기 쉬운 부분
core objects에서 pager/pageable/header까지 제어권이 이동하는 조건
tee.elf에서 tee.bin, pager, pageable 조각과 v2 header가 생성되는 규칙을 읽고 TF-A BL32 입력과 연결합니다. 이 경로는 함수 호출 목록만 외워서는 연결되지 않는다. core objects → linker script → tee.elf → gen_tee_bin.py → pager/pageable/header 순서에서 각 단계가 읽는 입력, 새로 확정하는 상태, 다음 단계에 넘기는 값을 구분해야 한다. 특히 host build and TF-A packaging boundary에서는 이전 단계가 남긴 register와 memory attribute가 C 코드의 전제 조건이 된다.
하나의 tee.bin만 보지 말고 pager가 켜진 구성과 v2 split image에서 각 파일의 load address와 runtime owner가 어떻게 달라지는지 확인한다. 따라서 첫 지점에서 tee.elf / tee.bin v2 segments의 주소와 owner를 기록하고, 마지막 지점에서 같은 값이 그대로 유지되는지 아니면 새 객체로 교체되는지를 확인한다. 중간 함수가 성공을 반환해도 header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다.
tee.elf sections와 tee-header_v2.bin의 생성 시점과 수명
이 글에서 함께 나타나는 객체는 tee.elf sections, tee-pager.bin, tee-pageable.bin, tee-header_v2.bin이다. 이름이 비슷해도 저장 위치와 수명은 다르다. build-time descriptor인지, boot 단계의 임시 객체인지, world switch 뒤에도 남는 runtime 객체인지 나눠야 pointer를 따라가다 다른 단계의 구조체를 같은 것으로 오해하지 않는다.
tee.elf / tee.bin v2 segments을 기준으로 allocation 또는 정적 배치 위치, list/table에 공개되는 시점, 참조가 끊기는 시점을 적는다. 그 다음 source와 destination 범위, per-CPU 여부, secure/non-secure 접근 권한을 map과 runtime log로 대조한다. 이 절차를 거치면 단순한 호출 순서가 아니라 실제 소유권 이동이 보인다.
성공 로그만으로 놓치기 쉬운 실패 경계
대표적인 실패 조건은 header/image 조합 불일치: BL32 load 실패; pageable 누락: init 중 page fault; link address 오류: _start 이전 fault이다. 이 문제들은 대개 fault가 발생한 함수보다 앞에서 만들어진 잘못된 주소, size, security state 또는 refcount 때문에 생긴다. 마지막 출력만 보지 말고 각 경계 직전의 상태를 한 줄씩 남겨 최초 불일치 지점을 찾는다.
재현에는 readelf section과 gen_tee_bin descriptor 대조; CFG_WITH_PAGER 전후 산출물 비교; FIP 안 BL32 UUID payload 크기 확인를 사용한다. 정상 경로와 실패 경로에서 같은 필드를 같은 위치에 출력하고, 실패가 검증 단계에서 차단되는지 아니면 다음 context까지 전파되는지 비교한다. firmware와 secure world에서는 실패 뒤의 cleanup 또는 reset 경로도 정상 경로만큼 중요하다.
DEEP ANALYSIS
레지스터에서 오류 판정까지 상세 분석
OP-TEE OS 빌드는 tee.elf를 만든 뒤 확장자만 바꿔 tee.bin을 내는 과정이 아니다. pager를 사용하는 구성에서는 resident pager와 pageable payload가 물리적으로 나뉘고, v2 image header는 각 segment의 load address, size, memory usage와 compression 정보를 TF-A 또는 bootloader에 전달한다.
따라서 최종 파일 하나만 보지 말고 linker section, ELF LOAD segment, gen_tee_bin.py가 만든 segment descriptor, FIP의 BL32 payload를 연결해야 한다. CFG_WITH_PAGER와 CFG_CORE_ASLR 값이 달라지면 같은 symbol의 link address, load address, runtime address 관계도 달라진다.
platform_config와 source selection이 target memory map과 일치해야 한다.
LOAD segment의 VMA, paddr, filesz, memsz, flags를 기록한다.
resident code와 demand-paged byte 범위가 겹치지 않아야 한다.
magic, version, arch, flags와 segment descriptor가 실제 파일과 일치해야 한다.
사용할 OP-TEE packaging 형식과 UUID가 TF-A build option과 맞아야 한다.
각 계약은 앞 단계가 생산하고 현재 단계가 검증한 뒤 다음 소비자에게 넘기는 상태다. 한 항목이라도 확인되지 않으면 뒤 단계의 fault를 그 지점의 문제로 단정하지 않는다.
진입 레지스터와 메모리 계약
함수 첫 줄에 도달했을 때 이미 참이라고 가정하는 값과, 그 값이 틀렸을 때 영향을 받는 범위를 함께 적었다.
| # | 입력 상태 | 생산자 | 정상 조건 | 확인 이유 |
|---|---|---|---|---|
| 01 | PLATFORM/PLATFORM_FLAVOR | build command | platform_config와 source selection이 target memory map과 일치해야 한다. | TEE_RAM, TA_RAM, shared-memory 범위를 결정한다. |
| 02 | tee.elf program header | linker | LOAD segment의 VMA, paddr, filesz, memsz, flags를 기록한다. | raw image와 runtime mapping을 잇는 기준이다. |
| 03 | pager/pageable split | linker symbols와 gen_tee_bin | resident code와 demand-paged byte 범위가 겹치지 않아야 한다. | 초기 적재와 backing store 책임을 나눈다. |
| 04 | v2 header | gen_tee_bin.py | magic, version, arch, flags와 segment descriptor가 실제 파일과 일치해야 한다. | TF-A 또는 loader가 BL32를 배치하는 계약이다. |
| 05 | FIP BL32 entry | TF-A fiptool | 사용할 OP-TEE packaging 형식과 UUID가 TF-A build option과 맞아야 한다. | secure payload가 실제 boot chain에 포함됐음을 확인한다. |
핵심 구조체 필드의 생산자, 소비자와 수명
구조체 이름만 나열하지 않고 어떤 코드가 값을 쓰고, 어느 코드가 처음 읽으며, 언제까지 주소와 내용이 유지되어야 하는지 구분했다.
| # | 객체 또는 필드 | 생산자 | 소비자 | 수명과 불변 조건 |
|---|---|---|---|---|
| 01 | tee.elf | OP-TEE linker | debugger/readelf/objcopy | symbol과 DWARF를 가진 기준 산출물이며 target에 그대로 적재되지 않을 수 있다. |
| 02 | tee-pager.bin | gen_tee_bin | TF-A/bootloader | 항상 resident해야 하는 core와 초기 데이터를 포함한다. |
| 03 | tee-pageable.bin | gen_tee_bin | OP-TEE pager backing setup | hash table과 함께 보존되어 fault 때 검증·복사된다. |
| 04 | tee-header_v2.bin | gen_tee_bin | BL32 image loader | segment file과 한 세트이며 다른 build의 payload와 섞이면 안 된다. |
| 05 | embedded data/hash area | link/build scripts | early relocation와 pager init | 초기 assembly가 이동·검증할 때까지 link layout과 동일해야 한다. |
| 06 | tee.map/symbol table | linker | 주소 검증과 crash decode | 배포 binary와 동일 build임을 hash 또는 build ID로 고정한다. |
함수 내부 실행 순서
소스의 큰 분기와 side effect를 실행 순서대로 다시 펼쳤다. breakpoint는 이 목록의 경계에 두고, 다음 번호로 넘어갈 때 새로 유효해진 객체를 기록한다.
- 01
platform conf.mk와 global config를 합쳐 pager, ASLR, shared memory, storage, log option을 확정한다.
- 02
core, architecture, platform object를 만들고 generated header와 linker script에 최종 memory 상수를 반영한다.
- 03
linker가 resident text/rodata, init, pageable, data/BSS, nozi, stack과 heap section을 배치한다.
- 04
tee.elf의 symbol과 relocation을 검증하고 LOAD segment의 filesz/memsz 차이를 기록한다.
- 05
gen_tee_bin.py가 pager와 pageable byte를 분리하고 필요한 hash·embedded metadata를 생성한다.
- 06
선택한 image format에 따라 monolithic tee.bin 또는 v2 header와 segment 파일을 만든다.
- 07
header descriptor의 load address·size를 ELF와 비교하고 각 segment 파일 hash를 기록한다.
- 08
TF-A FIP에 BL32 payload를 넣고 fiptool unpack 결과가 OP-TEE output과 동일한지 확인한다.
- 09
target의 _start PC, core_mmu_tee_load_pa와 tee.elf symbol을 비교해 실제 load/relocation을 닫는다.
빌드 설정이 바꾸는 실제 코드 경로
동일한 함수 이름이라도 아래 설정에 따라 포함되는 source, 구조체 크기, 인자 의미와 failure path가 달라진다.
| # | 설정 | 바뀌는 동작 | 확인 방법 |
|---|---|---|---|
| 01 | CFG_WITH_PAGER | resident pager와 pageable image를 분리한다. | tee-pager/pageable 크기와 linker symbol을 확인한다. |
| 02 | CFG_CORE_ASLR | core virtual placement와 relocation offset을 바꾼다. | _start load PA와 runtime VA, relocation log를 기록한다. |
| 03 | CFG_CORE_DYN_SHM/CFG_CORE_RESERVED_SHM | 초기 memory map과 메시지 경로에 포함할 shared memory가 달라진다. | DT/config의 NS SHM 범위와 build config를 맞춘다. |
| 04 | CFG_TEE_CORE_LOG_LEVEL | trace 문자열과 timing, image 크기를 바꾼다. | release 산출물의 log level과 map 크기를 기록한다. |
| 05 | CFG_TA_ASLR/CFG_WITH_USER_TA | user TA loader와 address-space 지원 코드를 포함한다. | TA 관련 section/symbol이 기대대로 link됐는지 본다. |
증상에서 최초 불일치 지점까지 추적하기
마지막 panic 메시지가 아니라 어디에서 멈추고 무엇을 읽어 어떤 결론을 내릴지 정리했다. 정상값과 실패값은 같은 build와 같은 위치에서 비교한다.
| # | 관찰 증상 | 중단 위치 | 기록할 값 | 판정 |
|---|---|---|---|---|
| 01 | TF-A가 BL32 header를 거부 | BL32 image parser | header magic/version, segment count, size | TF-A가 기대하는 packaging format과 OP-TEE output 불일치를 찾는다. |
| 02 | _start에서 즉시 abort | BL32 entry와 _start | load PC, tee.elf entry, first bytes, load address | 다른 platform binary 또는 segment 배치 오류를 판정한다. |
| 03 | pager 구성에서만 init hash 실패 | init_pager_runtime | pageable base/size, embedded hash table | pager와 pageable 파일이 서로 다른 build에서 왔는지 확인한다. |
| 04 | crash 주소가 map에 없음 | panic PC decode | runtime VA, ASLR offset, tee.elf build ID | ASLR offset 미적용 또는 잘못된 symbol file 사용을 구분한다. |
OBJECT LIFETIME
객체와 수명
| 대상 | 만들어지는 시점 | 유효 범위 | 확인할 조건 |
|---|---|---|---|
tee.elf / tee.bin v2 segments | linker script | pager/pageable/header 또는 오류 정리 완료까지 | header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다. |
| 입력 buffer / metadata | core objects | parse와 검증이 끝날 때까지 | 길이, 정렬, 소유권, 변조 가능성 |
| 등록된 list / descriptor | tee.elf | subsystem 종료 또는 image handoff까지 | 이중 등록, dangling pointer, 오류 unwind |
| hardware 또는 persistent state | 실제 write/probe가 완료된 뒤 | reset 또는 명시적 해제·갱신까지 | flush, timeout, 전원 차단, rollback |
tee.elf, tee.bin, pager/pageable images | link/image 생성 시점 | 다음 stage가 새 image로 교체할 때까지 | load address, entry, section과 header 일치 |
FAILURE PATH
실패 지점과 증상
| # | 조건 | 관찰되는 증상 | 먼저 볼 단계 |
|---|---|---|---|
| 01 | header/image 조합 불일치 | BL32 load 실패 | linker script |
| 02 | pageable 누락 | init 중 page fault | tee.elf |
| 03 | link address 오류 | _start 이전 fault | gen_tee_bin.py |
로그가 끊긴 마지막 함수만 고치지 않는다. 그 함수가 받은 주소, size, flag가 만들어진 앞 단계까지 올라가고, 오류 뒤 등록 객체와 hardware 상태가 남았는지도 확인한다.
EVIDENCE
소스 밖에서 확인할 증거
소스 해석은 실제 빌드 산출물과 target 로그로 닫아야 한다. 아래 명령의 보드 이름과 toolchain prefix는 사용 중인 빌드 환경에 맞게 바꾼다.
| # | 목적 | 명령 또는 계측 | 판정 기준 |
|---|---|---|---|
| 01 | 빌드 산출물 | make PLATFORM=<platform> CFG_TEE_CORE_LOG_LEVEL=4 | tee.elf, tee.bin과 pageable/pager 구성이 같은 설정에서 생성됐는지 확인한다. |
| 02 | ELF 배치 | ${CROSS_COMPILE64}readelf -W -lS out/arm/core/tee.elf | secure RAM 안에서 text, data, pager, pageable 구간이 어떤 주소와 권한으로 배치되는지 확인한다. |
| 03 | 심볼과 주소 | ${CROSS_COMPILE64}nm -n out/arm/core/tee.elf | grep '$' | entry, thread, TA manager 함수의 링크 주소를 원본 설명과 연결한다. |
| 04 | 명령과 예외 경로 | ${CROSS_COMPILE64}objdump -drS out/arm/core/tee.elf | SMC entry, world switch, abort 복귀가 실제 register save/restore와 어떻게 이어지는지 대조한다. |
| 05 | Normal world 왕복 | xtest; dmesg | grep -i optee | secure console과 Linux OP-TEE driver 로그를 함께 보고 SMC, RPC, shared memory 왕복의 양쪽 증거를 맞춘다. |
LAB
직접 확인할 실험
- 01readelf section과 gen_tee_bin descriptor 대조
linker script진입 전후에 tee.elf sections의 주소·크기·반환값과 timestamp를 함께 남긴다. 결과는 정상 부팅 여부로 끝내지 말고 header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다. 조건이 처음 깨지는 줄을 기록한다. - 02CFG_WITH_PAGER 전후 산출물 비교
tee.elf진입 전후에 tee-pager.bin의 주소·크기·반환값과 timestamp를 함께 남긴다. 결과는 정상 부팅 여부로 끝내지 말고 header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다. 조건이 처음 깨지는 줄을 기록한다. - 03FIP 안 BL32 UUID payload 크기 확인
gen_tee_bin.py진입 전후에 tee-pageable.bin의 주소·크기·반환값과 timestamp를 함께 남긴다. 결과는 정상 부팅 여부로 끝내지 말고 header의 segment descriptor와 실제 output file 크기·load address가 일치하고 TF-A가 선택한 BL32 packaging 방식과 맞아야 한다. 조건이 처음 깨지는 줄을 기록한다.
PRIMARY REFERENCES