← Architecture 비교DUJINLABS.COM

Linux 6.18.37 LTS · Architecture comparison 21/21

Boot firmware handoff: DTB, ACPI, EFI와 setup_arch

bootloader/firmware가 kernel image, memory map, CPU topology와 command line을 넘긴 뒤 각 architecture가 early mapping과 platform description을 확정하는 과정을 비교합니다.

비교 대상
arm64 / x86-64 / RISC-V
실제 원본
3 files · 285 annotated lines
기준 tag
Linux v6.18.37
분석 축
state · ordering · lifetime · latency

01 · QUESTION

무엇을 확인할 것인가

start_kernel() 이전과 setup_arch() 안에서 어떤 정보가 physical pointer로 들어오고, 언제 memblock과 일반 virtual address로 안전하게 사용할 수 있는가?

architecture entry가 최소 MMU/stack을 준비하고 boot parameter를 보존한 뒤 setup_arch()가 memory map, command line, CPU, interrupt/timer와 firmware tables를 검증한다. 결과는 memblock reservations와 generic kernel subsystem 초기화의 입력이 된다.

firmware-owned memory, bootloader temporary data, kernel image/initrd/DTB, reserved-memory와 일반 RAM을 구분한다. early mapping이 없는 physical pointer를 일반 C pointer처럼 dereference하면 안 된다.

지연 시간 관점boot latency는 firmware enumeration, decompression, page-table construction, ACPI/DT parse와 secondary CPU bring-up으로 나뉜다. 오류 분석에는 timestamp보다 마지막 유효 memory ownership 변화가 중요하다.

02 · CONTRACT

공통 계약과 architecture 구현

architecture핵심 mechanism실패 형태확인할 상태
arm64Image header entry, x0 DTB와 EFI stub/ACPI 선택DTB 8-byte alignment/크기, RAM 밖 위치, initrd overlap 또는 reserved-memory 누락은 early abort와 allocator overwrite를 만든다.x0 DTB PA, Image load PA/size, memblock memory/reserved, EFI descriptor, ACPI RSDP와 initrd start/end를 확인한다.
x86-64boot_params zero page, BIOS/e820 또는 EFI와 ACPItruncated boot_params, 겹친 e820 entry, initrd가 low/high limit 밖에 있거나 setup_data chain loop가 있으면 RAM 오인과 overwrite가 발생한다.boot_params PA, e820 raw/sanitized map, setup_data, initrd, EFI descriptors, ACPI RSDP, KASLR physical/virtual offset을 본다.
RISC-Va0 hartid, a1 DTB와 SBI firmware contractboot hart mismatch, DTB의 hart mapping/ISA string 오류, unsupported SATP mode 또는 SBI version 차이는 secondary hart, timer와 MMU 초기화 실패를 만든다.a0/a1, boot_cpu_hartid, DTB totalsize, memblock ranges, SATP.MODE/root PPN, SBI spec/extensions와 initrd를 확인한다.

03 · DIAGRAMS

세 그림으로 먼저 읽기

그림 1. 같은 목적, 서로 다른 mechanism각 ISA에서 실제로 추적할 state와 checkpoint를 한 줄에 맞췄습니다.

arm64

mechanism
Image header entry, x0 DTB와 EFI stub/ACPI 선택
state
boot protocol은 x0에 DTB physical address를 넘기고 MMU off, cache 조건을 규정한다. EFI stub을 거치면 EFI memory map과 system table도 보존한다. setup_arch()가 early FDT를 scan하고 memblock, ACPI 여부와 CPU topology를 확정한다.
checkpoint
x0 DTB PA, Image load PA/size, memblock memory/reserved, EFI descriptor, ACPI RSDP와 initrd start/end를 확인한다.

x86-64

mechanism
boot_params zero page, BIOS/e820 또는 EFI와 ACPI
state
boot protocol의 boot_params에 e820 memory map, command line, initrd와 framebuffer 정보가 들어온다. EFI boot path는 EFI memory map을 병합하고 setup_arch()가 e820을 sanitize해 memblock에 반영하며 ACPI/SMBIOS를 찾는다.
checkpoint
boot_params PA, e820 raw/sanitized map, setup_data, initrd, EFI descriptors, ACPI RSDP, KASLR physical/virtual offset을 본다.

RISC-V

