63          48 47            39 38            30 29            21 20         12 11         0
+-------------+----------------+----------------+----------------+-------------+------------+
| Sign Extend |    Page-Map    | Page-Directory | Page-directory |  Page-Table |  Physical  |
|             | Level-4 Offset |    Pointer     |     Offset     |   Offset    |   Offset   |
+-------------+----------------+----------------+----------------+-------------+------------+
              |                |                |                |             |            |
              +------- 9 ------+------- 9 ------+------- 9 ------+----- 9 -----+---- 12 ----+
                                          Virtual Address

vaddr (include > threads > vaddr.h)

/* Page offset (bits 0:12). */
#define PGSHIFT 0                          /* 가장 첫번째 오프셋 비트의 인덱스 */
#define PGBITS  12                         /* 오프셋 비트 수 */
#define PGSIZE  (1 << PGBITS)              /* 페이지 크기 (page size) 4,096 바이트 */
#define PGMASK  BITMASK(PGSHIFT, PGBITS)   /* 페이지 오프셋 비트 (0:12)
																							0xfff: 페이지 오프셋 비트가 1로, 나머지 비트가 0으로 설정된 비트 마스크 */

/* 페이지 내 오프셋(offset) */
#define pg_ofs(va) ((uint64_t) (va) & PGMASK) /* 가상 주소 va에서 페이지 오프셋을 추출하여 반환 */

#define pg_no(va) ((uint64_t) (va) >> PGBITS) /* 가상 주소 va에서 페이지 번호를 추출하여 반환 */

/* va를 가장 가까운 페이지 경계로 올림한 값을 반환 */
#define pg_round_up(va) ((void *) (((uint64_t) (va) + PGSIZE - 1) & ~PGMASK))

/* 가장 가까운 페이지 경계로 내림 처리
va가 가리키는 가상 주소의 속한 가상 페이지의 시작 주소(va의 페이지 오프셋이 0인 주소)를 반환 */
#define pg_round_down(va) (void *) ((uint64_t) (va) & ~PGMASK)

/* 커널 가상 주소 시작점
사용자 가상 메모리는 가상 주소 0~KERN_BASE. 커널 가상 메모리는 나머지 가상 주소 공간을 차지 */
#define KERN_BASE LOADER_KERN_BASE

/* 유저 스택 시작 주소 */
#define USER_STACK 0x47480000

/* VADDR이 유저 가상 주소라면 true을 반환 */
#define is_user_vaddr(vaddr) (!is_kernel_vaddr((vaddr)))

/* VADDR가 커널 가상 주소인 경우 true를 반환 */
#define is_kernel_vaddr(vaddr) ((uint64_t)(vaddr) >= KERN_BASE)

/* FIXME: 확인을 추가해야 함
물리 주소 PADDR이 매핑 된 커널 가상 주소를 반환. 이 때, 물리 메모리의 크기를 초과하지 않아야 함 */
#define ptov(paddr) ((void *) (((uint64_t) paddr) + KERN_BASE))

/* VADDR를 매핑한 물리 주소를 반환 / 커널 가상 주소를 물리 메모리 주소로 변환 */
#define vtop(vaddr) \\
({ \\
	ASSERT(is_kernel_vaddr(vaddr)); \\
	((uint64_t) (vaddr) - (uint64_t) KERN_BASE);\\
})

mmu (include > threads > mmu.c)


typedef bool pte_for_each_func (uint64_t *pte, void *va, void *aux);

/* 해당 페이지 테이블 엔트리(PTE)가 가리키는 가상 주소가 쓰기 가능한지 여부를 조회 */
#define is_writable(pte) (*(pte) & PTE_W)
/* 해당 페이지 테이블 엔트리(PTE)가 유저 혹은 커널에 의해 소유되었는지에 대해 검사 */
#define is_user_pte(pte) (*(pte) & PTE_U)
#define is_kern_pte(pte) (!is_user_pte (pte))

#define pte_get_paddr(pte) (pg_round_down(*(pte)))

syscall (2)