# 부트 정보를 ARM64 커널의 주소와 장치 구조로 바꿉니다

v6.18.37 / arch/arm64/kernel/setup.c

부트로더가 넘긴 주소와 장치 설명은 그대로 모든 커널 기능이 사용할 수 있는 객체가 아닙니다. setup_arch는 초기 매핑, FDT 또는 ACPI, 메모리 영역과 CPU 정보를 차례로 연결합니다. 특히 임시 idmap을 제거하는 시점은 이후 실행이 정식 매핑으로 가능한지와 연결됩니다.

## setup_arch

```c

void __init __no_sanitize_address setup_arch(char **cmdline_p)
{
	setup_initial_init_mm(_text, _etext, _edata, _end);

	*cmdline_p = boot_command_line;

	kaslr_init();

	early_fixmap_init();
	early_ioremap_init();

	setup_machine_fdt(__fdt_pointer);

	/*
	 * Initialise the static keys early as they may be enabled by the
	 * cpufeature code and early parameters.
	 */
	jump_label_init();
	parse_early_param();

	dynamic_scs_init();

	/*
	 * The primary CPU enters the kernel with all DAIF exceptions masked.
	 *
	 * We must unmask Debug and SError before preemption or scheduling is
	 * possible to ensure that these are consistently unmasked across
	 * threads, and we want to unmask SError as soon as possible after
	 * initializing earlycon so that we can report any SErrors immediately.
	 *
	 * IRQ and FIQ will be unmasked after the root irqchip has been
	 * detected and initialized.
	 */
	local_daif_restore(DAIF_PROCCTX_NOIRQ);

	/*
	 * TTBR0 is only used for the identity mapping at this stage. Make it
	 * point to zero page to avoid speculatively fetching new entries.
	 */
	cpu_uninstall_idmap();

	xen_early_init();
	efi_init();

	if (!efi_enabled(EFI_BOOT)) {
		if ((u64)_text % MIN_KIMG_ALIGN)
			pr_warn(FW_BUG "Kernel image misaligned at boot, please fix your bootloader!");
		WARN_TAINT(mmu_enabled_at_boot, TAINT_FIRMWARE_WORKAROUND,
			   FW_BUG "Booted with MMU enabled!");
	}

	arm64_memblock_init();

	paging_init();

	acpi_table_upgrade();

	/* Parse the ACPI tables for possible boot-time configuration */
	acpi_boot_table_init();

	if (acpi_disabled)
		unflatten_device_tree();

	bootmem_init();

	kasan_init();

	request_standard_resources();

	early_ioremap_reset();

	if (acpi_disabled)
		psci_dt_init();
	else
		psci_acpi_init();

	arm64_rsi_init();

	init_bootcpu_ops();
	smp_init_cpus();
	smp_build_mpidr_hash();

#ifdef CONFIG_ARM64_SW_TTBR0_PAN
	/*
	 * Make sure init_thread_info.ttbr0 always generates translation
	 * faults in case uaccess_enable() is inadvertently called by the init
	 * thread.
	 */
	init_task.thread_info.ttbr0 = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
#endif

	if (boot_args[1] || boot_args[2] || boot_args[3]) {
		pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n"
			"\tx1: %016llx\n\tx2: %016llx\n\tx3: %016llx\n"
			"This indicates a broken bootloader or old kernel\n",
			boot_args[1], boot_args[2], boot_args[3]);
	}
}

```

### 281행

```c

void __init __no_sanitize_address setup_arch(char **cmdline_p)

```

arm64 플랫폼과 메모리 기반을 부팅 중 준비하는 함수입니다. __init은 초기화 코드 분류, __no_sanitize_address는 이 함수의 주소 검사 계측 제외를 나타냅니다. char **를 통해 호출자의 명령줄 포인터를 돌려줍니다.

### 283행

```c

	setup_initial_init_mm(_text, _etext, _edata, _end);

```

초기 커널 mm에 코드·데이터·이미지 끝 주소를 기록합니다.

### 285행

```c

	*cmdline_p = boot_command_line;

```

호출자에게 부트 명령줄 포인터를 돌려줍니다. char **를 통해 호출자의 포인터 값을 변경합니다.

### 287행

```c

	kaslr_init();

```

커널 주소 무작위화 관련 초기 상태를 정리합니다.

### 289행

```c

	early_fixmap_init();

```

부트 정보와 하드웨어에 접근할 초기 고정 매핑 체계를 준비합니다.

### 290행

```c

	early_ioremap_init();

```

부팅 중 물리 영역을 임시로 매핑하여 읽는 기반을 준비합니다.

