본문 바로가기
Programming/7. Device Driver

Windows 아키텍처 기초 - 5화 페이징 메커니즘

by S.W 2026. 5. 22.
Windows 커널 & 드라이버 시리즈 — 5화

페이징 메커니즘 — 가상 주소가 물리 주소로 변환되는 과정

📅 2026 ⏱ 읽기 약 13분 🏷 메모리 관리 / MMU
4화에서 "가상 주소는 물리 주소로 변환된다"고 했는데, 그 변환이 실제로 어떻게 일어나는지 이번 화에서 파헤쳐 볼게요. 페이지 테이블, PTE, TLB — 처음엔 낯선 단어들이지만, 한 번 개념이 잡히면 이후 메모리 관련 드라이버 코드가 훨씬 잘 읽혀요.

페이지(Page)란?

메모리는 페이지(Page)라는 단위로 관리됩니다. x86/x64에서 기본 페이지 크기는 4KB(4096 바이트)예요. 가상 메모리도, 물리 메모리도 모두 4KB 단위로 나뉘어 관리됩니다.

왜 4KB냐고요? 역사적 이유와 TLB 효율성의 균형점이 4KB라는 게 밝혀졌기 때문이에요. 너무 작으면 페이지 테이블 엔트리가 너무 많아지고, 너무 크면 내부 단편화가 심해지거든요.

💡 Large Page (2MB) 도 있어요 성능이 중요한 경우 Large Page(2MB) 또는 Huge Page(1GB)를 쓸 수 있어요. 드라이버에서는 MmAllocateLargePages()로 Large Page를 할당할 수 있습니다. TLB 히트율이 높아져서 메모리 집약적 작업에서 성능 향상이 있어요.

페이지 테이블 — 변환 표

가상 주소 → 물리 주소 변환은 페이지 테이블(Page Table)을 통해 이루어져요. 페이지 테이블은 간단히 말하면 "가상 페이지 번호 → 물리 페이지 번호" 매핑 표입니다.

x64에서는 4단계 페이지 테이블(4-Level Paging)을 사용해요:

  • PML4 (Page Map Level 4) — CR3 레지스터가 가리키는 최상위 테이블
  • PDPT (Page Directory Pointer Table)
  • PD (Page Directory)
  • PT (Page Table) — 최하위. 여기의 엔트리(PTE)가 최종 물리 주소를 담음

48비트 가상 주소는 다음과 같이 분해됩니다:

가상 주소 (48비트): [47:39] [38:30] [29:21] [20:12] [11:0] PML4 PDPT PD PT Page Offset 9 bits 9 bits 9bits 9bits 12 bits

CPU(MMU)는 이 인덱스들을 순서대로 따라가면서 최종 물리 주소를 찾아냅니다. 이 과정을 페이지 테이블 워크(Page Table Walk)라고 해요.

PTE — 페이지 테이블 엔트리

페이지 테이블의 각 엔트리를 PTE(Page Table Entry)라고 해요. 8바이트(64비트) 크기이며, 단순히 물리 주소만 담는 게 아니라 여러 플래그를 포함해요:

비트 이름 의미
0 Present (P) 1이면 물리 메모리에 있음, 0이면 스왑됨 또는 미할당
1 Read/Write (RW) 0이면 읽기 전용
2 User/Supervisor (US) 0이면 커널 모드만 접근 가능
5 Accessed (A) 이 페이지에 접근한 적 있으면 CPU가 자동으로 1로 설정
6 Dirty (D) 이 페이지에 쓴 적 있으면 1 — 스왑 아웃 시 디스크에 써야 함을 표시
63 No Execute (NX) 1이면 이 페이지의 코드 실행 불가 (DEP/NX 기능)
12~51 Physical Frame Number 물리 페이지의 주소 (12 왼쪽 시프트하면 물리 주소)

페이지 폴트(Page Fault) — 없는 페이지를 읽으면?

Present 비트가 0인 페이지에 접근하면 CPU가 페이지 폴트 예외(#PF, Interrupt 14)를 발생시켜요. OS의 페이지 폴트 핸들러가 이 예외를 받아서 다음 중 하나를 처리합니다:

  • 정상적 페이지 폴트 — 스왑 파일에서 페이지를 읽어와 물리 메모리에 올려놓고 재시도 → 앱은 모름
  • Demand Paging — 처음 할당 시 물리 메모리를 바로 안 줌. 실제로 접근하면 그때 할당
  • Copy-on-Write — fork() 등에서 공유 페이지에 쓰기 시도 시 새 물리 페이지 할당
  • 접근 위반 — 유저 모드에서 커널 페이지에 접근하거나, 없는 주소에 접근 → Access Violation 예외로 앱에 전달
⚠️ 드라이버에서의 페이지 폴트 높은 IRQL(인터럽트 수준)에서는 페이지 폴트 처리가 불가능해요. 그래서 DISPATCH_LEVEL 이상에서 Paged Pool을 접근하면 즉시 BSOD가 납니다. 이 부분은 14화(IRQL)에서 자세히 다뤄요.

TLB — 변환 캐시

4단계 페이지 테이블 워크는 매번 수행하면 메모리를 4번 읽어야 하는 셈이에요. 이 오버헤드를 줄이기 위해 CPU에는 TLB(Translation Lookaside Buffer)라는 캐시가 있어요.

TLB는 "이 가상 주소는 이 물리 주소"라는 변환 결과를 캐싱해 두었다가, 같은 주소가 다시 오면 페이지 테이블 워크 없이 바로 변환 결과를 돌려줍니다.

그런데 다른 프로세스로 컨텍스트 스위치가 일어나면, 이전 프로세스의 TLB 엔트리가 다 무효화되어야 해요. 이게 컨텍스트 스위치 비용의 상당 부분을 차지합니다.

WinDbg로 PTE 직접 보기

WinDbg 커널 디버거에서 아래 명령으로 특정 가상 주소의 PTE를 조회할 수 있어요:

; 가상 주소 0xFFFF...의 PTE 조회 !pte 0xffff800000000000 ; 출력 예시: ; VA ffff800000000000 ; PXE at FFFFF6FB7DBED800 PPE at FFFFF6FB7DB00000 PDE at FFFFF6FB60000000 PTE at FFFFF68000000000 ; contains 00000000`001AD063 contains 00000000`00246063 ... ; pfn 1ad ---DA--KWEV pfn 246 ---DA--KWEV ...

여기서 pfn은 Physical Frame Number, K는 커널만 접근 가능, W는 쓰기 가능을 의미해요.


✅ 5화 요약
  • 메모리는 4KB 페이지 단위로 관리됩니다.
  • x64는 4단계 페이지 테이블(PML4 → PDPT → PD → PT)로 가상→물리 주소 변환을 합니다.
  • PTE에는 물리 주소 외에 Present, RW, US, NX 등 다양한 플래그가 있습니다.
  • 없는 페이지에 접근하면 페이지 폴트가 발생하고 OS가 처리합니다.
  • TLB가 변환 결과를 캐싱해서 성능을 높여요. 컨텍스트 스위치 시 TLB가 플러시됩니다.
다음 화
6화 — 프로세스와 스레드 (커널 관점): EPROCESS, ETHREAD 구조체 해부 →

#페이징 #PageTable #PTE #TLB #페이지폴트