Skip to content

- week09 - Virtual Memory {pintos} {swjungle}#

Stack Growth#

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

x86-64 아키텍처는 PUSH 명령으로 함수호출시 항상 스택 포인터 아래 8바이트의 공간을 먼저 참조를 시도하여 해당 주소가 접근 가능한지 여부를 검사한다고. 

다음 문단이 엄청 중요한 것 같은데 이해가 잘 되지 않는다.

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.

시스템 콜, 유저 프로그램에서 발생한 page fault에서 intr_frame::rsp에서 스택 포인터를 가져올 수 있다는 점을 설명하고 있다. 그런데 유효하지 않은 메모리 접근을 감지하기 위해 page fault에만 의존하게 된다면 커널 안에서 발생하는 page fault를 처리해야 한다고 한다. 프로세서는 rsp를 유저모드에서 커널모드로 넘어갈 때에만 저장하기 때문에 page_fault 인자 f를 통해 rsp를 읽는다면 정의되지 않은 값을 읽을 수도 있게된다.

아, 이런 케이스가 있을 수도 있겠구나, 유저가 시스템 콜 함수의 인자로 유효하지 않은 주소를 전달한다. ⟶ 커널모드로 전환이 된 후에 주소값을 참조하려다 page fault가 발생한다. ⟶ 당연하겠지만 rsp는 커널 스레드의 스택일 것이다.

  • [?] 그런데, 그냥 CR2 레지스터가 담고있는 fault_addr만 잘 참조하면 되는거 아닌가? 굳이 thread::user_rsp 이런거 저장할 필요가 있을까?

    gpt answer:

    CR2 레지스터는 페이지 폴트가 발생한 주소를 가리키지만, 이 주소는 주로 유저 모드에서의 주소입니다. 따라서 커널 모드에서 페이지 폴트가 발생하면 CR2 레지스터에는 유저 스택 주소가 아닌 커널 주소가 들어갈 수 있습니다. 이런 경우, 커널은 유저 스택에 접근해야 하는 시나리오에서는 rsp (유저 스택 포인터)를 활용하여 정확한 유저 스택 주소를 얻는 것이 중요합니다.

    추론단계: CR2 레지스터는 폴트가 난 유저랜드 가상주소를 저장하고 있어야 한다. rsp 레지스터는 CALL마다 초기화되는 스택 관리용 레지스터이기에, 유저모드이던, 커널모드이던 항상 실행중인 콜스택의 바닥을 저장하고 있어야 한다.. 시스템 콜 호출로 인해서 실행흐름이 커널모드가 된 상태에서 폴트가 난 경우, CR2 레지스터는 폴트가 발생한 위치를 가리키지만 RSP 레지스터는 마지막으로 커널영역의 위치를 가리키지 않을까?

Implement stack growth functionalities.#

vm_try_handle_fault 안에서 stack growth 상황을 식별한 뒤 vm_stack_growth 함수를 호출하라.

For this project, you should limit the stack size to be 1MB at maximum.
PintOS는 스택 최대크기를 1MB로 만들어야 한다.