mechanism
a0 hartid, a1 DTB와 SBI firmware contract
state
entry ABI는 a0에 boot hart id, a1에 DTB physical address를 넘긴다. EFI stub 경로도 가능하지만 일반 platform은 DTB와 SBI를 사용한다. setup_arch()가 FDT memory/CPU/ISA 정보를 읽고 memblock, SATP mode와 paging을 확정한다.
checkpoint
a0/a1, boot_cpu_hartid, DTB totalsize, memblock ranges, SATP.MODE/root PPN, SBI spec/extensions와 initrd를 확인한다.
그림 2. 공통 kernel과 architecture hook의 소유권공통 정책이 hardware state를 직접 소유하지 않는 경계를 표시합니다.
Linux common contractarchitecture entry가 최소 MMU/stack을 준비하고 boot parameter를 보존한 뒤 setup_arch()가 memory map, command line, CPU, interrupt/timer와 firmware tables를 검증한다. 결과는 memblock reservations와 generic kernel subsystem 초기화의 입력이 된다.
arm64Image header entry, x0 DTB와 EFI stub/ACPI 선택DTB와 initrd를 memblock reserve한 뒤 memory limit/nomap을 적용하고 page table을 확장한다. EFI memory map exit 시점과 runtime mapping도 순서를 가진다.
x86-64boot_params zero page, BIOS/e820 또는 EFI와 ACPIreal-mode/early identity mapping에서 받은 physical pointer를 reserve하고 e820 type 충돌을 정리한 뒤 direct map을 만든다. KASLR relocation도 reserved range와 함께 계산한다.
RISC-Va0 hartid, a1 DTB와 SBI firmware contractDTB를 early mapping으로 읽고 kernel/initrd/reserved-memory를 reserve한 뒤 final page table과 fixmap을 전환한다. SBI extension probe는 timer, IPI, RFENCE와 reset backend 선택에 영향을 준다.
lifetime boundaryDTB, EFI map, ACPI tables와 initrd는 parse와 필요한 copy가 끝날 때까지 memblock에서 reserve해야 한다. reclaimable firmware memory는 해당 consumer가 완료된 뒤에만 buddy allocator로 넘긴다.
그림 3. publication과 관찰 순서state를 준비한 뒤 architecture ordering을 거쳐 관찰 가능한 checkpoint가 됩니다.
arm64state 준비DTB와 initrd를 memblock reserve한 뒤 memory limit/nomap을 적용하고 page table을 확장한다. EFI memory map exit 시점과 runtime mapping도 순서를 가진다.관찰: x0 DTB PA, Image load PA/size, memblock memory/reserved, EFI descriptor, ACPI RSDP와 initrd start/end를 확인한다.
x86-64state 준비real-mode/early identity mapping에서 받은 physical pointer를 reserve하고 e820 type 충돌을 정리한 뒤 direct map을 만든다. KASLR relocation도 reserved range와 함께 계산한다.관찰: boot_params PA, e820 raw/sanitized map, setup_data, initrd, EFI descriptors, ACPI RSDP, KASLR physical/virtual offset을 본다.
RISC-Vstate 준비DTB를 early mapping으로 읽고 kernel/initrd/reserved-memory를 reserve한 뒤 final page table과 fixmap을 전환한다. SBI extension probe는 timer, IPI, RFENCE와 reset backend 선택에 영향을 준다.관찰: a0/a1, boot_cpu_hartid, DTB totalsize, memblock ranges, SATP.MODE/root PPN, SBI spec/extensions와 initrd를 확인한다.

04 · SOURCE

Linux 6.18.37 원본 코드와 줄별 설명

소스 위치를 고정된 숫자로 복사하지 않고 Linux v6.18.37 tree에서 함수 선언을 다시 찾아 발췌했습니다. 아래 코드와 각 줄의 설명은 1:1로 대응합니다.

arm64 · Linux 6.18.37

Image header entry, x0 DTB와 EFI stub/ACPI 선택

boot protocol은 x0에 DTB physical address를 넘기고 MMU off, cache 조건을 규정한다. EFI stub을 거치면 EFI memory map과 system table도 보존한다. setup_arch()가 early FDT를 scan하고 memblock, ACPI 여부와 CPU topology를 확정한다.

원본 코드: arch/arm64/kernel/setup.c:273-363

