현재 상태는 페이지 테이블만 있음(pml4).
supplemental page table 구조체가 비어있다. 어떠한 정보가 필요한가?
페이지 폴트와 자원 관리를 처리해야함. 그럼 hash table이 일단 필요하겠다. hash 구조체 구경하기
<vm.h>
struct supplemental_page_table {
struct hash spt_hash;
};
Instead, each structure that can potentially be in a hash must embed a struct hash_elem member.
이라고 되어있어서 page에 hash_elem 구조체 추가함<vm.h>
struct page {
'''
struct hash_elem hash_elem;
'''
};
그리고 세가지 function을 손봐야한다.
bool hash_init (struct hash *h, hash_hash_func *hash, hash_less_func *less, void *aux)
<vm.c>
/* Computes and returns the hash value for hash element E, */
unsigned
page_hash (const struct hash_elem *he, void *aux UNUSED) {
const struct page *p = hash_entry(he, struct page, hash_elem);
// hash_bytes: returns a hash of the size(sec arg) bytes in BUF(first arg)
return hash_bytes (&p->va, sizeof(p->va));
}
/* Returns true if A is less than B, or false if A is greater than or equal to B */
bool
page_less (const struct hash_elem *a, const struct hash_elem *b, void *aux UNUSED) {
const struct page *pa = hash_entry(a, struct page, hash_elem);
const struct page *pb = hash_entry(b, struct page, hash_elem);
return pa->va < pb->va;
}
/* Initialize new supplemental page table */
void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
hash_init(spt, page_hash, page_less, NULL);
}
struct page spt_find_page (struct supplemental_page_table spt, void *va);
hash_find() 함수 사용하자. 주석 설명
Finds and returns an element equal to E in hash table H, or a
null pointer if no equal element exists in the table.
그렇다면 spt_find_page에서 인자로 받아오는 spt가 hash이니까 첫번째 매개변수로 넘기고, va를 아니까 page 할당받아서 va넣고 그 페이지의 hash_elem 을 넘기자.
/* Find VA from spt and return page. On error, return NULL. */
struct page *
spt_find_page (struct supplemental_page_table *spt UNUSED, void *va UNUSED) {
struct page *page = NULL;
page = palloc_get_page(PAL_USER);
page->va = va;
struct hash_elem *e;
e = hash_find(&spt, &page->hash_elem);
return e!=NULL ? hash_entry(e, struct page, hash_elem):NULL;
}
bool spt_insert_page (struct supplemental_page_table spt, struct page page);
hash_insert(&spt, &page->hash_elem) 이렇게 쓰면 될것같은데 존재하지 않을 경우에만이라는 조건을 어떻게 넣을 수 있을까.
hash_insert 함수의 주석을 보고 아이디어를 얻었다.
Inserts NEW into hash table H and returns a null pointer, if no equal element is already in the table. If an equal element is already in the table, returns it without inserting NEW.
그럼 없던 데이터를 넣을 땐 null pointer를 반환하니까 함수 값이 널일 때만 실행 되게 하면 되겠다.
/* Insert PAGE into spt with validation. */
bool spt_insert_page(struct supplemental_page_table *spt UNUSED,
struct page *page UNUSED) {
int succ = false;
return hash_insert(&spt, &page->hash_elem) == NULL ? true : false;
}
Implement vm_get_frame
, vm_claim_page
and vm_do_claim_page
in vm/vm.c
.
/* Gets a new physical page from the user pool by calling palloc_get_page.
* When successfully got a page from the user pool, also allocates a frame,
* initialize its members, and returns it.
* 사용자 풀에서 페이지를 성공적으로 가져오면, 프레임을 할당하고 해당 프레임의
* 멤버를 초기화한 후 반환한다. 페이지 할당을 실패할 경우, PANIC ("todo")로
* 표시한다. (swap out을 구현한 이후 변경한다.)
*
* palloc() and get frame. If there is no available page, evict the page
* and return it. This always return valid address. That is, if the user pool
* memory is full, this function evicts the frame to get the available memory
* space.*/
static struct frame *vm_get_frame(void) {
struct frame *frame = NULL;
/* TODO: Fill this function. */
void *kva = palloc_get_page(PAL_USER);
if (kva == NULL) {
PANIC("todo");
}
// 프레임을 할당하고 해당 프레임의 멤버를 초기화한 후 반환한다
frame = malloc(size_of(struct frame));
frame->kva = kva;
ASSERT(frame != NULL);
ASSERT(frame->page == NULL);
return frame;
}
git book 설명
Claims, meaning allocate a physical frame, a page. You first get a frame by calling vm_get_frame (which is already done for you in the template). Then, you need to set up the MMU. In other words, add the mapping from the virtual address to the physical address in the page table. The return value should indicate whether the operation was successful or not.
프레임을 vm_get_frame으로 얻으라고 해서 얻고 frame이랑 page랑 밑에 함수에서 엮어주길래 나도 엮어주고 까지는 했는데 그 다음에서 add the mapping from the virtual address to the physical address in the page table
그니까 page table에서 가상주소에서 물리주소로 맵핑해줘라인데 page table에 어떻게 해줘야할지 난감했다.
page table 관련 함수가 threads/mmu.c에 있어서 함수를 뒤지다가 pml4_set_page() 함수의 주석을 보고 이놈으로 결정했다. 주석은 이렇다.
Adds a mapping in page map level 4 PML4 from user virtual page UPAGE to the physical frame identified by kernel virtual address KPAGE.
근데 pml4가 어디에 있느냐 말이다. 아 thread 구조체 안에 있다.
/* Claim the PAGE and set up the mmu. */
static bool vm_do_claim_page(struct page *page) {
struct frame *frame = vm_get_frame();
/* Set links */
frame->page = page;
page->frame = frame;
// add the mapping from the virtual address to the physical address in the
// page table (pml4_set_page())
struct thread *curr = current_thread();
pml4_set_page(curr->pml4, page->va, frame->kva, page->writable);
return swap_in(page, frame->kva);
}
Claims the page to allocate va. You will first need to get a page and then calls vm_do_claim_page with the page.
/* Claim the page that allocate on VA. */ bool vm_claim_page(void *va UNUSED) { struct page *page = NULL; // spt에서 va에 해당하는 page 찾기 page = spt_find_page(&thread_current()->spt, va); return vm_do_claim_page(page); }