### 292행

```c

	setup_machine_fdt(__fdt_pointer);

```

부트로더의 평탄한 장치 트리 주소를 해석하여 플랫폼 정보를 준비합니다.

### 298행

```c

	jump_label_init();

```

static branch에 필요한 패치 정보를 초기화합니다. 조건마다 일반 분기를 계속 실행하지 않도록 코드를 선택할 기반입니다.

### 299행

```c

	parse_early_param();

```

일반 인자 처리보다 먼저 효과가 필요한 early parameter를 해석합니다.

### 301행

```c

	dynamic_scs_init();

```

구성에 맞춰 동적 shadow call stack 관련 코드 처리를 준비합니다.

### 314행

```c

	local_daif_restore(DAIF_PROCCTX_NOIRQ);

```

프로세스 문맥에서 IRQ를 허용하지 않는 DAIF 상태를 적용합니다. 디버그·SError·IRQ·FIQ의 마스크를 정의된 조합으로 바꾸는 것이며, 일반 IRQ를 지금 활성화하는 호출이 아닙니다.

### 320행

```c

	cpu_uninstall_idmap();

```

부팅 전환에 사용한 identity mapping 상태를 정리합니다. 이후 정식 커널 매핑으로 실행 가능해야 합니다.

### 322행

```c

	xen_early_init();

```

Xen 실행 환경에서 필요한 이른 가상화 상태를 준비합니다.

### 323행

```c

	efi_init();

```

EFI가 전달한 시스템 테이블과 메모리 정보를 초기화합니다.

### 325행

```c

	if (!efi_enabled(EFI_BOOT)) {

```

EFI로 부팅하지 않은 경우에 적용할 ARM64 부트 규약 검사를 시작합니다.

### 326행

```c

		if ((u64)_text % MIN_KIMG_ALIGN)

```

커널 이미지 시작 주소가 요구한 정렬 단위의 배수인지 나머지 연산으로 확인합니다.

### 327행

```c

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

```

부트로더가 커널 이미지를 요구한 경계에 맞추지 않았음을 경고합니다. 주소를 이 자리에서 다시 정렬하는 동작은 없으므로 부트로더 배치를 수정해야 한다는 진단입니다.

### 328행

```c

		WARN_TAINT(mmu_enabled_at_boot, TAINT_FIRMWARE_WORKAROUND,

```

비EFI 부팅에서 부트 시 MMU가 켜져 있었다면 경고하고 펌웨어 우회와 관련된 taint를 기록합니다. 바로 위 이미지 정렬 검사와 별개의 부트 규약 검사입니다.

### 329행

```c

			   FW_BUG "Booted with MMU enabled!");

```

앞줄 WARN_TAINT에 전달할 진단 문구입니다. 현재 paging_init이 완료되었는지를 말하는 것이 아니라 부트로더가 넘긴 최초 MMU 상태를 지적합니다.

### 332행

```c

	arm64_memblock_init();

```

ARM64가 사용할 초기 물리 메모리 범위와 예약 영역을 memblock에 정리합니다.

### 334행

```c

	paging_init();

```

커널이 지속적으로 사용할 페이지 테이블과 메모리 매핑을 준비합니다.

### 336행

```c

	acpi_table_upgrade();

```

제공된 ACPI 테이블 교체 정보가 있으면 반영합니다.

### 339행

```c

	acpi_boot_table_init();

```

부팅에 필요한 ACPI 테이블 해석 기반을 준비합니다.

### 341행

```c

	if (acpi_disabled)

```

ACPI를 사용하지 않는 구성을 검사하여 DT 기반의 대체 경로를 선택합니다.

### 342행

```c

		unflatten_device_tree();

```

평탄한 FDT 바이트 구조를 커널의 device_node 구조로 만듭니다.

### 344행

```c

	bootmem_init();

```

초기 메모리 구역과 페이지 관리의 아키텍처별 초기화를 수행합니다.

### 346행

```c

	kasan_init();

```

KASAN(Kernel Address Sanitizer)은 범위를 벗어난 메모리 접근과 해제 후 사용을 찾아내는 검사 기능입니다. arm64의 이 호출은 Generic·Software Tags 모드에서 실제 메모리를 설명할 shadow 영역과 검사 상태를 준비합니다. Hardware Tags 모드만 쓰거나 해당 소프트웨어 모드가 없으면 이 함수는 빈 구현이며 태그 모드의 추가 준비도 별도 경로에 있습니다.

### 348행

```c

	request_standard_resources();

```

