Project3 - gitbook(2)

이후띵·2022년 1월 12일
0

PintOS

목록 보기
23/31

Handling page fault

Supplemental page table의 가장 중요한 고객은 page fault handler이다.
프로젝트2 에서, page fault는 항상 커널이나 유저프로그램의 버그를 가리켰다. 프로젝트3 에서는 더이상 이것이 사실이 아니다. 지금부터는, page fault는 파일이나 스왑슬롯에서 페이지를 가져와야한다는 것만을 가리킨다. 너는 이러한 케이스들을 핸들하기위해 정교한 page fault를 구현해야 한다.

userprog/exception.c 의 page_fault() 함수는 page fault handler이며, vm/vm.c에 있는 vm_try_handle_fault() 즉, 너의 page fault handler를 호출한다.

너의 page fault handler가 해야할 일:

  1. supplemental page table에서 page fault가 발생한 페이지를 찾는다. 만약 그 메모리의 참조가 valid하면, supplemental page table entry를 사용하여 파일시스템, 스왑슬롯, 또는 단순히 모두 0으로 되어있는 페이지일 수도 있는 그 페이지에 있는 데이터를 찾는다. 너가 COW를 구현한다면, 페이지의 데이터는 막말로 페이지테이블에 없고, 이미 페이지 프레임에 있을 수도 있다. 만약 supplemental page table이 (1)유저프로세스가 접근하려는 곳에 아무런 데이터도 기대할 수 없거나, (2) 페이지가 커널 vm에 있거나, (3) read-only page에 write를 시도하면, 이 접근은 invalid하다. invalid 접근은 프로세스를 제거하고 이것에 의해 모든 자원을 free한다.

  2. 페이지를 저장하기위한 프레임을 획득해라. sharing을 구현하는 경우, 너가 필요한 데이터가 이미 프레임에 있을 수 있으며, 이 경우, 너는 프레임을 찾을 수 있어야 한다.

  3. 파일 시스템이나 swap으로부터 읽어오거나, 0으로 설정하거나 등등을 통해 데이터를 프레임으로 가져옵니다. sharing를 구현하는 경우, 필요한 페이지가 이미 프레임에 있을 수 있으며, 이 경우 이 단계에서는 조치가 필요하지 않습니다.

  4. faulting 가상 주소의 페이지 테이블 항목을 실제 페이지로 가리키세요. threads/mmu.c에서 함수를 사용할 수 있습니다.

Managing the Frame Table

프레임 테이블은 각 프레임당 하나의 entry만 포함하고 있다. 프레임 테이블의 각각의 entry는 페이지를 가리키며 현재 그 프레임을 점유하고 있는 포인터와 너가 선택한 다른 데이터를 포함하고 있다. 프레임 테이블은 프레임들이 모두 free하지 않을 때(꽉차있을 때?) 핀토스가 퇴거시킬 페이지에 효율적으로 퇴거 정책을 펼칠 수 있도록 한다.

유저 페이지들로 사용되는 프레임들은 반드시 "user pool"에서 얻어와야한다. palloc_get_page(PAL_USER) 를 통해 가능하다. 너는 PAL_USER를 사용하여 몇몇의 테스트 케이스들에서 예상치 못한 fail을 발생시킬 수 있는 "kernel pool"에 할당하는 것을 피할 수 있다. 프레임 테이블 구현파트에서 palloc.c를 수정할 때 두 pool의 차이를 확실하게 유지해야한다.

프레임 테이블에서 가장 중요하게 수행되는 것은 사용하지 않는 프레임을 획득하는 것이다. 프레임이 free일때는 굉장히 쉬운 것이다. 아무것도 free된 것이 없을 때, 몇몇을 프레임을 퇴거시켜서 free시켜줘야한다.

스왑 슬롯을 할당하지 않고 프레임을 퇴거할 수 없다. 그러나 스왑이 가득 찼다면, 커널에 패닉에 빠지게 된다. 실제 OS는 그러한 상황에서 복구하거나 방지하기 위해 광범위한 정책을 적용하지만, 이러한 정책은 이 프로젝트의 범위를 벗어난다.

process of eviction은 대충 다음과 같은 과정을 거친다:

  1. 너의 replace algorithm을 사용하여 evict시킬 프레임을 고른다. "Accessed and Dirty Bits"파트를 보면 유용할 것이다.(밑에나옴)

  2. 페이지 테이블에서 해당 프레임을 참조하는 모든 것을 지운다. 너가 sharing을 구현해놓지 않은 이상, 어떤 순간에도 단일 페이지만 프레임을 참조하는 것이 가능한 상태이다.

  3. 필요하다면, 페이지를 파일시스템이나 스왑에 기록해라. 퇴거시킬 프레임은 아마 다른 페이지를 저장하기위해 사용될 것이다.

