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하면 안 된다.
02 · CONTRACT
공통 계약과 architecture 구현
| architecture | 핵심 mechanism | 실패 형태 | 확인할 상태 |
|---|---|---|---|
| arm64 | Image 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-64 | boot_params zero page, BIOS/e820 또는 EFI와 ACPI | truncated 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-V | a0 hartid, a1 DTB와 SBI firmware contract | boot 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
세 그림으로 먼저 읽기
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를 확인한다.
setup_arch()가 memory map, command line, CPU, interrupt/timer와 firmware tables를 검증한다. 결과는 memblock reservations와 generic kernel subsystem 초기화의 입력이 된다.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개 줄에 각각 설명을 붙였습니다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };계산한 pointer, flag, register image 또는 generation을 다음 단계가 읽을 위치에 저장한다. 값의 단위, address space와 publication ordering을 확인한다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
u64 cpu_logical_map(unsigned int cpu)이 함수의 진입 계약이 시작된다. arm64에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.
{C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
return __cpu_logical_map[cpu];이 함수가 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 단계의 결과 또는 오류를 상위 계층에 전달한다. 반환 전에 lock, interrupt state, reference와 hardware active state가 정리됐는지 확인한다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
void __init __no_sanitize_address setup_arch(char **cmdline_p)이 함수의 진입 계약이 시작된다. arm64에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.
{C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
setup_initial_init_mm(_text, _etext, _edata, _end);helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
*cmdline_p = boot_command_line;Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
kaslr_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
early_fixmap_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
early_ioremap_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
setup_machine_fdt(__fdt_pointer);entry에서 보존한 DTB physical pointer를 검증하고 machine model, chosen, memory 정보를 early parse한다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* Initialise the static keys early as they may be enabled by theLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* cpufeature code and early parameters.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
jump_label_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
parse_early_param();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
dynamic_scs_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* The primary CPU enters the kernel with all DAIF exceptions masked.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* We must unmask Debug and SError before preemption or scheduling isLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* possible to ensure that these are consistently unmasked acrossLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* threads, and we want to unmask SError as soon as possible afterLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* initializing earlycon so that we can report any SErrors immediately.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* IRQ and FIQ will be unmasked after the root irqchip has beenLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* detected and initialized.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
local_daif_restore(DAIF_PROCCTX_NOIRQ);helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* TTBR0 is only used for the identity mapping at this stage. Make itLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* point to zero page to avoid speculatively fetching new entries.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
cpu_uninstall_idmap();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
xen_early_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
efi_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
if (!efi_enabled(EFI_BOOT)) {이 조건이 arm64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
if ((u64)_text % MIN_KIMG_ALIGN)이 조건이 arm64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
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를 연결해 본다.
WARN_TAINT(mmu_enabled_at_boot, TAINT_FIRMWARE_WORKAROUND,불가능해야 하는 상태 또는 복구 가능한 오류를 외부에 드러내는 줄이다. 직전 register/object 값을 함께 남겨 재현 가능한 failure signature를 만든다.
FW_BUG "Booted with MMU enabled!");이 줄이 arm64의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
arm64_memblock_init();RAM range에서 kernel, DTB, initrd와 reserved-memory를 제외해 early physical allocator의 소유권을 확정한다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
paging_init();최종 kernel linear mapping과 page-table hierarchy를 구성해 이후 일반 virtual memory 초기화 기반을 만든다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
acpi_table_upgrade();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/* Parse the ACPI tables for possible boot-time configuration */Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
acpi_boot_table_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
if (acpi_disabled)이 조건이 arm64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
unflatten_device_tree();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
bootmem_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
kasan_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
request_standard_resources();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
early_ioremap_reset();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
if (acpi_disabled)이 조건이 arm64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
psci_dt_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
else앞 조건이 성립하지 않았을 때의 대체 경로다. fast path와 같은 ownership, ordering과 반환 계약을 제공해야 한다.
psci_acpi_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
arm64_rsi_init();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
init_bootcpu_ops();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
smp_init_cpus();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
smp_build_mpidr_hash();helper 또는 architecture operation을 실행한다. arm64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 arm64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
#ifdef CONFIG_ARM64_SW_TTBR0_PANKconfig와 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개 줄에 각각 설명을 붙였습니다.
* systems (with a traditional BIOS) as well as on EFI systems.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* setup_arch - architecture-specific boot-time initializationsLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* Note: On x86_64, fixmaps are ready for use even before this is called.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
void __init setup_arch(char **cmdline_p)이 함수의 진입 계약이 시작된다. x86-64에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.
{C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
#ifdef CONFIG_X86_32Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
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를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* copy kernel address range established so far and switchLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* to the proper swapper page tableLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
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를 분리해 해석한다.
initial_page_table + KERNEL_PGD_BOUNDARY,이 줄이 x86-64의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.
KERNEL_PGD_PTRS);이 줄이 x86-64의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
load_cr3(swapper_pg_dir);helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* Note: Quark X1000 CPUs advertise PGE incorrectly and requireLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* a cr3 based tlb flush, so the following __flush_tlb_all()Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* will not flush anything because the CPU quirk which clearsLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* X86_FEATURE_PGE has not been invoked yet. Though due to theLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* load_cr3() above the TLB has been flushed already. TheLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* quirk is invoked before subsequent calls to __flush_tlb_all()Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* so proper operation is guaranteed.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
__flush_tlb_all();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
#elseKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
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를 연결해 본다.
boot_cpu_data.x86_phys_bits = MAX_PHYSMEM_BITS;계산한 pointer, flag, register image 또는 generation을 다음 단계가 읽을 위치에 저장한다. 값의 단위, address space와 publication ordering을 확인한다.
#endifKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
#ifdef CONFIG_CMDLINE_BOOLKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
#ifdef CONFIG_CMDLINE_OVERRIDEKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
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를 연결해 본다.
#elseKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
if (builtin_cmdline[0]) {이 조건이 x86-64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
/* append boot loader cmdline to builtin */Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
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를 연결해 본다.
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를 연결해 본다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
#endifKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
builtin_cmdline_added = true;계산한 pointer, flag, register image 또는 generation을 다음 단계가 읽을 위치에 저장한다. 값의 단위, address space와 publication ordering을 확인한다.
#endifKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
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를 연결해 본다.
*cmdline_p = command_line;Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* If we have OLPC OFW, we might end up relocating the fixmap due toLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* reserve_top(), so do this before touching the ioremap area.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
olpc_ofw_detect();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
idt_setup_early_traps();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
early_cpu_init();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
jump_label_init();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
static_call_init();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
early_ioremap_init();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
setup_olpc_ofw_pgd();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
parse_boot_params();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
x86_init.oem.arch_setup();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* Do some memory reservations *before* memory is added to memblock, soLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* memblock allocations won't overwrite it.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* After this point, everything still needed from the boot loader orLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* firmware or kernel text should be early reserved or marked not RAM inLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* e820. All other memory is free game.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* This call needs to happen before e820__memory_setup() which calls theLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* xen_memory_setup() on Xen dom0 which relies on the fact that thoseLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* early reservations have happened already.Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
early_reserve_memory();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1;계산한 pointer, flag, register image 또는 generation을 다음 단계가 읽을 위치에 저장한다. 값의 단위, address space와 publication ordering을 확인한다.
e820__memory_setup();firmware/bootloader memory map을 정리해 usable RAM과 reserved type의 기준을 만든다.
parse_setup_data();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
copy_edd();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
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를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/*Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* x86_configure_nx() is called before parse_early_param() to detectLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* whether hardware doesn't support NX (so that the early EHCI debugLinux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
* console setup can safely call set_fixmap()).Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
*/Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
x86_configure_nx();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
parse_early_param();helper 또는 architecture operation을 실행한다. x86-64에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 x86-64 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
if (efi_enabled(EFI_BOOT))이 조건이 x86-64 fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
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개 줄에 각각 설명을 붙였습니다.
if (!using_ext)이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
pr_err("Queued spinlock without Zabha or Ziccrse");불가능해야 하는 상태 또는 복구 가능한 오류를 외부에 드러내는 줄이다. 직전 register/object 값을 함께 남겨 재현 가능한 failure signature를 만든다.
else앞 조건이 성립하지 않았을 때의 대체 경로다. fast path와 같은 ownership, ordering과 반환 계약을 제공해야 한다.
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를 연결해 본다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
extern void __init init_rt_signal_env(void);helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
void __init setup_arch(char **cmdline_p)이 함수의 진입 계약이 시작된다. RISC-V에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.
{C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
parse_dtb();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
setup_initial_init_mm(_stext, _etext, _edata, _end);helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
*cmdline_p = boot_command_line;Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
early_ioremap_setup();final page table 이전에 firmware table과 MMIO physical range를 임시로 접근할 fixmap 기반을 준비한다.
sbi_init();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
jump_label_init();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
parse_early_param();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
efi_init();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
paging_init();선택된 Sv39/Sv48/Sv57 mode로 final kernel mapping을 만들고 memory management 다음 단계로 넘긴다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
/* Parse the ACPI tables for possible boot-time configuration */Linux 원본 주석이다. 바로 아래 코드의 호출 조건, hardware 제약 또는 예외 처리를 설명하므로 실행 줄과 함께 읽는다.
acpi_boot_table_init();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
if (acpi_disabled) {이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
#if IS_ENABLED(CONFIG_BUILTIN_DTB)Kconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
unflatten_and_copy_device_tree();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
#elseKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
unflatten_device_tree();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
#endifKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
misc_mem_init();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
init_resources();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
#ifdef CONFIG_KASANKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
kasan_init();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
#endifKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
#ifdef CONFIG_SMPKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
setup_smp();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
#endifKconfig와 compiler feature에 따라 최종 object에 남는 경로가 달라지는 전처리 경계다. 대상 .config와 disassembly로 실제 선택을 확인한다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
if (!acpi_disabled) {이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
acpi_init_rintc_map();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
acpi_map_cpus_to_nodes();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
riscv_init_cbo_blocksizes();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
riscv_fill_hwcap();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
apply_boot_alternatives();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
init_rt_signal_env();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
if (IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM) &&이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
riscv_isa_extension_available(NULL, ZICBOM))이 함수의 진입 계약이 시작된다. RISC-V에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.
riscv_noncoherent_supported();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
riscv_set_dma_cache_alignment();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
riscv_user_isa_enable();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
riscv_spinlock_init();helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
if (!IS_ENABLED(CONFIG_RISCV_ISA_ZBB) || !riscv_isa_extension_available(NULL, ZBB))이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
static_branch_disable(&efficient_ffs_key);helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
bool arch_cpu_is_hotpluggable(int cpu)이 함수의 진입 계약이 시작된다. RISC-V에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.
{C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
return cpu_has_hotplug(cpu);이 함수가 Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 단계의 결과 또는 오류를 상위 계층에 전달한다. 반환 전에 lock, interrupt state, reference와 hardware active state가 정리됐는지 확인한다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
void free_initmem(void)이 함수의 진입 계약이 시작된다. RISC-V에서 caller context, argument ownership과 반환 시 보장할 architecture state를 먼저 적는다.
{C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) {이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
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를 연결해 본다.
if (IS_ENABLED(CONFIG_64BIT))이 조건이 RISC-V fast path와 fallback/error path를 가른다. 조건에 쓰인 flag가 어느 CPU 또는 object의 상태인지, 동시에 바뀔 수 있는지 확인한다.
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를 연결해 본다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
free_initmem_default(POISON_FREE_INITMEM);helper 또는 architecture operation을 실행한다. RISC-V에서 이 호출이 register write, cache/TLB operation, callback 또는 object lifetime 중 무엇을 바꾸는지 call site와 callee를 연결해 본다.
}C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
(blank)빈 줄은 RISC-V Boot firmware handoff: DTB, ACPI, EFI와 setup_arch 경로에서 한 상태 묶음이 끝나는 위치다. 위쪽에서 만든 값이 아래쪽에서 소비되는지 구간을 나눠 읽는다.
static int dump_kernel_offset(struct notifier_block *self,이 줄이 RISC-V의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.
unsigned long v, void *p)이 줄이 RISC-V의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.
{C block의 시작 또는 끝이다. lock, RCU, preemption과 interrupt-disabled 범위를 이 중괄호 바깥 호출까지 넘겨 추정하지 않는다.
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를 분리해 해석한다.
kernel_map.virt_offset,이 줄이 RISC-V의 현재 상태에서 읽는 register와 memory, 그리고 다음 줄에 남기는 값을 적는다. Boot firmware handoff: DTB, ACPI, EFI와 setup_arch의 공통 kernel 계약과 architecture 전용 side effect를 분리해 해석한다.
05 · WORKED EXAMPLE
숫자로 검산하기
1GiB RAM에서 early ownership ledger 만들기
RAM 0x80000000-0xbfffffff, kernel 32MiB at 0x80200000, DTB 256KiB at 0x88000000, initrd 64MiB at 0x90000000이라고 가정한다.
- RAMmemblock.memory에 전체 0x40000000 bytes를 넣되 firmware reserved range를 먼저 제외한다.
- kernel0x80200000-0x821fffff를 reserve해 allocator가 실행 중인 image를 덮지 못하게 한다.
- DTB/initrdDTB 0x88000000-0x8803ffff와 initrd 0x90000000-0x93ffffff를 parse/사용 완료까지 reserve한다.
- handofffree usable RAM만 buddy allocator에 넘기고 DTB copy나 initrd unpack이 끝난 시점에 각각 reclaim 여부를 결정한다.
결론부팅 주소 그림은 위치만 보여주면 부족하다. 각 범위의 현재 owner, 접근 주소 종류와 해제 조건을 함께 표시해야 한다.
06 · DEEP DIVE
경계별 상세 분석
공통 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하면 안 된다.
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를 확인한다.
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을 본다.
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를 확인한다.
객체 수명과 소유권을 먼저 고정한다
DTB, EFI map, ACPI tables와 initrd는 parse와 필요한 copy가 끝날 때까지 memblock에서 reserve해야 한다. reclaimable firmware memory는 해당 consumer가 완료된 뒤에만 buddy allocator로 넘긴다.
주소나 register 값이 맞는지만 확인하면 stale state를 놓친다. producer, publication, consumer와 폐기 지점을 같은 표에 기록한다.
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
실패를 어떤 증거로 나눌 것인가
| 분류 | 관찰되는 결과 | 첫 확인값 |
|---|---|---|
| arm64 | 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-64 | truncated 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-V | boot 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
재현과 계측 절차
- earlycon과 memblock=debug로 firmware map 입력부터 최종 reserved ledger까지 architecture별 로그를 비교한다.
- DTB/initrd를 의도적으로 kernel과 겹치게 배치해 boot protocol과 early validation이 어느 단계에서 거부하는지 확인한다.
- 동일한 workload에서 세 architecture의 tracepoint 이름, CPU 번호, PC, stack pointer와 address-space identifier를 같은 열로 기록한다.
- 소스만 읽고 끝내지 않고 최종
vmlinux의objdump -dr,readelf -SW결과로 선택된 alternative와 section 배치를 확인한다.
09 · REFERENCES
원문 좌표
- arm64arch/arm64/kernel/setup.c:273-363
- x86-64arch/x86/kernel/setup.c:878-982
- RISC-Varch/riscv/kernel/setup.c:308-396
Linux kernel source: GPL-2.0-only. 이 글의 코드 발췌는 Linux v6.18.37 원문을 기준으로 하며, 분석 문장은 해당 코드의 실행 조건과 상태 경계를 설명합니다.