[WEEK 12] PintOS - Project 3: Virtual Memory (Stack Growth)

신호정 벨로그·2021년 10월 25일

Today I Learned

목록 보기

Stack Growth

In project 2, the stack was a single page starting from the USER_STACK, and programs' executions were limited to this size. Now, if the stack grows past its current size, we allocate additional pages as necessary.

Allocate additional pages only if they "appear" to be stack accesses. Devise a heuristic that attempts to distinguish stack accesses from other accesses.

User programs are buggy if they write to the stack below the stack pointer, because typical real OSes may interrupt a process at any time to deliver a "signal," which modifies data on the stack. However, the x86-64 PUSH instruction checks access permissions before it adjusts the stack pointer, so it may cause a page fault 8 bytes below the stack pointer.

You will need to be able to obtain the current value of the user program's stack pointer. Within a system call or a page fault generated by a user program, you can retrieve it from the rsp member of the struct intr_frame passed to syscall_handler() or page_fault(), respectively. If you depend on page faults to detect invalid memory access, you will need to handle another case, where a page fault occurs in the kernel. Since the processor only saves the stack pointer when an exception causes a switch from user to kernel mode, reading rsp out of the struct intr_frame passed to page_fault() would yield an undefined value, not the user stack pointer. You will need to arrange another way, such as saving rsp into struct thread on the initial transition from user to kernel mode.

Implement stack growth functionalities. To implement this, you first modify vm_try_handle_fault in vm/vm.c to identify the stack growth. After identifying the stack growth, you should make a call to vm_stack_growth in vm/vm.c to grow the stack. Implement the vm_stack_growth.

스택 확장 개요

  • 확장 가능한 스택 구현
  • 현재 스택의 크기는 4KB로 고정된 상태이다.
  • 현재 스택의 크기를 초과하는 주소에 접근이 발생했을 때, 유효한 스택 접근인지 세그멘테이션 폴트인지 판별하는 휴리스틱을 적용하도록 수정한다.
  • 확장 가능한 스택의 최대 크기가 8MB가 되도록 수정한다.

PintOS는 스택의 크기를 4KB로 고정한다.

스택 포인터(esp)가 스택 영역을 벗어나면 세그멘테이션 폴트가 발생한다.

확장 가능한 스택의 구현

최대 8MB까지 확장한다.

현재 스택 포인터로부터 grow limit 이내에 포함되는 접근은 유효한 스택 접근으로 간주하여 스택을 확장한다.

  • bool expand_stack(void *addr)
  • addr 주소를 포함하도록 스택을 확장한다.
  • bool handle_mm_fault(struct vm_entry *vme)
  • 스택 확장을 지원하도록 수정한다.

handle_mm_fault() 함수를 호출하여 페이지 할당 여부를 확인한다.

vm_entry 타입을 확인하여 VM_BIN, VM_FILE, VM_ANON 각 타입에 따라 스왑 과정을 실행한다.

스택 확장 과정을 추가한다.

스택 확장 가능 여부 결정 - page_fault()

STACK_HEURISTIC 휴리스틱을 적용하여 스택 확장 여부를 판단한다.

expand_stack()을 호출하여 스택을 확장한다.

스택 확장 함수 구현

  • bool expand_stack(void *addr)
  • addr 주소를 포함하도록 스택을 확장한다.
  • alloc_page()를 통해 메모리를 할당한다.
  • vm_entry의 할당 및 초기화한다.
  • install_page()를 호출하여 페이지 테이블을 설정한다.
  • 성공시 true를 리턴한다.

verify_stack() 함수 구현

  • verify_stack(void *sp)
  • sp 주소가 포함되어 있는지 확인한다.
  • sp 주소가 존재할 시 handle_mm_fault() 함수를 호출한다.

0개의 댓글