273 
274u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
275 
276u64 cpu_logical_map(unsigned int cpu)
277{
278	return __cpu_logical_map[cpu];
279}
280 
281void __init __no_sanitize_address setup_arch(char **cmdline_p)
282{
283	setup_initial_init_mm(_text, _etext, _edata, _end);
284 
285	*cmdline_p = boot_command_line;
286 
287	kaslr_init();
288 
289	early_fixmap_init();
290	early_ioremap_init();
291 
292	setup_machine_fdt(__fdt_pointer);
293 
294	/*
295	 * Initialise the static keys early as they may be enabled by the
296	 * cpufeature code and early parameters.
297	 */
298	jump_label_init();
299	parse_early_param();
300 
301	dynamic_scs_init();
302 
303	/*
304	 * The primary CPU enters the kernel with all DAIF exceptions masked.
305	 *
306	 * We must unmask Debug and SError before preemption or scheduling is
307	 * possible to ensure that these are consistently unmasked across
308	 * threads, and we want to unmask SError as soon as possible after
309	 * initializing earlycon so that we can report any SErrors immediately.
310	 *
311	 * IRQ and FIQ will be unmasked after the root irqchip has been
312	 * detected and initialized.
313	 */
314	local_daif_restore(DAIF_PROCCTX_NOIRQ);
315 
316	/*
317	 * TTBR0 is only used for the identity mapping at this stage. Make it
318	 * point to zero page to avoid speculatively fetching new entries.
319	 */
320	cpu_uninstall_idmap();
321 
322	xen_early_init();
323	efi_init();
324 
325	if (!efi_enabled(EFI_BOOT)) {
326		if ((u64)_text % MIN_KIMG_ALIGN)
327			pr_warn(FW_BUG "Kernel image misaligned at boot, please fix your bootloader!");
328		WARN_TAINT(mmu_enabled_at_boot, TAINT_FIRMWARE_WORKAROUND,
329			   FW_BUG "Booted with MMU enabled!");
330	}
331 
332	arm64_memblock_init();
333 
334	paging_init();
335 
336	acpi_table_upgrade();
337 
338	/* Parse the ACPI tables for possible boot-time configuration */
339	acpi_boot_table_init();
340 
341	if (acpi_disabled)
342		unflatten_device_tree();
343 
344	bootmem_init();
345 
346	kasan_init();
347 
348	request_standard_resources();
349 
350	early_ioremap_reset();
351 
352	if (acpi_disabled)
353		psci_dt_init();
354	else
355		psci_acpi_init();
356 
357	arm64_rsi_init();
358 
359	init_bootcpu_ops();
360	smp_init_cpus();
361	smp_build_mpidr_hash();
362 
363#ifdef CONFIG_ARM64_SW_TTBR0_PAN

라인 바이 라인 주석

빈 줄과 전처리 경계도 생략하지 않았습니다. 원본의 91개 줄에 각각 설명을 붙였습니다.

L273(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L274u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };

계산한 pointer, flag, register image 또는 generation을 다음 단계가 읽을 위치에 저장한다. 값의 단위, address space와 publication ordering을 확인한다.

L275(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L276u64 cpu_logical_map(unsigned int cpu)

이 함수의 진입 계약이 시작된다. arm64에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.

L277{

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L278 return __cpu_logical_map[cpu];

이 함수가 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 단계의 결과 또는 오류를 상위 계층에 전달한다. 반환 전에 lock, interrupt state, reference와 hardware active state가 정리됐는지 확인한다.

L279}

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L280(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L281void __init __no_sanitize_address setup_arch(char **cmdline_p)

이 함수의 진입 계약이 시작된다. arm64에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.

L282{

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L283 setup_initial_init_mm(_text, _etext, _edata, _end);

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L284(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L285 *cmdline_p = boot_command_line;

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L286(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L287 kaslr_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L288(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L289 early_fixmap_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L290 early_ioremap_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L291(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L292 setup_machine_fdt(__fdt_pointer);

entry에서 보존한 DTB physical pointer를 검증하고 machine model, chosen, memory 정보를 early parse한다.

L293(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L294 /*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L295 * Initialise the static keys early as they may be enabled by the

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L296 * cpufeature code and early parameters.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L297 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L298 jump_label_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L299 parse_early_param();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L300(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L301 dynamic_scs_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L302(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L303 /*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L304 * The primary CPU enters the kernel with all DAIF exceptions masked.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L305 *

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L306 * We must unmask Debug and SError before preemption or scheduling is

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L307 * possible to ensure that these are consistently unmasked across

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L308 * threads, and we want to unmask SError as soon as possible after

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L309 * initializing earlycon so that we can report any SErrors immediately.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L310 *

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L311 * IRQ and FIQ will be unmasked after the root irqchip has been

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L312 * detected and initialized.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L313 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L314 local_daif_restore(DAIF_PROCCTX_NOIRQ);

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L315(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L316 /*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L317 * TTBR0 is only used for the identity mapping at this stage. Make it

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L318 * point to zero page to avoid speculatively fetching new entries.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L319 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L320 cpu_uninstall_idmap();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L321(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L322 xen_early_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L323 efi_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L324(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L325 if (!efi_enabled(EFI_BOOT)) {

이 조건이 arm64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L326 if ((u64)_text % MIN_KIMG_ALIGN)

이 조건이 arm64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L327 pr_warn(FW_BUG "Kernel image misaligned at boot, please fix your bootloader!");

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L328 WARN_TAINT(mmu_enabled_at_boot, TAINT_FIRMWARE_WORKAROUND,

불가능해야 하는 상태 또는 복구 가능한 오류를 외부에 드러내는 줄이다. 직전 register/object 값을 함께 남겨 재현 가능한 failure signature를 만든다.

L329 FW_BUG "Booted with MMU enabled!");

이 줄이 arm64의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.

L330 }

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L331(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L332 arm64_memblock_init();

RAM range에서 kernel, DTB, initrd와 reserved-memory를 제외해 early physical allocator의 소유권을 확정한다.

L333(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L334 paging_init();

최종 kernel linear mapping과 page-table hierarchy를 구성해 이후 일반 virtual memory 초기화 기반을 만든다.

L335(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L336 acpi_table_upgrade();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L337(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L338 /* Parse the ACPI tables for possible boot-time configuration */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L339 acpi_boot_table_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L340(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L341 if (acpi_disabled)

이 조건이 arm64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L342 unflatten_device_tree();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L343(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L344 bootmem_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L345(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L346 kasan_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L347(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L348 request_standard_resources();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L349(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L350 early_ioremap_reset();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L351(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L352 if (acpi_disabled)

이 조건이 arm64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L353 psci_dt_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L354 else

앞 조건이 성립하지 않았을 때의 대체 경로다. fast path와 같은 ownership, ordering과 반환 계약을 제공해야 한다.

L355 psci_acpi_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L356(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L357 arm64_rsi_init();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L358(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L359 init_bootcpu_ops();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L360 smp_init_cpus();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L361 smp_build_mpidr_hash();

helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L362(blank)

빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L363#ifdef CONFIG_ARM64_SW_TTBR0_PAN

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

x86-64 · Linux 6.18.37

boot_params zero page, BIOS/e820 또는 EFI와 ACPI

boot protocol의 boot_params에 e820 memory map, command line, initrd와 framebuffer 정보가 들어온다. EFI boot path는 EFI memory map을 병합하고 setup_arch()가 e820을 sanitize해 memblock에 반영하며 ACPI/SMBIOS를 찾는다.

원본 코드: arch/x86/kernel/setup.c:878-982

878 * systems (with a traditional BIOS) as well as on EFI systems.
879 */
880/*
881 * setup_arch - architecture-specific boot-time initializations
882 *
883 * Note: On x86_64, fixmaps are ready for use even before this is called.
884 */
885 
886void __init setup_arch(char **cmdline_p)
887{
888#ifdef CONFIG_X86_32
889	memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
890 
891	/*
892	 * copy kernel address range established so far and switch
893	 * to the proper swapper page table
894	 */
895	clone_pgd_range(swapper_pg_dir     + KERNEL_PGD_BOUNDARY,
896			initial_page_table + KERNEL_PGD_BOUNDARY,
897			KERNEL_PGD_PTRS);
898 
899	load_cr3(swapper_pg_dir);
900	/*
901	 * Note: Quark X1000 CPUs advertise PGE incorrectly and require
902	 * a cr3 based tlb flush, so the following __flush_tlb_all()
903	 * will not flush anything because the CPU quirk which clears
904	 * X86_FEATURE_PGE has not been invoked yet. Though due to the
905	 * load_cr3() above the TLB has been flushed already. The
906	 * quirk is invoked before subsequent calls to __flush_tlb_all()
907	 * so proper operation is guaranteed.
908	 */
909	__flush_tlb_all();
910#else
911	printk(KERN_INFO "Command line: %s\n", boot_command_line);
912	boot_cpu_data.x86_phys_bits = MAX_PHYSMEM_BITS;
913#endif
914 
915#ifdef CONFIG_CMDLINE_BOOL
916#ifdef CONFIG_CMDLINE_OVERRIDE
917	strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
918#else
919	if (builtin_cmdline[0]) {
920		/* append boot loader cmdline to builtin */
921		strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
922		strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
923		strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
924	}
925#endif
926	builtin_cmdline_added = true;
927#endif
928 
929	strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
930	*cmdline_p = command_line;
931 
932	/*
933	 * If we have OLPC OFW, we might end up relocating the fixmap due to
934	 * reserve_top(), so do this before touching the ioremap area.
935	 */
936	olpc_ofw_detect();
937 
938	idt_setup_early_traps();
939	early_cpu_init();
940	jump_label_init();
941	static_call_init();
942	early_ioremap_init();
943 
944	setup_olpc_ofw_pgd();
945 
946	parse_boot_params();
947 
948	x86_init.oem.arch_setup();
949 
950	/*
951	 * Do some memory reservations *before* memory is added to memblock, so
952	 * memblock allocations won't overwrite it.
953	 *
954	 * After this point, everything still needed from the boot loader or
955	 * firmware or kernel text should be early reserved or marked not RAM in
956	 * e820. All other memory is free game.
957	 *
958	 * This call needs to happen before e820__memory_setup() which calls the
959	 * xen_memory_setup() on Xen dom0 which relies on the fact that those
960	 * early reservations have happened already.
961	 */
962	early_reserve_memory();
963 
964	iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1;
965	e820__memory_setup();
966	parse_setup_data();
967 
968	copy_edd();
969 
970	setup_initial_init_mm(_text, _etext, _edata, (void *)_brk_end);
971 
972	/*
973	 * x86_configure_nx() is called before parse_early_param() to detect
974	 * whether hardware doesn't support NX (so that the early EHCI debug
975	 * console setup can safely call set_fixmap()).
976	 */
977	x86_configure_nx();
978 
979	parse_early_param();
980 
981	if (efi_enabled(EFI_BOOT))
982		efi_memblock_x86_reserve_range();

라인 바이 라인 주석

빈 줄과 전처리 경계도 생략하지 않았습니다. 원본의 105개 줄에 각각 설명을 붙였습니다.

L878 * systems (with a traditional BIOS) as well as on EFI systems.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L879 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L880/*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L881 * setup_arch - architecture-specific boot-time initializations

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L882 *

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L883 * Note: On x86_64, fixmaps are ready for use even before this is called.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L884 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L885(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L886void __init setup_arch(char **cmdline_p)

이 함수의 진입 계약이 시작된다. x86-64에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.

L887{

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L888#ifdef CONFIG_X86_32

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L889 memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L890(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L891 /*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L892 * copy kernel address range established so far and switch

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L893 * to the proper swapper page table

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L894 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L895 clone_pgd_range(swapper_pg_dir + KERNEL_PGD_BOUNDARY,

이 줄이 x86-64의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.

L896 initial_page_table + KERNEL_PGD_BOUNDARY,

이 줄이 x86-64의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.

L897 KERNEL_PGD_PTRS);

이 줄이 x86-64의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.

L898(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L899 load_cr3(swapper_pg_dir);

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L900 /*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L901 * Note: Quark X1000 CPUs advertise PGE incorrectly and require

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L902 * a cr3 based tlb flush, so the following __flush_tlb_all()

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L903 * will not flush anything because the CPU quirk which clears

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L904 * X86_FEATURE_PGE has not been invoked yet. Though due to the

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L905 * load_cr3() above the TLB has been flushed already. The

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L906 * quirk is invoked before subsequent calls to __flush_tlb_all()

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L907 * so proper operation is guaranteed.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L908 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L909 __flush_tlb_all();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L910#else

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L911 printk(KERN_INFO "Command line: %s\n", boot_command_line);

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L912 boot_cpu_data.x86_phys_bits = MAX_PHYSMEM_BITS;

계산한 pointer, flag, register image 또는 generation을 다음 단계가 읽을 위치에 저장한다. 값의 단위, address space와 publication ordering을 확인한다.

L913#endif

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L914(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L915#ifdef CONFIG_CMDLINE_BOOL

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L916#ifdef CONFIG_CMDLINE_OVERRIDE

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L917 strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L918#else

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L919 if (builtin_cmdline[0]) {

이 조건이 x86-64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L920 /* append boot loader cmdline to builtin */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L921 strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L922 strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L923 strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L924 }

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L925#endif

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L926 builtin_cmdline_added = true;

계산한 pointer, flag, register image 또는 generation을 다음 단계가 읽을 위치에 저장한다. 값의 단위, address space와 publication ordering을 확인한다.

L927#endif

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L928(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L929 strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L930 *cmdline_p = command_line;

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L931(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L932 /*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L933 * If we have OLPC OFW, we might end up relocating the fixmap due to

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L934 * reserve_top(), so do this before touching the ioremap area.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L935 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L936 olpc_ofw_detect();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L937(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L938 idt_setup_early_traps();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L939 early_cpu_init();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L940 jump_label_init();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L941 static_call_init();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L942 early_ioremap_init();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L943(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L944 setup_olpc_ofw_pgd();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L945(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L946 parse_boot_params();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L947(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L948 x86_init.oem.arch_setup();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L949(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L950 /*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L951 * Do some memory reservations *before* memory is added to memblock, so

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L952 * memblock allocations won't overwrite it.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L953 *

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L954 * After this point, everything still needed from the boot loader or

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L955 * firmware or kernel text should be early reserved or marked not RAM in

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L956 * e820. All other memory is free game.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L957 *

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L958 * This call needs to happen before e820__memory_setup() which calls the

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L959 * xen_memory_setup() on Xen dom0 which relies on the fact that those

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L960 * early reservations have happened already.

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L961 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L962 early_reserve_memory();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L963(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L964 iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1;

계산한 pointer, flag, register image 또는 generation을 다음 단계가 읽을 위치에 저장한다. 값의 단위, address space와 publication ordering을 확인한다.

L965 e820__memory_setup();

firmware/bootloader memory map을 정리해 usable RAM과 reserved type의 기준을 만든다.

L966 parse_setup_data();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L967(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L968 copy_edd();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L969(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L970 setup_initial_init_mm(_text, _etext, _edata, (void *)_brk_end);

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L971(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L972 /*

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L973 * x86_configure_nx() is called before parse_early_param() to detect

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L974 * whether hardware doesn't support NX (so that the early EHCI debug

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L975 * console setup can safely call set_fixmap()).

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L976 */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L977 x86_configure_nx();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L978(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L979 parse_early_param();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L980(blank)

빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L981 if (efi_enabled(EFI_BOOT))

이 조건이 x86-64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L982 efi_memblock_x86_reserve_range();

helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

RISC-V · Linux 6.18.37

a0 hartid, a1 DTB와 SBI firmware contract

entry ABI는 a0에 boot hart id, a1에 DTB physical address를 넘긴다. EFI stub 경로도 가능하지만 일반 platform은 DTB와 SBI를 사용한다. setup_arch()가 FDT memory/CPU/ISA 정보를 읽고 memblock, SATP mode와 paging을 확정한다.

원본 코드: arch/riscv/kernel/setup.c:308-396

308	if (!using_ext)
309		pr_err("Queued spinlock without Zabha or Ziccrse");
310	else
311		pr_info("Queued spinlock %s: enabled\n", using_ext);
312}
313 
314extern void __init init_rt_signal_env(void);
315 
316void __init setup_arch(char **cmdline_p)
317{
318	parse_dtb();
319	setup_initial_init_mm(_stext, _etext, _edata, _end);
320 
321	*cmdline_p = boot_command_line;
322 
323	early_ioremap_setup();
324	sbi_init();
325	jump_label_init();
326	parse_early_param();
327 
328	efi_init();
329	paging_init();
330 
331	/* Parse the ACPI tables for possible boot-time configuration */
332	acpi_boot_table_init();
333 
334	if (acpi_disabled) {
335#if IS_ENABLED(CONFIG_BUILTIN_DTB)
336		unflatten_and_copy_device_tree();
337#else
338		unflatten_device_tree();
339#endif
340	}
341 
342	misc_mem_init();
343 
344	init_resources();
345 
346#ifdef CONFIG_KASAN
347	kasan_init();
348#endif
349 
350#ifdef CONFIG_SMP
351	setup_smp();
352#endif
353 
354	if (!acpi_disabled) {
355		acpi_init_rintc_map();
356		acpi_map_cpus_to_nodes();
357	}
358 
359	riscv_init_cbo_blocksizes();
360	riscv_fill_hwcap();
361	apply_boot_alternatives();
362	init_rt_signal_env();
363 
364	if (IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM) &&
365	    riscv_isa_extension_available(NULL, ZICBOM))
366		riscv_noncoherent_supported();
367	riscv_set_dma_cache_alignment();
368 
369	riscv_user_isa_enable();
370	riscv_spinlock_init();
371 
372	if (!IS_ENABLED(CONFIG_RISCV_ISA_ZBB) || !riscv_isa_extension_available(NULL, ZBB))
373		static_branch_disable(&efficient_ffs_key);
374}
375 
376bool arch_cpu_is_hotpluggable(int cpu)
377{
378	return cpu_has_hotplug(cpu);
379}
380 
381void free_initmem(void)
382{
383	if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) {
384		set_kernel_memory(lm_alias(__init_begin), lm_alias(__init_end), set_memory_rw_nx);
385		if (IS_ENABLED(CONFIG_64BIT))
386			set_kernel_memory(__init_begin, __init_end, set_memory_nx);
387	}
388 
389	free_initmem_default(POISON_FREE_INITMEM);
390}
391 
392static int dump_kernel_offset(struct notifier_block *self,
393			      unsigned long v, void *p)
394{
395	pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n",
396		 kernel_map.virt_offset,

라인 바이 라인 주석

빈 줄과 전처리 경계도 생략하지 않았습니다. 원본의 89개 줄에 각각 설명을 붙였습니다.

L308 if (!using_ext)

이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L309 pr_err("Queued spinlock without Zabha or Ziccrse");

불가능해야 하는 상태 또는 복구 가능한 오류를 외부에 드러내는 줄이다. 직전 register/object 값을 함께 남겨 재현 가능한 failure signature를 만든다.

L310 else

앞 조건이 성립하지 않았을 때의 대체 경로다. fast path와 같은 ownership, ordering과 반환 계약을 제공해야 한다.

L311 pr_info("Queued spinlock %s: enabled\n", using_ext);

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L312}

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L313(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L314extern void __init init_rt_signal_env(void);

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L315(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L316void __init setup_arch(char **cmdline_p)

이 함수의 진입 계약이 시작된다. RISC-V에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.

L317{

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L318 parse_dtb();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L319 setup_initial_init_mm(_stext, _etext, _edata, _end);

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L320(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L321 *cmdline_p = boot_command_line;

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L322(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L323 early_ioremap_setup();

final page table 이전에 firmware table과 MMIO physical range를 임시로 접근할 fixmap 기반을 준비한다.

L324 sbi_init();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L325 jump_label_init();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L326 parse_early_param();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L327(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L328 efi_init();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L329 paging_init();

선택된 Sv39/Sv48/Sv57 mode로 final kernel mapping을 만들고 memory management 다음 단계로 넘긴다.

L330(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L331 /* Parse the ACPI tables for possible boot-time configuration */

Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.

L332 acpi_boot_table_init();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L333(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L334 if (acpi_disabled) {

이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L335#if IS_ENABLED(CONFIG_BUILTIN_DTB)

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L336 unflatten_and_copy_device_tree();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L337#else

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L338 unflatten_device_tree();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L339#endif

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L340 }

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L341(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L342 misc_mem_init();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L343(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L344 init_resources();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L345(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L346#ifdef CONFIG_KASAN

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L347 kasan_init();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L348#endif

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L349(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L350#ifdef CONFIG_SMP

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L351 setup_smp();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L352#endif

Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.

L353(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L354 if (!acpi_disabled) {

이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L355 acpi_init_rintc_map();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L356 acpi_map_cpus_to_nodes();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L357 }

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L358(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L359 riscv_init_cbo_blocksizes();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L360 riscv_fill_hwcap();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L361 apply_boot_alternatives();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L362 init_rt_signal_env();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L363(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L364 if (IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM) &&

이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L365 riscv_isa_extension_available(NULL, ZICBOM))

이 함수의 진입 계약이 시작된다. RISC-V에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.

L366 riscv_noncoherent_supported();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L367 riscv_set_dma_cache_alignment();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L368(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L369 riscv_user_isa_enable();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L370 riscv_spinlock_init();

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L371(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L372 if (!IS_ENABLED(CONFIG_RISCV_ISA_ZBB) || !riscv_isa_extension_available(NULL, ZBB))

이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L373 static_branch_disable(&efficient_ffs_key);

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L374}

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L375(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L376bool arch_cpu_is_hotpluggable(int cpu)

이 함수의 진입 계약이 시작된다. RISC-V에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.

L377{

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L378 return cpu_has_hotplug(cpu);

이 함수가 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 단계의 결과 또는 오류를 상위 계층에 전달한다. 반환 전에 lock, interrupt state, reference와 hardware active state가 정리됐는지 확인한다.

L379}

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L380(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L381void free_initmem(void)

이 함수의 진입 계약이 시작된다. RISC-V에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.

L382{

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L383 if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) {

이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L384 set_kernel_memory(lm_alias(__init_begin), lm_alias(__init_end), set_memory_rw_nx);

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L385 if (IS_ENABLED(CONFIG_64BIT))

이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.

L386 set_kernel_memory(__init_begin, __init_end, set_memory_nx);

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L387 }

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L388(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L389 free_initmem_default(POISON_FREE_INITMEM);

helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.

L390}

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L391(blank)

빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.

L392static int dump_kernel_offset(struct notifier_block *self,

이 줄이 RISC-V의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.

L393 unsigned long v, void *p)

이 줄이 RISC-V의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.

L394{

C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.

L395 pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n",

이 줄이 RISC-V의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.

L396 kernel_map.virt_offset,

이 줄이 RISC-V의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.

05 · WORKED EXAMPLE

숫자로 검산하기

01

1GiB RAM에서 early ownership ledger 만들기

RAM 0x80000000-0xbfffffff, kernel 32MiB at 0x80200000, DTB 256KiB at 0x88000000, initrd 64MiB at 0x90000000이라고 가정한다.

  1. RAMmemblock.memory에 전체 0x40000000 bytes를 넣되 firmware reserved range를 먼저 제외한다.
  2. kernel0x80200000-0x821fffff를 reserve해 allocator가 실행 중인 image를 덮지 못하게 한다.
  3. DTB/initrdDTB 0x88000000-0x8803ffff와 initrd 0x90000000-0x93ffffff를 parse/사용 완료까지 reserve한다.
  4. handofffree usable RAM만 buddy allocator에 넘기고 DTB copy나 initrd unpack이 끝난 시점에 각각 reclaim 여부를 결정한다.

결론부팅 주소 그림은 위치만 보여주면 부족하다. 각 범위의 현재 owner, 접근 주소 종류와 해제 조건을 함께 표시해야 한다.

06 · DEEP DIVE

경계별 상세 분석

01

공통 kernel core와 architecture hook의 경계

architecture entry가 최소 MMU/stack을 준비하고 boot parameter를 보존한 뒤 setup_arch()가 memory map, command line, CPU, interrupt/timer와 firmware tables를 검증한다. 결과는 memblock reservations와 generic kernel subsystem 초기화의 입력이 된다.

firmware-owned memory, bootloader temporary data, kernel image/initrd/DTB, reserved-memory와 일반 RAM을 구분한다. early mapping이 없는 physical pointer를 일반 C pointer처럼 dereference하면 안 된다.

02

arm64: Image header entry, x0 DTB와 EFI stub/ACPI 선택

boot protocol은 x0에 DTB physical address를 넘기고 MMU off, cache 조건을 규정한다. EFI stub을 거치면 EFI memory map과 system table도 보존한다. setup_arch()가 early FDT를 scan하고 memblock, ACPI 여부와 CPU topology를 확정한다.

DTB와 initrd를 memblock reserve한 뒤 memory limit/nomap을 적용하고 page table을 확장한다. EFI memory map exit 시점과 runtime mapping도 순서를 가진다. 디버깅할 때는 x0 DTB PA, Image load PA/size, memblock memory/reserved, EFI descriptor, ACPI RSDP와 initrd start/end를 확인한다.

03

x86-64: boot_params zero page, BIOS/e820 또는 EFI와 ACPI

boot protocol의 boot_params에 e820 memory map, command line, initrd와 framebuffer 정보가 들어온다. EFI boot path는 EFI memory map을 병합하고 setup_arch()가 e820을 sanitize해 memblock에 반영하며 ACPI/SMBIOS를 찾는다.

real-mode/early identity mapping에서 받은 physical pointer를 reserve하고 e820 type 충돌을 정리한 뒤 direct map을 만든다. KASLR relocation도 reserved range와 함께 계산한다. 디버깅할 때는 boot_params PA, e820 raw/sanitized map, setup_data, initrd, EFI descriptors, ACPI RSDP, KASLR physical/virtual offset을 본다.

04

RISC-V: a0 hartid, a1 DTB와 SBI firmware contract

entry ABI는 a0에 boot hart id, a1에 DTB physical address를 넘긴다. EFI stub 경로도 가능하지만 일반 platform은 DTB와 SBI를 사용한다. setup_arch()가 FDT memory/CPU/ISA 정보를 읽고 memblock, SATP mode와 paging을 확정한다.

DTB를 early mapping으로 읽고 kernel/initrd/reserved-memory를 reserve한 뒤 final page table과 fixmap을 전환한다. SBI extension probe는 timer, IPI, RFENCE와 reset backend 선택에 영향을 준다. 디버깅할 때는 a0/a1, boot_cpu_hartid, DTB totalsize, memblock ranges, SATP.MODE/root PPN, SBI spec/extensions와 initrd를 확인한다.

05

객체 수명과 소유권을 먼저 고정한다

DTB, EFI map, ACPI tables와 initrd는 parse와 필요한 copy가 끝날 때까지 memblock에서 reserve해야 한다. reclaimable firmware memory는 해당 consumer가 완료된 뒤에만 buddy allocator로 넘긴다.

주소나 register 값이 맞는지만 확인하면 stale state를 놓친다. producer, publication, consumer와 폐기 지점을 같은 표에 기록한다.

06

latency upper bound는 hardware instruction 하나가 아니다

boot latency는 firmware enumeration, decompression, page-table construction, ACPI/DT parse와 secondary CPU bring-up으로 나뉜다. 오류 분석에는 timestamp보다 마지막 유효 memory ownership 변화가 중요하다.

평균값 외에 interrupt-off 구간, remote CPU 응답, firmware 호출과 retry 횟수를 분리해야 최악 지연의 원인을 찾을 수 있다.

07 · FAILURE

실패를 어떤 증거로 나눌 것인가

분류관찰되는 결과첫 확인값
arm64DTB 8-byte alignment/크기, RAM 밖 위치, initrd overlap 또는 reserved-memory 누락은 early abort와 allocator overwrite를 만든다.x0 DTB PA, Image load PA/size, memblock memory/reserved, EFI descriptor, ACPI RSDP와 initrd start/end를 확인한다.
x86-64truncated boot_params, 겹친 e820 entry, initrd가 low/high limit 밖에 있거나 setup_data chain loop가 있으면 RAM 오인과 overwrite가 발생한다.boot_params PA, e820 raw/sanitized map, setup_data, initrd, EFI descriptors, ACPI RSDP, KASLR physical/virtual offset을 본다.
RISC-Vboot hart mismatch, DTB의 hart mapping/ISA string 오류, unsupported SATP mode 또는 SBI version 차이는 secondary hart, timer와 MMU 초기화 실패를 만든다.a0/a1, boot_cpu_hartid, DTB totalsize, memblock ranges, SATP.MODE/root PPN, SBI spec/extensions와 initrd를 확인한다.

08 · LAB

재현과 계측 절차

  1. earlycon과 memblock=debug로 firmware map 입력부터 최종 reserved ledger까지 architecture별 로그를 비교한다.
  2. DTB/initrd를 의도적으로 kernel과 겹치게 배치해 boot protocol과 early validation이 어느 단계에서 거부하는지 확인한다.
  3. 동일한 workload에서 세 architecture의 tracepoint 이름, CPU 번호, PC, stack pointer와 address-space identifier를 같은 열로 기록한다.
  4. 소스만 읽고 끝내지 않고 최종 vmlinuxobjdump -dr, readelf -SW 결과로 선택된 alternative와 section 배치를 확인한다.

09 · REFERENCES

원문 좌표

Linux kernel source: GPL-2.0-only. 이 글의 코드 발췌는 Linux v6.18.37 원문을 기준으로 하며, 분석 문장은 해당 코드의 실행 조건과 상태 경계를 설명합니다.