Post

Intel 4-level paging

Intel 4-level paging

해당 글에서는 Intel x86-64 프로세서에서 가상 주소가 물리 주소로 변환되는 상세과정을 리뷰합니다.

가상 메모리는 다음과 같이 4단계를 거쳐서 물리 메모리 주소로 변환되며, 이러한 과정을 Intel 4-level paging이라고 표현합니다.

DirBase (DirectoryTableBase)

가장 먼저 참조되는 메모리는 DirBase 입니다. PML4 테이블의 물리 주소를 가리키며, 해당 주소는 Control Register의 CR3하고 동일합니다.

CR3는 프로세스 컨텍스트가 전환될 때 함께 변경되며, windbg에서는 다음과 같은 명령을 통해 확인 가능합니다.

1
2
3
4
5
// (Kernel mode only) Displays the control registers, for example CR0, CR2, CR3 and CR8.
14: kd> rm 0x80
14: kd> r
cr0=0000000080050033 cr2=fffff60278a90fe8 cr3=0000000253ef0000
cr8=0000000000000000
1
2
14: kd> r cr3
cr3=0000000253ef0000

해당 값은 PCB->DirectoryTableBase에 저장되어 있습니다.

1
2
3
4
5
6
14: kd> dt_eprocess ffffdf02ec514080 -r1
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
      +0x000 Header           : _DISPATCHER_HEADER
      +0x018 ProfileListHead  : _LIST_ENTRY [ 0xffffdf02`ec514098 - 0xffffdf02`ec514098 ]
      +0x028 DirectoryTableBase : 0x00000002`53ef0000

다음과 같이 !process 명령을 통해서도 쉽게 확인 가능합니다.

1
2
3
4
5
14: kd> !process 0 0 dwm.exe
PROCESS ffffdf02ec514080
    SessionId: 2  Cid: 20f4    Peb: 14a7356000  ParentCid: 2278
    DirBase: 253ef0000  ObjectTable: ffffc7899afec040  HandleCount: 2719.
    Image: dwm.exe

PML4E (Page Map Level-4 Entry)

다음으로는 PML4 테이블(DirBase)을 참조하여 PML4E 주소를 구합니다. 인덱스는 가상 주소의 47:39번째 비트에 해당합니다.

windbg에서는 다음과 같은 명령을 통해 확인이 가능합니다. 해당 덤프 파일에서 PML4E의 인덱스 값은 011111111이며, Hex 값으로 변환 시 0xFF에 해당합니다.

1
2
3
4
5
6
7
8
9
10
11
14: kd> .formats 00007ff7`63e90000
Evaluate expression:
  Hex:     00007ff7`63e90000
  Decimal: 140700509863936
  Decimal (unsigned) : 140700509863936
  Octal:   0000003777354372200000
  Binary:  0000000000000000 *011111111 111011101100011111010010000000000000000
  Chars:   ...c...
  Time:    Wed Jun 13 05:20:50.986 1601 (UTC + 9:00)
  Float:   low 8.59618e+021 high 4.59051e-041
  Double:  6.95153e-310

64비트 운영체제에서는 주소 크기가 8바이트에 해당하므로, 다음과 같이 테이블을 참조하여 PML4E 값을 구합니다. 현재 샘플에서 구한 PML4E 값은 0x253ef07f8 입니다.

1
2
14: kd> dq /p 253ef0000+(0xFF*8) L? 1
00000002`53ef07f8  0a000007`871fc867

해당 주소에서 사용되는 실제 값은 13:51번째 비트에 해당합니다. 페이즈 크기만큼(0x1000) 곱하면 PDP 테이블의 물리 주소가 됩니다. 현재 샘플에서 구한 PDP 테이블의 물리 주소는 0x7871fc000 입니다.

PDPE (Page Directory Pointer Entry)

다음으로 PDP 테이블 내에서 인덱스 값을 참조하여 PDPE을 구합니다. 마찬가지로 가상 주소 내에 인덱스 값이 포함되어 있으며 38:30번째 비트에 해당합니다.

1
2
3
4
5
6
7
8
9
10
11
14: kd> .formats 00007ff7`63e90000
Evaluate expression:
  Hex:     00007ff7`63e90000
  Decimal: 140700509863936
  Decimal (unsigned) : 140700509863936
  Octal:   0000003777354372200000
  Binary:  0000000000000000011111111 *111011101 100011111010010000000000000000
  Chars:   ...c...
  Time:    Wed Jun 13 05:20:50.986 1601 (UTC + 9:00)
  Float:   low 8.59618e+021 high 4.59051e-041
  Double:  6.95153e-310

수집된 덤프 파일에서는 PDPE 인덱스 값이 000111011101이며, Hex 값으로 변환시 0x1DD에 해당합니다.

다음과 같은 연산을 통해 PDPE 주소를 구합니다. 해당 값또한 실제로 사용되는 주소는 13:51번째에 해당하며, PD 테이블의 물리 주소가 저장되어 있습니다.

1
2
14: kd> dq /p 0x7871fc000+(0x1DD*8) L? 1
00000007`871fcee8  0a000007`a9efd867

PDE (Page Directory Entry)

PDE Index는 가상 주소의 29:21번째 비트에 해당합니다. 수집된 덤프에서는 100011111이며, Hex로 변환 시 0x11F입니다.

1
2
3
4
5
6
7
8
9
10
11
14: kd> .formats 00007ff7`63e90000
Evaluate expression:
  Hex:     00007ff7`63e90000
  Decimal: 140700509863936
  Decimal (unsigned) : 140700509863936
  Octal:   0000003777354372200000
  Binary:  0000000000000000011111111111011101 *100011111 010010000000000000000
  Chars:   ...c...
  Time:    Wed Jun 13 05:20:50.986 1601 (UTC + 9:00)
  Float:   low 8.59618e+021 high 4.59051e-041
  Double:  6.95153e-310

다음과 같이 연산하여 PDE의 주소를 구합니다. 해당 샘플에서 PDE의 주소는 0x7a9efd8f8이며, PT 테이블의 주소는 0x7917fe000 입니다.

1
2
14: kd> dq /p 7a9efd000+(0x11F*8) L? 1
00000007`a9efd8f8  0a000007`917fe867

PTE (Page Table Entry)

PTE Index는 가상 주소의 20:12번째 비트에 해당합니다. 수집된 덤프에서는 010010000이며, Hex로 변환 시 0x90입니다.

1
2
3
4
5
6
7
8
9
10
11
14: kd> .formats 00007ff7`63e90000
Evaluate expression:
  Hex:     00007ff7`63e90000
  Decimal: 140700509863936
  Decimal (unsigned) : 140700509863936
  Octal:   0000003777354372200000
  Binary:  0000000000000000011111111111011101100011111 *010010000 000000000000
  Chars:   ...c...
  Time:    Wed Jun 13 05:20:50.986 1601 (UTC + 9:00)
  Float:   low 8.59618e+021 high 4.59051e-041
  Double:  6.95153e-310

PTE는 다음과 같은 구조이며, 12:50 비트에 가상 메모리의 물리 주소가 저장되어 있습니다.

또한 1비트에는 Read/Write 권한이, 63비트에는 Execute 권한이 저장되어 있습니다.

다음과 같이 연산하여 PTE 주소를 구합니다. 해당 샘플에서 PTE의 주소는 0x7917fe480 입니다.

1
2
14: kd> dq /p 7917fe000+(0x90*8) L? 1
00000007`917fe480  81000008`14c3c025

해당 샘플에서 실제 메모리가 저장된 물리 주소는 00000000000000100000010100110000111100이며, Hex로 변환 시 0x814C3C입니다.

1
2
3
4
5
6
7
8
9
10
11
14: kd> .formats 81000008`14c3c025
Evaluate expression:
  Hex:     81000008`14c3c025
  Decimal: -9151314408108736475
  Decimal (unsigned) : 9295429665600815141
  Octal:   1004000000402460740045
  Binary:  10000001000000 *00000000000000100000010100110000111100 000000100101
  Chars:   .......%
  Time:    ***** Invalid FILETIME
  Float:   low 1.97658e-026 high -2.35099e-038
  Double:  -7.29118e-304

페이지 크기(0x1000)만큼 곱하여, 해당 위치에 메모리를 확인해보면 가상 메모리와 동일한 것을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
14: kd> db /p 0x814C3C000
00000008`14c3c000  4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00  MZ..............
00000008`14c3c010  b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00  ........@.......
00000008`14c3c020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00000008`14c3c030  00 00 00 00 00 00 00 00-00 00 00 00 00 01 00 00  ................
00000008`14c3c040  0e 1f ba 0e 00 b4 09 cd-21 b8 01 4c cd 21 54 68  ........!..L.!Th
00000008`14c3c050  69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f  is program canno
00000008`14c3c060  74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20  t be run in DOS 
00000008`14c3c070  6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00  mode....$.......
1
2
3
4
5
6
7
8
9
14: kd> db 00007ff763e90000
00007ff7`63e90000  4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00  MZ..............
00007ff7`63e90010  b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00  ........@.......
00007ff7`63e90020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00007ff7`63e90030  00 00 00 00 00 00 00 00-00 00 00 00 00 01 00 00  ................
00007ff7`63e90040  0e 1f ba 0e 00 b4 09 cd-21 b8 01 4c cd 21 54 68  ........!..L.!Th
00007ff7`63e90050  69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f  is program canno
00007ff7`63e90060  74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20  t be run in DOS 
00007ff7`63e90070  6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00  mode....$.......

!vtop

!vtop 명령어를 통해 변환 과정을 확인할 수 있으며, 위에서 직접 구한 모든 Entry 주소가 일치합니다.

1
2
3
4
5
6
7
8
14: kd> !vtop 253ef0000 00007ff763e90000
Amd64VtoP: Virt 00007ff763e90000, pagedir 0000000253ef0000
Amd64VtoP: PML4E 0000000253ef07f8
Amd64VtoP: PDPE 00000007871fcee8
Amd64VtoP: PDE 00000007a9efd8f8
Amd64VtoP: PTE 00000007917fe480
Amd64VtoP: Mapped phys 0000000814c3c000
Virtual address 7ff763e90000 translates to physical address 814c3c000.

4-Level Paging Linear Address Translation

정리하자면, 물리 주소 변환에 사용되는 가상 주소는 다음과 같은 구조로 이루어져있습니다.

Bit Position(s)Contents
47:39PML4E Index
38:30PDPE Index
29:21PDE Index
20:12PTE Index
11:0Page Offset

그리고, 참조되는 Entry 포맷은 다음과 같습니다.

50:12 비트에 물리 주소가 저장되어 있습니다.

Bit Position(s)Contents
50:12Physical Address

Intel 5-level paging

추가로, 최신 프로세서는 한단계 확장된 5-level panging 기술을 지원합니다.

기존에 사용되던 4-level paging에서 PML4와 유사한 PML5가 추가되었습니다.

PML5E (Page Map Level-5 Entry)

PML5E는 다음과 같은 구조이며, PML4E와 유사하며 더욱 큰 가상 주소 공간을 사용할 수 있습니다.

현재 테스트 환경에서는 PML5가 활성화되어있지 않기 때문에, 추후에 기회가 된다면 해당 부분도 리뷰해볼 예정입니다.

Reference

This post is licensed under CC BY 4.0 by the author.