"프로세스의 모든 메모리 자원을 관리하는 절대 장부" 하드웨어 페이지 테이블(PML4)은 멍청해서 주소 변환밖에 모른다. 페이지 상태(스왑, 파일 등)를 관리할 별도의 장부가 필요하다.
struct thread) 내부에 존재.struct page (가상 페이지 정보를 담은 객체)struct hash_elem hash_elem: 해시 테이블에 넣기 위해 반드시 추가해야 함.Union: 메모리 절약을 위해 UNINIT, ANON, FILE 중 하나의 상태만 가지도록 설계됨.spt_init)hash_init을 호출하여 빈 테이블을 만든다.page_hash(해싱 함수)와 page_less(비교 함수)를 인자로 넘겨줘야 한다.va) 다.spt_find_page)hash_find는 hash_elem을 요구하는데, 우린 va밖에 없다.dummy_page를 만들고 va를 채운다. (pg_round_down 필수!)hash_find에 dummy_page.hash_elem을 미끼로 던진다.va만 보므로, 진짜 페이지를 찾아준다. (같은 녀석으로 인식)elem을 hash_entry로 복원해서 page 반환.spt_insert_page)hash_insert가 중복 검사를 해주므로 별도의 검증 로직 불필요.insert 성공 시 NULL 반환, 실패 시 기존 요소 반환함."실제 땅(RAM)을 관리하고 연결하는 과정"
[ User Page (UVA) ] <---> [ Frame (KVA) ] <---> [ Physical Memory (PA) ]
page는 신청서, frame은 등기부. 둘을 연결해야 메모리 사용 가능.vm_get_frame (땅 확보):
palloc_get_page(PAL_USER): 유저 풀에서 4KB 땅(KVA)을 받아온다.malloc: 커널 풀에서 struct frame 서류를 만든다.frame->kva = kva)하고 반환.vm_do_claim_page (연결):
vm_get_frame 호출.page <-> frame 서로 포인터 연결.pml4_set_page: 하드웨어(MMU)에 "이 가상 주소는 저 물리 주소다"라고 등록.swap_in: 데이터 로딩 시작.vm_claim_page (인터페이스):
va로 페이지 찾아서 vm_do_claim_page에 넘기는 결정자 역할."쪽지(Aux)를 써두고, 나중에 펴보고 심부름시킨다."
데이터를 메모리에 올리지 않고 쪽지(aux)만 써둔다.
load_segment -> vm_alloc_page_with_initializeraux) 작성: "나중에 이 파일의 이 위치 읽어라."VM_UNINIT 상태로 만들고, 쪽지와 작업반장(lazy_load_segment)을 넣어둠.사용자가 주소를 건드려서 에러가 난다.
vm_try_handle_fault -> vm_do_claim_page -> swap_inswap_in이 호출되면 uninit_initialize가 실행된다.anon_initializer 등을 호출해 VM_ANON 등으로 변신.lazy_load_segment) 호출.lazy_load_segmentaux)를 펼쳐본다.file_read로 진짜 데이터를 읽어서 kva에 넣는다.memset(0)으로 청소한다 (보안!).setup_stack)VM_ANON)다.argc, argv)을 위해 당장 써야 하므로 바로 할당(claim)한다.vm_alloc_page(VM_ANON | VM_MARKER_0, ...) (예약)vm_claim_page(...) (즉시 할당)rsp 설정 (USER_STACK)spt_copy)부모의 SPT를 hash_iterator로 돌면서 복사한다. 얕은 복사는 절대 금지!
VM_UNINIT: 아직 로딩 안 됨 -> 계획(Initializer, Aux)만 복사.VM_ANON: 이미 로딩 됨 -> 물리 메모리 할당(claim) + 내용 복사(memcpy).struct page를 복사하는 게 아니라, 내용물(4KB)을 복사해야 함!spt_kill)hash_clear로 장부를 비우면서 destroy 호출 -> 자원 해제.