
2025.06.03
오늘한 내용 : PintOS - Project3: Virtual Memory - frame table 구현!
WEEK 12 : 정글 끝까지(PintOS) - Virtual Memory
2. 프레임 테이블 & vm_get_frame (
vm/vm.c):페이지를 실제로 RAM에 올릴 수 있도록 프레임 할당 기능 구현.
- vm_get_frame 구현 - 프레임 생성 및 리스트 연결
/* 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)
{
lock_acquire(&frame_table_lock);
struct frame *frame = NULL;
/* TODO: Fill this function. */
/* 1) 빈 유저 페이지가 있는지 할당 시도 <- 빈 물리 페이지를 할당*/
void *kva = palloc_get_page(PAL_USER);
if (kva != NULL)
{
/* 받아온 kva를 관리할 struct frame을 malloc <- 프레임 테이블 위함 */
frame = (struct frame *)malloc(sizeof(struct frame));
if (frame == NULL)
{
palloc_free_page(kva);
lock_release(&frame_table_lock);
return NULL;
}
frame->kva = kva;
frame->page = NULL;
list_push_back(&frame_table, &frame->frame_elem); // 프레임 테이블에 넣어줌
ASSERT(frame != NULL);
ASSERT(frame->page == NULL);
lock_release(&frame_table_lock);
return frame;
}
/* 2) 빈 유저 페이지가 없을 때 evicit(축출) 수행 */
struct frame *victim = vm_evict_frame();
if (victim == NULL)
{
/* evicition 실패 했다면 NULL을 리턴
함수 상단 주석을 보면 항상 옳은 주소 반환 -> 실패 없음
*/
lock_release(&frame_table_lock);
return NULL;
}
victim->page = NULL;
ASSERT(victim != NULL);
ASSERT(victim->page == NULL);
lock_release(&frame_table_lock);
return victim;
}
/* Evict one page and return the corresponding frame.
* Return NULL on error.*/
static struct frame *
vm_evict_frame(void)
{
struct frame *victim = vm_get_victim();
/* TODO: swap out the victim and return the evicted frame. */
if (victim == NULL)
return NULL;
/* victim이 차지하고 있는 페이지가 있다면 swap_out*/
if (!swap_out(victim->page))
return NULL;
return victim;
}
/* Get the struct frame, that will be evicted. */
static struct frame *
vm_get_victim(void)
{
struct frame *victim = NULL;
/* TODO: The policy for eviction is up to you. */
if (list_empty(&frame_table))
return NULL;
/* FIFO 방식 */
// struct list_elem *e = list_pop_front(&frame_table);
// victim = list_entry(e, struct frame, frame_elem);
/* CLOCK 방식 */
struct list_elem *e;
struct frame *victim;
for (e = list_begin(&frame_table); e != list_end(&frame_table);)
{
victim = list_entry(e, struct frame, frame_elem);
if (pml4_is_accessed(thread_current()->pml4, victim->page->va))
{
/* 참조되었으니, second chance: accessed 비트만 0으로 내리고 뒤로 보낸다 */
pml4_set_accessed(thread_current()->pml4, victim->page->va, false);
e = list_remove(e); // list_next를 반환해줌
list_push_back(&frame_table, &victim->frame_elem);
}
else
{
/* accessed 비트가 이미 0 → 이게 바로 victim */
list_remove(e);
return victim;
}
}
/* 2) 위 루프에서 victim을 못 찾았다면, 리스트 앞에서 그냥 꺼낸다 (가장 오래된 것) */
e = list_pop_front(&frame_table);
victim = list_entry(e, struct frame, frame_elem);
return victim;
}
/* Claim the page that allocate on VA. */
bool vm_claim_page(void *va)
{
struct page *page = NULL;
/* TODO: Fill this function */
/* 현재 스레드의 spt에서 해당 VA에 할당된 struct page 찾기 */
page = spt_find_page(&thread_current()->spt, va);
if (page == NULL)
return false;
return vm_do_claim_page(page);
}
/* 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;
/* TODO: Insert page table entry to map page's VA to frame's PA. */
/* 가상 주소와 물리 주소를 매핑 */
pml4_set_page(thread_current->pml4, page->va, frame->kva, page->writable);
return swap_in(page, frame->kva);
}