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)