기존에는 스택이 USER_STACK에서 시작하는 단일 페이지로 4KB로 제한하여 실행했다. 이제부터는 stack growth를 통해 스택이 초과하면 필요에 따라 추가 페이지를 할당하여야 한다.
USER_PROGRAM은 스택 포인터(rsp) 아래를 사용할 경우 버그가 발생하였다.
-> 일반적인 실제 os가 스택의 데이터를 수정하는 시그널을 전달하기 위해 언제든지 프로세스를 중단할 수 있기 때문이다.
하지만 x86-64 push 명령어는 스택 포인터를 조정하기 전 접근 권한을 검사하므로 stack pointer 아래 8바이트에 대해 page fault를 발생시킬 수 있다.
USER_PROGRAME은 스택 포인터의 현재 값을 얻을 수 있어야 한다.
intr_frame
의 rsp를 검색하면 된다. USER모드에서 KERNEL모드로 전환 시 rsp를 struct thread에 저장하는 방법 등을 사용해야 한다.
[!seealso]
대부분의 OS에서 스택의 크기는 제한되어 있다. GNU/linux는 기본 제한은 8MB이고 우리가 사용하는 pintos의 경우 1MB로 제한되어있다.
메모리 맵 파일은 운영 체제에서 파일을 다루는 방법 중 하나이다. 물리 디스크 파일, 장치, 공유 메모리 객체와 같이 운영 체제에서 파일로 다루는 모든 대상에 대해서 사용 가능하며, 메모리 맵 파일을 통해 프로세스의 가상 메모리 주소 공간에 파일을 매핑한 뒤 가상 메모리 주소에 직접 접근하는 것으로 파일 읽기/쓰기를 대신한다.
read_bytes
변수는 do_mmap
함수의 매개변수인 length
값과 관련이 있다. length
는 매핑하려는 메모리 영역의 크기를 나타낸다. read_bytes
는 이 length
값으로 초기화되며, 매핑할 때까지 남은 읽기 바이트 수를 나타낸다.
변수 zero_bytes
는 파일을 매핑할 때 메모리 페이지의 끝에 필요한 패딩 또는 "제로" 바이트의 양을 결정하기 위해 메모리 매핑 컨텍스트에서 사용됩니다.
파일을 메모리 매핑할 때 파일의 내용은 일반적으로 시스템의 메모리 페이지 크기인 고정 크기 페이지로 나뉩니다. 그러나 파일 크기가 페이지 크기의 정확한 배수가 아닐 수 있으므로 끝에 부분 페이지가 표시됩니다.
'zero_bytes' 변수는 마지막 메모리 페이지를 채우는 데 필요한 남은 바이트 수를 나타냅니다. 예상 페이지 크기를 유지하기 위해 메모리 페이지에서 0으로 설정해야 하는 바이트 수를 나타냅니다.
offset
매개변수는 메모리 매핑 컨텍스트에서 매핑이 시작되어야 하는 파일 내의 시작 위치를 지정하는 데 사용됩니다.
파일을 메모리 매핑할 때 '오프셋'을 사용하면 메모리에 매핑할 파일 부분을 제어할 수 있습니다. 오프셋을 지정하여 전체 파일, 특정 범위를 매핑하거나 파일 내의 특정 위치에서 매핑을 시작하도록 선택할 수 있습니다.
Dirty bit은 해당 페이지가 변경되었는지 여부를 저장하는 비트이다. 페이지가 변경될 때마다 이 비트는 1이 되고, 디스크에 변경 내용을 기록하고 나면 해당 페이지의 dirty bit는 다시 0으로 초기화해야 한다. 즉, 변경하는 동안에 dirty bit가 1이 된다.
페이지 교체 정책에서 dirty bit이 1인 페이지는 디스크에 접근해 업데이트한 뒤 매핑을 해제해줘야 하기 때문에 비용이 비싸다. (디스크 한 번 갔다 와야 하니까). 따라서 페이지 교체 알고리즘은 dirty page 대신 변경되지 않은 상태인 깨끗한(?) 페이지를 내보내는 것을 선호한다. 이 경우는 그냥 swap out만 해주면 되니까.
해당 페이지가 물리 메모리에 매핑되어 있는지 아니면 swap out되었는지를 가리킨다. Swap in/out에서 더 다룰 것. present bit이 1이면 해당 페이지가 물리 메모리 어딘가에 매핑되어 있다는 말이며 0이면 디스크에 내려가(swap out)있다는 말이다. 이렇게 present bit이 0인, 물리 메모리에 존재하지 않는 페이지에 접근하는 과정이 file-backed page에서의 page fault이다.
mmapp
에 대한 호출이 실패