커널 이미지 등 표준 메모리 영역을 자원 관리 체계에 등록합니다.

### 350행

```c

	early_ioremap_reset();

```

초기 임시 매핑 단계의 상태를 정리합니다.

### 352행

```c

	if (acpi_disabled)

```

ACPI를 사용하지 않는 구성을 검사하여 DT 기반의 대체 경로를 선택합니다.

### 353행

```c

		psci_dt_init();

```

DT가 기술한 PSCI 펌웨어 호출 방식을 연결합니다.

### 354행

```c

	else

```

앞 조건이 성립하지 않은 경로를 선택합니다. 앞쪽 처리와 아래 처리를 모두 수행하는 것이 아닙니다.

### 355행

```c

		psci_acpi_init();

```

ACPI 정보에서 PSCI 펌웨어 호출 방식을 연결합니다.

### 357행

```c

	arm64_rsi_init();

```

지원 구성에서 Realm Services Interface 관련 상태를 준비합니다. 호출 존재만으로 모든 플랫폼이 Realm이라는 뜻은 아닙니다.

### 359행

```c

	init_bootcpu_ops();

```

부트 CPU와 관련된 CPU 동작 함수를 준비합니다.

### 360행

```c

	smp_init_cpus();

```

플랫폼에 있는 CPU들을 열거하고 SMP 관리 정보에 반영합니다.

### 361행

```c

	smp_build_mpidr_hash();

```

CPU 하드웨어 식별자로 CPU별 저장 상태를 찾을 수 있도록 해시 구성을 준비합니다.

### 363행

```c

#ifdef CONFIG_ARM64_SW_TTBR0_PAN

```

PAN(Privileged Access Never)을 TTBR0 전환으로 구현하여 커널의 무분별한 사용자 메모리 접근을 막는 구성입니다. 정상 사용자 접근 함수가 잠시 올바른 TTBR0를 복원하며, 여기서는 초기 태스크에 사용할 예약 테이블 값을 저장합니다. 이 선택은 전처리 단계에서 이루어지며, CPU가 실행 중 이 줄의 조건을 검사하지 않습니다.

### 369행

```c

	init_task.thread_info.ttbr0 = phys_to_ttbr(__pa_symbol(reserved_pg_dir));

```

소프트웨어 PAN 경로에서 사용할 예약 페이지 테이블의 물리 주소를 TTBR 형식으로 바꿔 초기 태스크에 저장합니다.

### 370행

```c

#endif

```

소프트웨어 PAN용 초기 TTBR0 값을 기록하는 구간을 마칩니다. 다음 부트 인자 검사는 이 PAN 설정과 별개의 공통 진단입니다.

### 372행

```c

	if (boot_args[1] || boot_args[2] || boot_args[3]) {

```

부트 규약상 0이어야 할 x1–x3 인자가 남아 있는지 검사합니다.

### 373행

```c

		pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n"

```

커널 진입 시 0이어야 하는 x1–x3에 값이 남아 부트 규약을 어겼음을 보고하기 시작합니다. 보존해 둔 boot_args를 사용하므로 현재 레지스터 내용을 새로 읽는 출력이 아닙니다. 로그 출력 자체가 오류 상태를 복구하지는 않으며, 실제 중단·복구 처리는 뒤의 코드가 담당합니다.

### 374행

```c

			"\tx1: %016llx\n\tx2: %016llx\n\tx3: %016llx\n"

```

각 부트 인자 값을 16자리 16진수로 보여 주는 형식 문자열입니다. 어느 인자가 규약을 어겼는지 실제 비트 패턴을 확인할 수 있게 합니다. 앞줄에서 시작한 호출이나 식에 이어지는 부분이므로, 이 줄만으로 별도의 함수 호출이 생기지는 않습니다.

### 375행

```c

			"This indicates a broken bootloader or old kernel\n",

```

진단 메시지에 가능한 전달 경로의 문제를 안내합니다. 이 문자열 출력이 부트로더의 구체적인 고장 원인을 자동 판정하는 것은 아닙니다. 앞줄에서 시작한 호출이나 식에 이어지는 부분이므로, 이 줄만으로 별도의 함수 호출이 생기지는 않습니다.

### 376행

```c

			boot_args[1], boot_args[2], boot_args[3]);

```

초기 진입에서 저장한 x1·x2·x3 값을 순서대로 로그에 전달합니다. 첫 DTB 인자 x0는 이 0 검사 대상과 구분됩니다. 앞줄에서 시작한 호출이나 식에 이어지는 부분이므로, 이 줄만으로 별도의 함수 호출이 생기지는 않습니다.

