# Boot firmware handoff: DTB, ACPI, EFI와 setup_arch

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

커널이 처음 실행될 때에는 장치와 사용 가능한 RAM을 아직 모릅니다. 펌웨어와 부트로더가 준 정보를 실제로 읽을 수 있는 주소에 연결해야 합니다. arm64는 DTB 또는 ACPI를, x86은 boot_params·메모리 지도·ACPI 등을, RISC-V는 DTB 및 SBI 환경 등을 이용합니다. 여기서는 arm64 DTB 초기 처리 함수를 대표로 읽습니다.

## setup_machine_fdt

```c

static void __init setup_machine_fdt(phys_addr_t dt_phys)
{
	int size = 0;
	void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
	const char *name;

	if (dt_virt)
		memblock_reserve(dt_phys, size);

	/*
	 * dt_virt is a fixmap address, hence __pa(dt_virt) can't be used.
	 * Pass dt_phys directly.
	 */
	if (!early_init_dt_scan(dt_virt, dt_phys)) {
		pr_crit("\n"
			"Error: invalid device tree blob: PA=%pa, VA=%px, size=%d bytes\n"
			"The dtb must be 8-byte aligned and must not exceed 2 MB in size.\n"
			"\nPlease check your bootloader.\n",
			&dt_phys, dt_virt, size);

		/*
		 * Note that in this _really_ early stage we cannot even BUG()
		 * or oops, so the least terrible thing to do is cpu_relax(),
		 * or else we could end-up printing non-initialized data, etc.
		 */
		while (true)
			cpu_relax();
	}

	/* Early fixups are done, map the FDT as read-only now */
	fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);

	name = of_flat_dt_get_machine_name();
	if (!name)
		return;

	pr_info("Machine model: %s\n", name);
	dump_stack_set_arch_desc("%s (DT)", name);
}

```

### 170행

```c

static void __init setup_machine_fdt(phys_addr_t dt_phys)

```

부트로더가 전달한 DTB 물리 주소를 받아 초기 매핑과 구조 해석을 준비합니다. __init 코드는 부팅 후 회수 가능한 영역에 놓입니다.

### 172행

```c

	int size = 0;

```

DTB 크기의 출력값을 받을 변수를 0으로 준비합니다. 처음부터 크기를 알고 있다고 가정하지 않습니다.

### 173행

```c

	void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);

```

물리 DTB를 fixmap에 연결해 C에서 읽을 가상 주소를 얻습니다. &size로 실제 크기도 받으며 초기 접근 속성은 PAGE_KERNEL입니다.

### 174행

```c

	const char *name;

```

뒤에서 DTB의 machine model 문자열을 받을 포인터를 선언합니다.

### 176행

```c

	if (dt_virt)

```

매핑이 성공해 유효한 가상 주소를 얻었는지 확인합니다.

### 177행

```c

		memblock_reserve(dt_phys, size);

```

초기 할당기가 DTB 물리 영역을 다른 용도로 덮어쓰지 않도록 예약합니다. 매핑과 메모리 예약은 다른 작업입니다.

### 183행

```c

	if (!early_init_dt_scan(dt_virt, dt_phys)) {

```

DTB를 검사하고 초기 정보를 읽습니다. fixmap 주소를 __pa로 역변환하지 않고 원래 dt_phys를 별도로 전달합니다.

### 184행

```c

		pr_crit("\n"

```

DTB 검사가 실패했음을 심각한 오류 메시지로 출력하기 시작합니다.

### 185행

```c

			"Error: invalid device tree blob: PA=%pa, VA=%px, size=%d bytes\n"

```

오류를 재현할 수 있도록 DTB의 물리 주소·가상 주소·크기를 메시지에 포함합니다. %pa에는 물리 주소 변수의 주소를 넘깁니다.

### 186행

```c

			"The dtb must be 8-byte aligned and must not exceed 2 MB in size.\n"

```

부팅 프로토콜이 요구하는 DTB의 8바이트 정렬 및 2MiB 크기 제한을 안내하는 문자열입니다.

### 187행

```c

			"\nPlease check your bootloader.\n",

```

입력 DTB를 준비한 부트로더를 확인하도록 안내하고 앞선 문자열을 끝냅니다. 여러 C 문자열은 컴파일 때 이어집니다.

### 188행

```c

			&dt_phys, dt_virt, size);

```

앞 메시지의 서식 항목에 물리 주소 변수의 주소, 매핑 주소, 크기를 전달합니다.

### 195행

```c

		while (true)

```

매우 초기라 정상적인 오류 처리도 기대하기 어려우므로 무한 반복으로 더 진행하지 않습니다.

### 196행

```c

			cpu_relax();

```

반복 대기용 cpu_relax를 실행합니다. 잘못된 DTB 상태로 일반 초기화를 계속하지 않으려는 경로입니다.

### 200행

```c

	fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);

```

초기 DTB 수정이 끝난 뒤 같은 영역을 읽기 전용으로 다시 매핑해 이후 의도치 않은 변경을 제한합니다.

### 202행

```c

	name = of_flat_dt_get_machine_name();

```

펼치기 전의 DTB에서 기계 모델 이름을 얻습니다.

### 203행

```c

	if (!name)

```

선택적인 모델 문자열이 없을 경우를 검사합니다.

### 204행

```c

		return;

```

이름이 없어도 앞선 초기화는 끝났으므로 함수에서 돌아갑니다.

### 206행

```c

	pr_info("Machine model: %s\n", name);

```

부팅 로그에 모델 이름을 남겨 사용 중인 플랫폼을 확인하게 합니다.

### 207행

```c

	dump_stack_set_arch_desc("%s (DT)", name);

```

이후 스택 덤프에도 표시할 아키텍처 설명을 등록합니다.

