사용자 프로세스의 가상 페이지 접근을 제어하기 위해 페이지 테이블 엔트리에는 3개의 permission bit
인 SUP, READ, WRITE
가 존재함
사용자 모드로 동작하는 프로세스는 SUP 비트가 0인 페이지에만 접근 가능
MMU(Memory Management Unit)
는 페이지 테이블을 사용해서 가상 주소를 물리 주소로 변환
PTE(Page Table Entry)
를 통해 VPN(Virtual Page Number)
을 PPN(Physical Page Number)
으로 변환하고 여기에 VPO(Virtual Page Offset)
을 결합해서 물리 주소를 산출함 (Virtual Page Offset
은 Physical Page Offset
과 같음)
매번 PTE를 메인 메모리에서 찾으면 비용이 많이 들기 때문에 MMU는 PTE를 저장하는 캐시인 TLB(Translation Lookaside Buffer)
를 포함함
VPN은 TLBT(TLB tag)
와 TLBI(TLB index)
로 나누어져 TLB에서 PTE를 찾는 데 사용됨
가상 주소 공간의 일부만 사용함에도 전체 페이지 테이블을 메인 메모리에 상주시키는 것은 비효율적이므로 계층적 구조의 multi-level 페이지 테이블을 사용함
multi-level 페이지 테이블을 사용했을 때의 장점
1. 미할당 페이지에 대한 페이지 테이블은 존재하지 않아도 됨
2. level 1 페이지 테이블만 메인 메모리에 상주하고 나머지는 디스크에 스왑 인/아웃 가능
즉 메모리 사용이 더 효율적임
리눅스의 가상 주소 공간은 kernel virtual memory
와 process virtual memory
로 나누어짐
커널 가상 메모리에 매핑되는 페이지
1. 모든 프로세스에 의해 공유되는, 커널 코드와 전역 자료구조가 저장된 물리 페이지
2. 전체 물리 페이지 (연속적인 가상 주소 공간에 매핑됨, 커널이 물리 메모리의 특정 위치에 접근할 수 있는 기능 제공)
3. 프로세스마다 다른 정보를 가지는 페이지 (페이지 테이블, 커널 스택, 가상 주소 공간의 현재 상태를 추적하는 다양한 자료구조 등)
리눅스는 가상 메모리를 여러 개의 area
(또는 segment
)로 구성함
각 area는 연속적이고 할당된(allocated) 가상 메모리로 해당 area 내 페이지는 연관되어 있음
code segment, data segment, heap, shared library, user stack 등은 모두 서로 다른 area임
커널 자료구조인 task_struct
의 element들은 커널이 프로세스를 실행하기 위해 필요한 모든 정보(PID, 유저 스택에 대한 포인터, 실행 파일 이름, PC 등)를 저장하거나 가리킴
task_struct의 필드인 mm
은 mm_struct
자료구조를 가리키는데 이는 가상 메모리의 현재 상태
를 나타냄
mm_struct의 필드 중 pgd
는 level 1 페이지 테이블의 시작 주소
를 저장하고(커널이 프로세스를 실행할 때 pgd를 CR3 제어 레지스터(페이지 테이블 베이스 레지스터)
에 저장함), mmap
은 현재 가상 주소 공간의 area
를 나타내는 vm_area_struct
자료구조의 리스트를 가리킴
MMU가 페이지 폴트를 발생시키면 커널의 페이지 폴트 핸들러는 다음과 같이 동작함
1. vm_area_struct의 리스트를 통해 가상 주소가 legal한지 확인함, 유효하지 않다면 segmentation fault
를 발생시킴 (프로세스에게 SIGSEGV 시그널을 보내고, 이는 프로세스를 종료시킴)
2. 메모리 접근이 legal한지(프로세스가 해당 area에 속한 페이지에 대해 접근 권한이 있는지) 확인하고, 아니라면 protection exception
을 발생시키는데, 이는 프로세스를 종료시킴
3. legal한 가상 주소에 대한 legal한 operation에 의해 페이지 폴트가 발생한 것이므로, 커널은 victim page를 선택하고, dirty page라면 스왑 아웃하고, 새로운 페이지를 스왑 인하고, 페이지 테이블을 업데이트함, 페이지 폴트 핸들러가 리턴할 때 CPU는 faulting instruction을 재실행함