Accessed and Dirty Bits

x86-64 하드웨어는 page replacement algorithm들을 실행하기 위한 some assistance를 제공한다(a pair of bits in the page table entry (PTE) for each page를 통해). page에 read나 write을 하는 모든 경우에 CPU는 page의 PTE에 accessed bit를 1로 설정한다. write은 dirty bit을 1로 설정한다. CPU는 절때 이 비트들을 0으로 재설정 하지 않으며ㅏ, OS가 아마 해야될꺼다.

즉, CPU가 알아서 해주는 것은
-> read의 경우 accesed bit = 1
-> write의 경우 accesed bit = 1, dirty bit = 1
다 쓰고나서는 OS에서 0으로 reset해줘야 한다.

너는 aliases를 신경써야한다. 그게뭐냐면, 두개 이상의 페이지가 같은 프레임을 참조하는 것이다. 둘이상의 프레임들이 accessed하게되면, accessed bit와 dirty bit은 오직 하나의 PTE에만 업데이트 되어야한다.

핀토스에서 모든 유저의 가상페이지는 그것의 커널 가상페이지와 aliased 된다. 너는 이걸 어떻게든 관리해아한다. 예를들어, 너의 코드는 커널의 가상페이지와 유저의 가상페이지 둘다 accesed, dirty bit들을 모두 체크하고 업데이트 할 것이다. 대안적으로, 커널은 오직 (user 가상 주소를 통해) user data에만 접근함으로써 이문제를 피할 수 있을 것이다.
-> is_user_addr()써서 유저데이터만 bit처리해주면 될듯?

다른 alias들은 sharing을 구현하거나 너의 코드가 버그가 있을때나 발생한다.

Managing the Swap Table

swap table은 사용중이거나, free되어있는 swap slot들을 추적한다. 스왑테이블은 페이지를 프레임으로부터 스왑파티션으로 퇴거시키기 위해 사용하지 않는 스왑슬롯을 선택할 수 있어야한다. 또한, 그것의 페이지가 read back 될 때나, 페이지가 스왑된 프로세스가 제거될 때 free시키는 것을 가능하게 해야 한다.

vm/build 디렉토리에서, pintos-mkdisk swap.dsk --swap--size=n 커맨드를 통해 n-MB 스왑 파티션을 포함한 swap.dsk를 생성할 수 있다. 이후에 핀토스를 실행할 때 swap.dsk는 자동적으로 추가된다. 또는, 너는 --swap-size=n 을 통해 임시 n-MB 디스크를 single run에서 활용할 수 있다.

스왑 슬롯은 실제로 퇴거가 요구될 때만 게으르게 할당되어야한다. 실행 파일에서 데이터 페이지를 읽고 프로세스 시작 시 즉시 스왑하도록 작성하는 것은 게으르지 않다. 스왑슬롯들은 특정페이지를 저장하기위해 예약되서는 안된다.

내용을 프레임으로 다시 읽을 때 스왑 슬롯을 free 시켜라.

Managing Memory Mapped Files

파일시스템은 read나 write 시스템콜들로 접근되는 것이 가장 일반적이다. 두 번째 인터페이스는 파일에서 가상 페이지로 맵핑하기 위함이다(mmap 시스템콜을 사용해서). 프로그램은 그제서야 메모리 인스트럭션들을 파일데이터에 직접 사용할 수 있다. foo라는 파일이 0x1000(4kB)라고 가정하자. 만약 foo가 0x5000에서 메모리가 시작하는 것으로 맵핑되어 있다면, 0x5000 ~ 0x5fff 사이에있는 어떠한 메모리에 접근하던 foo에 상응하는 바이트들에 접근할 것이다.

밑에 있는 건 mmap을 사용해서 콘솔에 파일을 프린트하는 프로그램이다. 이건 커맨드라인에서 특정된 파일을 오픈하고, 가상주소 0x10000000에 맵핑을하고, 맵핑된 데이터를 콘솔(fd 1)에 write하고, file을 unmap한다.

너의 코드는 메모리가 맵핑된 파일이 어떤 메모리에 있는지 추적이 가능해야한다. 맵핑된 영역에서 발생하는 page fault를 적절히 처리하는것이 필요하고, 맵핑된 파일이 프로세스 내의 어떠한 segement와도 중복되지 않되도록 해야한다.

EOI(End of Introduction)

profile
이후띵's 개발일지

0개의 댓글