/* 64-bit 가상 주소의 구조 */
63 48 47 39 38 30 29 21 20 12 11 0
+--------+----------------+----------------+----------------+-------------+----------+
| Sign | Page-Map | Page-Directory | Page-directory | Page-Table | Physical |
| Extend | Level-4 Offset | Pointer | Offset | Offset | Offset |
+--------+----------------+----------------+----------------+-------------+----------+
| | | | | |
+------- 9 ------+------- 9 ------+------- 9 ------+----- 9 -----+--- 12 ---+
Virtual Address
헤더파일
include/threads/vaddr.h
와include/threads/mmu.h
는 가상 주소들을 다루기위한 이런 함수들과 매크로들을 정의
각각 가상 주소 오프셋 부분의 인덱스 (0) bit 와 bit의 수 (12)
#define PGSHIFT { /* Omit details */ }
#define PGBITS { /* Omit details */ }
“페이지 오프셋” 부분의 비트들에 1, 나머지는 0으로 설정되어 있는 비트마스킹 매크로
#define PGMASK { /* Omit details */ }
바이트 단위에서 페이지 크기 (4,096)
#define PGSIZE { /* Omit details */ }
가상 주소 va 의 페이지 오프셋을 뽑아내 반환
#define pg_ofs(va) { /* Omit details */ }
가상 주소 va 의 페이지 번호를 뽑아내 반환
#define pg_no(va) { /* Omit details */ }
내부에서 va가 가리키는 가상 페이지의 시작 (페이지 오프셋이 0으로 설정된 va)을 반환
#define pg_round_down(va) { /* Omit details */ }
가장 근접한 페이지 경계 값으로 올림된 va를 반환
#define pg_round_up(va) { /* Omit details */ }
커널 가상 메모리의 기본 주소. 기본값은 0x8004000000.
#define KERN_BASE { /* Omit details */ }
유저 가상 메모리 : 가상 주소 0
부터 KERN_BASE
까지
커널 가상 메모리 : 가상 주소 공간의 나머지 부분을 차지
핀토스에서 가상 메모리는 두 영역(유저/커널)으로 나뉨 ( 참고 Virtual Memory Layout )
둘 사이의 경계 = KERN_BASE
va(가상주소)가 각각 유저 가상 주소 또는 커널 가상 주소 라면
True
, 아니면False
반환
#define is_user_vaddr(vaddr) { /* Omit details */ }
#define is_kernel_vaddr(vaddr) { /* Omit details */ }
x86-64에서는 주어진 물리 주소 메모리에 직접적으로 접근할 수 있는 방법을 제공하지 않는다.
이 기능은 os 커널에서 필요하며,
이를 위해 핀토스는 커널 가상 메모리를 물리 메모리와 1대1로 매핑(mapping)한다.
즉, 가상 주소가 KERN_BASE라면 물리 주소 0에 매핑되며,
가상 주소가 `KERN_BASE + 0x1234` 라면, 물리 주소 0x1234에 매핑된다.
따라서, 물리 주소에 `KERN_BASE` 를 더하면 커널 가상 주소를 얻을 수 있고,
커널 가상 주소에서 `KERN_BASE` 를 빼주면 물리 주소를 얻을 수 있다.
0 ~ (물리 주소의 크기) 내에 존재하는 물리 주소(pa)와 대응되는 커널 가상 주소를 반환
#define ptov(paddr) { /* Omit details */ }
커널 가상 주소(va)와 대응되는 물리 주소를 반환
#define vtop(vaddr) { /* Omit details */ }
헤더파일
include/threads/mmu.h
은 페이지 테이블 상에서의 활동을 제공
페이지 테이블 엔트리(PTE)의 주인이 유저인지 커널인지 확인
#define is_user_pte(pte) { /* Omit details */ }
#define is_kern_pte(pte) { /* Omit details */ }
PTE가 가리키는 가상주소가 작성 가능한 지(wriatable) 아닌 지 확인
#define is_writable(pte) { /* Omit details */ }
각 PML4 아래에 있는 valid entry마다, 함수 FUNC에 보조값 AUX를 계산
= 각pml4
가 유효한 entry를 가지고 있는지 검사
typedef bool pte_for_each_func (uint64_t *pte, void *va, void *aux);
bool pml4_for_each (uint64_t *pml4, pte_for_each_func *func, void *aux);
func
함수가 pml4_for_each
에서 구현되는 과정static bool
stat_page (uint64_t *pte, void *va, void *aux) {
if (is_user_vaddr (va))
printf ("user page: %llx\n", va);
if (is_writable (va))
printf ("writable page: %llx\n", va);
return true;
}
pml4_for_each
의 인자로 전달될 수 있는 func
의 예시이다.