jun-wiki

View My GitHub Profile

Posts (Latest 10 updated) :
Read all
Contents:
  1. 가상 주소 (Virtual Address라는 뜻)

가상 주소 (Virtual Address라는 뜻)

알다시피 64 비트 가상주소는 이렇게 구성되어있다

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


그리고 이러한 가상 주소를 다루기 위한 함수/매크로가
include/threads/vaddr.hinclude/threads/mmu.h 헤더에 정의되어 있다

#define PGSHIFT { /* 세부 내용 생략 */ }
#define PGBITS  { /* 세부 내용 생략 */ }

가상 주소의 오프셋 부분의 시작 비트 인덱스(0)와 비트 수(12)를 각각 나타낸다



#define PGMASK  { /* 세부 내용 생략 */ }

페이지 오프셋 위치의 비트가 1이고 나머지는 0인 비트 마스크(0xfff)



#define PGSIZE  { /* 세부 내용 생략 */ }

페이지 크기(바이트 단위, 4,096)



#define pg_ofs(va) { /* 세부 내용 생략 */ }

가상 주소 va에서 페이지 오프셋을 추출해 반환



#define pg_no(va) { /* 세부 내용 생략 */ }

가상 주소 va에서 페이지 번호를 추출해 반환



#define pg_round_down(va) { /* 세부 내용 생략 */ }

va가 속한 가상 페이지의 시작 주소(오프셋을 0으로 만든 값)를 반환



#define pg_round_up(va) { /* 세부 내용 생략 */ }

va가장 가까운 상위 페이지 경계로 반올림한 주소를 반환



Pintos에서는 가상 메모리를 사용자 가상 메모리커널 가상 메모리로 나눈다

두 영역의 경계는 KERN_BASE

#define KERN_BASE { /* 세부 내용 생략 */ }

커널 가상 메모리의 기준(base) 주소
기본값은 0x8004000000로 사용자 가상 메모리는 가상 주소 0부터 KERN_BASE 미만까지이며, 커널 가상 메모리는 나머지 가상 주소 공간을 차지한다



#define is_user_vaddr(vaddr)  { /* 세부 내용 생략 */ }
#define is_kernel_vaddr(vaddr){ /* 세부 내용 생략 */ }

각각 va가 사용자 가상 주소인지, 커널 가상 주소인지 여부를 true/false로 반환한다



x86-64에서 직접 물리 주소로 메모리 접근하는 방법이 없다

그치만 OS커널에서는 이러할 필요가 있기에 Pintos에서는 커널 가상 메모리와 물리 메모리를 1대1로 매핑시켜 우회했다

KERN_BASE보다 큰 가상 주소는 물리 주소 0을, 가상 주소 KERN_BASE + 0x1234물리 주소 0x1234 를 대응해주는 식으로 말이다

이를 통해 물리 주소에 KERN_BASE를 더하면 그 주소에 접근하는 커널 가상 주소가 되고, 반대로 커널 가상 주소에서 KERN_BASE를 빼면 해당하는 물리 주소가 된다

이를 위한 한 쌍의 함수를 include/threads/vaddr.h에서 제공한다

#define ptov(paddr) { /* 세부 내용 생략 */ }

물리 주소 pa(0 이상이고, 물리 메모리 총 바이트 수 이하)에 대응하는 커널 가상 주소를 반환


#define vtop(vaddr) { /* 세부 내용 생략 */ }

커널 가상 주소va에 대응하는 물리 주소를 반환



페이지 테이블에 대한 연산은 include/threads/mmu.h에서 제공한다

#define is_user_pte(pte) { /* 세부 내용 생략 */ }
#define is_kern_pte(pte) { /* 세부 내용 생략 */ }

해당 PTE(Page Table Entry)가 각각 사용자 혹은 커널 소유인지 확인


#define is_writable(pte) { /* 세부 내용 생략 */ }

해당 PTE가 가리키는 가상 주소가 쓰기 가능한지를 확인


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);

typedef bool pte_for_each_func(...) 는 콜백 함수다
역할은 PTE를 주면 계속 순회할지/중단할지 알려준다

bool pml4_for_each(...) 는 페이지 테이블 순회기로
주어진 PML4 아래의 모든 매핑된 최하위 PTE를 돌며 매 PTE마다 받은 콜백 호출한다


예시 콜백 함수

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;
}


아무튼, 이를 활용해서 리소스 회수하거나 CoW준비 등을 할 수 있다