# paging_init: RAM에 접근할 가상 주소 마련하기

v6.6 / arch/arm64/mm/mmu.c

RAM이 존재한다는 사실과 커널 포인터로 접근할 수 있다는 사실은 다릅니다. Linux v6.6의 paging_init은 최종 커널 매핑을 작성하고 TTBR1을 그 테이블로 교체한 뒤 초기 테이블 공간을 돌려줍니다. 주소를 해석하는 기준을 바꾸는 동안에도 코드가 계속 실행되어야 하므로 임시 매핑과 동일 주소 매핑이 필요합니다.

## paging_init

```c

void __init paging_init(void)
{
	pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));
	extern pgd_t init_idmap_pg_dir[];

	idmap_t0sz = 63UL - __fls(__pa_symbol(_end) | GENMASK(VA_BITS_MIN - 1, 0));

	map_kernel(pgdp);
	map_mem(pgdp);

	pgd_clear_fixmap();

	cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_idmap_pg_dir);
	init_mm.pgd = swapper_pg_dir;

	memblock_phys_free(__pa_symbol(init_pg_dir),
			   __pa_symbol(init_pg_end) - __pa_symbol(init_pg_dir));

	memblock_allow_resize();

	create_idmap();
}

```

### 790행

```c

void __init paging_init(void)

```

arm64의 부팅 중 페이지 테이블 구성 함수입니다. v6.6에서는 커널 매핑 작성과 TTBR1 교체까지 이 함수에서 연결합니다.

### 792행

```c

	pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));

```

swapper_pg_dir의 물리 주소를 구하고 fixmap의 임시 슬롯에 연결하여 수정 가능한 pgdp 주소를 얻습니다. 주소만 형 변환하는 것이 아니라 임시 매핑을 마련하는 호출입니다.

### 793행

```c

	extern pgd_t init_idmap_pg_dir[];

```

TTBR1 전환 중에 사용할 초기 동일 주소 매핑 테이블 심벌을 외부 선언합니다. 선언 자체가 테이블을 새로 만드는 것은 아닙니다.

### 795행

```c

	idmap_t0sz = 63UL - __fls(__pa_symbol(_end) | GENMASK(VA_BITS_MIN - 1, 0));

```

커널 끝 물리 주소와 최소 가상 주소 범위를 함께 고려해 동일 주소 매핑에 필요한 T0SZ 값을 계산합니다. __fls는 가장 높은 설정 비트를 찾아 필요한 주소 비트 수 판단에 사용됩니다.

### 797행

```c

	map_kernel(pgdp);

```

임시로 접근 가능한 커널 최상위 테이블에 커널 이미지의 코드·데이터 매핑을 작성합니다. 구간별 권한 등은 map_kernel이 처리합니다.

### 798행

```c

	map_mem(pgdp);

```

같은 테이블에 물리 RAM의 선형 매핑을 작성합니다. 커널 이미지 매핑과 일반 RAM 접근용 선형 매핑을 구분하셔야 합니다.

### 800행

```c

	pgd_clear_fixmap();

```

테이블 작성을 위해 사용한 임시 fixmap 슬롯을 해제합니다. 방금 작성한 커널 페이지 테이블 자체를 폐기하는 것이 아닙니다.

### 802행

```c

	cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_idmap_pg_dir);

```

초기 동일 주소 매핑을 사용하여 TTBR1을 새 커널 페이지 테이블로 교체합니다. lm_alias는 테이블에 대한 선형 매핑 쪽 주소를 제공하며 단순 포인터 대입보다 큰 주소 변환 전환입니다.

### 803행

```c

	init_mm.pgd = swapper_pg_dir;

```

초기 커널 mm 자료구조도 새 최상위 테이블을 가리키도록 맞춥니다. 하드웨어 기준과 소프트웨어 관리 정보를 일치시키는 단계입니다.

### 805행

```c

	memblock_phys_free(__pa_symbol(init_pg_dir),

```

전환 전 사용하던 init_pg_dir 메모리 구간을 memblock 예약에서 해제하기 시작합니다. 아래줄이 해제 크기를 계산합니다.

### 806행

```c

			   __pa_symbol(init_pg_end) - __pa_symbol(init_pg_dir));

```

init_pg_dir 시작부터 init_pg_end까지의 물리 주소 차이를 크기로 넘깁니다. swapper_pg_dir 자체를 해제하는 호출과 혼동하지 않으셔야 합니다.

### 808행

```c

	memblock_allow_resize();

```

이제 memblock의 내부 구간 배열이 필요할 때 확장될 수 있도록 허용합니다. 이 호출 자체가 모든 배열을 즉시 늘리지는 않습니다.

### 810행

```c

	create_idmap();

```

이후 낮은 수준의 주소 변환 전환 등에 사용할 동일 주소 매핑을 구성합니다. 앞에서 잠시 사용한 init_idmap_pg_dir와 사용 시점을 구별해서 읽으셔야 합니다.

