🐧

【x86-64】メモリアドレス変換(セグメンテーション / ページング)

2024/09/13に公開

概要

Intel 64 アーキテクチャ もしくは IA-32 アーキテクチャのプロテクトモードにおけるメモリ管理は、(1) セグメンテーション (segmentation) と (2) ページング (paging) の2つの機構で構成される。

メモリ管理は、以下の 3 つの種類のメモリアドレス空間を変換することで行われる。

  • 論理アドレス (logical address)
  • リニアアドレス (linear address)
  • 物理アドレス (physical address)

セグメンテーションは論理アドレスからリニアアドレスの変換を、ページングはリニアアドレスから物理アドレスへの変換を担う。

+------------------+
| Logical Address  |
+--------+---------+
         |  Segmentation
         v
+------------------+
|  Linear Address  |
+--------+---------+
         |  Paging
         v
+------------------+
| Physical Address |
+------------------+

セグメンテーションは、デフォルトで有効化されており、無効化することはできない。
一方で、ページングは、デフォルトで無効化されており、オプションで有効化することができる。ページングが有効になっていない場合は、リニアアドレスは物理アドレスにそのままマッピングされる。

セグメンテーション

セグメンテーションとは、リニアアドレス空間 (linear address space) を、より小さな保護されたセグメント (segment) に分離する機構である。

 Linear Address Space
    +-----------+
    |           |
    |           |
    +-----------+
    | Segment 1 |
    |           |
    +-----------+
    |           |
    |           |
    |           |
    +-----------+
    | Segment 2 |
    +-----------+
    |           |
    +-----------+
    | Segment 3 |
    |           |
    |           |
    |           |
    +-----------+
    |           |
    +-----------+

複数のプログラムをプロセッサで実行する場合、それぞれのプログラムにセグメントの集合が割り当てられる。プログラムは、割り当てられたセグメントの範囲内のデータのみにアクセスすることが許可され、他のプログラムに割り当てられたセグメントに干渉しないようにすることができる。

全てのセグメントは、リニアアドレス空間内に含まれており、セグメント内の特定のバイトにアクセスするには、論理アドレス (別名: ファーポインタ (far pointer)) を指定する。論理アドレスは、以下の2つの要素で構成される。

  • セグメントセレクタ (segment selector): セグメントのユニークな指定子
  • オフセット (offset): アクセスしようとしているデータのセグメント内での位置
   Logical Address
   (or Far Pointer)
          |
    +-----+-----+
    |           |
    v           |
 Segment        v
 Selector     Offset
+-------+ +-------------+
|       | |             |
+-------+ +-------------+

セグメントセレクタは、ディスクリプタテーブル (descriptor table) のエントリへのオフセットとして利用される。ディスクリプタテーブルは、セグメントに関する情報を含んだセグメントディスクリプタ (segment descriptor) をエントリとして持つ。

   Logical Address
   (or Far Pointer)
          |
    +-----+-----+
    |           |
    v           |
 Segment        v
 Selector     Offset
+-------+ +-------------+
|       | |             |
+---+---+ +-------------+
    |
    | Global Descriptor
    |    Table (GDT)
    |  +-------------+
    |  |             |
    |  |             |
    |  +-------------+
    |  |   Segment   |
    |  |  Descriptor |
    +->+-------------+
       |             |
       |             |
       +-------------+

セグメントディスクリプタには、そのセグメントの開始リニアアドレスが含まれる。また、オフセットは、セグメント内の位置を指定するものであり、セグメントの開始リニアアドレスに加算されることで、リニアアドレスが計算される。

(リニアアドレス) = (セグメントの開始リニアアドレス) + (セグメント内のオフセット)
   Logical Address
   (or Far Pointer)
          |
    +-----+-----+               Linear Address
    |           |                    Space   
    v           |              +--------------+
 Segment        v              |              |
 Selector     Offset           |              |
+-------+ +------------+       |              |
|       | |            +-+     |              |
+---+---+ +------------+ |     |              |
    |                    |     |    Segment   |
    | Global Descriptor  |     +--------------+
    |    Table (GDT)     |     |              |
    |  +-------------+   |     |              |
    |  |             |   |     +--------------+
    |  |             |   |  +->|  Lin. Addr.  |
    |  +-------------+   +->|  +--------------+
    |  |   Segment   |      |  |              |
    |  |  Descriptor +------+->+--------------+
    +->+-------------+         |              |
       |             |         |              |
       |             |         |              |
       +-------------+         |              |
                               |              |
                               |              |
                               +--------------+

ページング

ページングが有効化されていない場合、リニアアドレスがそのまま物理アドレスとして使用される。物理アドレス空間は、プロセッサがアドレスバスに渡すことができるアドレスの範囲として定義される。

マルチタスクシステムでは、物理メモリ空間よりも大きなリニアアドレス空間を提供することがあり、これを実現するためにリニアアドレス空間を仮想化する方法が必要であり、ページングがこの仮想化の役割を果たす。

ページングは、仮想的な1つの大きなリニアアドレス空間を、物理メモリとディスクストレージを使って提供する。具体的には、リニアアドレス空間は、ページ (page) と呼ばれる連続する小さなメモリの塊 (設定可能だが、一般的には 4 KBytes) に分割され、それが物理メモリまたはディスクストレージのいずれかに保存される。OS は、それぞれのページが物理メモリまたはディスクストレージ上で、どの領域に保存されているかを保持するデータ構造を管理する。

ページを管理するためのデータ構造は、ページディレクトリ (page directory) やページテーブル (page table) と呼ばれるテーブルである。リニアアドレスのうちの一部はページディレクトリ内のエントリを指定するためのオフセットとして使用され、またリニアアドレスの別の部分はページテーブル内のエントリを指定するためのオフセットとして使用される。残りのビットは、ページ内における位置を指定するためのオフセットとして使用される。

 Linear Address                                              Physical Address
      Space                    Linear Address                      Space
+--------------+          +-------+-------+--------+          +-------------+
|              |  +------>|  Dir  | Table | Offset |          |             |
|              |  |       +---+---+---+---+----+---+          |    Page     |
|              |  |           |       |        +-------+      |- - - - - - -|
|              |  |           |       |    Page Table  |      |             |
|              |  |           |       |     +-------+  |      +-------------+
|    Segment   |  |  +--------+       |     |       |  |   +->| Phys. Addr. |
+--------------+  |  |                |     |       |  |   |  +-------------+
|              |  |  | Page Directory |     +-------+  +-->|  |             |
|              |  |  |   +-------+    |     | Entry +------+->|- - - - - - -|
+--------------+  |  |   |       |    |  +->+-------+         |             |
|  Lin. Addr.  +--+  |   +-------+    +->|  |       |         |             |
+--------------+     +-->| Entry +-------+->+-------+         |             |
|              |         +-------+                            |             |
+--------------+         |       |                            |             |
|              |         |       |                            |             |
|              |         +-------+                            |             |
|              |                                              |             |
|              |                                              |             |
|              |                                              |             |
|              |                                              |             |
+--------------+                                              +-------------+

アクセスしようとしているページが、物理メモリ内に存在しておらず、ディスクストレージに退避されていた場合、プロセッサはプログラムの実行を中断し、ディスクストレージから対応するデータを物理メモリ上に読み出し、その後にプログラムの実行を再開する。そのプログラムを中断するための例外を、ページフォルト (page fault) とよぶ。

この機能により、使用頻度が低くなっているデータを物理メモリ上からディスクストレージに退避し、物理メモリサイズ以上のメモリがあるかのように見せる (仮想化する) ことができ、これをスワッピング (swapping) と呼ぶ。さらに、ディスクストレージに保存されたファイルのデータも、実際にデータが必要になるまで物理メモリ上に読み込まないようにすることができ、これをデマンドローディング (demand loading) またはデマンドページング (demand paging) と呼ぶ。

なお、ページングはページ単位でさまざまな保護を設定可能であり、セグメントが提供するセグメント単位の保護の代わりに使用されることができます。

全体像

以上のことをまとめると、以下のようになる。

   Logical Address
   (or Far Pointer)
          |
    +-----+-----+               Linear Address                                              Physical Address
    |           |                    Space                    Linear Address                      Space
    v           |              +--------------+          +-------+-------+--------+          +-------------+
 Segment        v              |              |  +------>|  Dir  | Table | Offset |          |             |
 Selector     Offset           |              |  |       +---+---+---+---+----+---+          |    Page     |
+-------+ +------------+       |              |  |           |       |        +-------+      |- - - - - - -|
|       | |            +-+     |              |  |           |       |    Page Table  |      |             |
+---+---+ +------------+ |     |              |  |           |       |     +-------+  |      +-------------+
    |                    |     |    Segment   |  |  +--------+       |     |       |  |   +->| Phys. Addr. |
    | Global Descriptor  |     +--------------+  |  |                |     |       |  |   |  +-------------+
    |    Table (GDT)     |     |              |  |  | Page Directory |     +-------+  +-->|  |             |
    |  +-------------+   |     |              |  |  |   +-------+    |     | Entry +------+->|- - - - - - -|
    |  |             |   |     +--------------+  |  |   |       |    |  +->+-------+         |             |
    |  |             |   |  +->|  Lin. Addr.  |--+  |   +-------+    +->|  |       |         |             |
    |  +-------------+   +->|  +--------------+     +-->| Entry +-------+->+-------+         |             |
    |  |   Segment   |      |  |              |         +-------+                            |             |
    |  |  Descriptor +------+->+--------------+         |       |                            |             |
    +->+-------------+         |              |         |       |                            |             |
       |             |         |              |         +-------+                            |             |
       |             |         |              |                                              |             |
       +-------------+         |              |                                              |             |
                               |              |                                              |             |
                               |              |                                              |             |
                               +--------------+                                              +-------------+

|---------------------------------------|-------------------------------------------------------------------|
              Segmentation                                            Paging

アドレス変換の大まかな動作は上記の通りで、さらなる詳細が必要ない人はここで読むのをやめても問題ありません。

動作モードの概要

前提知識として、動作モードについて説明する。

Intel がサポートしている命令セット / アーキテクチャは、以下の 3 つが存在する。

  • IA-32 / Intel Architecture, 32-bit / i386
  • Intel 64 / x86-64 / x64 / AMD64
  • IA-64 / Intel Itanium Architecture

注意したいのは、IA-64 は確かに 64-bit プロセッサ向けの命令セットなのだが、既存の x86 命令セット (IA-32) と互換性がなく、現在は使われていません。つまり、32-bit x86 プロセッサは IA-32、64-bit x86 プロセッサは Intel 64 と考えても、基本的には差し支えありません。

IA-32 と Intel 64 では、以下の動作モードがサポートされています。

  • IA-32
    • リアルモード (real-address mode / real mode / 16-bit mode)
    • プロテクトモード (protected mode / 32-bit mode)
    • SMM (System Management Mode)
    • 仮想 8086 モード (virtual 8086 mode)
  • Intel 64
    • IA-32 がサポートしている全ての動作モード
    • IA-32e モード (long mode)
      • 互換モード (compatibility mode)
      • 64-bit モード (64-bit mode)

SMM および 仮想 8086 モードは、ここではあまり気にしなくて問題ありません。

注意したいのは、IA-32e モードの中に 2 つのサブモードが存在する点です。

ざっくりと、起動 / リセット時には、16-bit のリアルモードで開始し、段階的に 32-bit のプロテクトモードに、さらに IA-32e モードの 64-bit モードに遷移すると考えていただくと良いです。

互換モードは、IA-32e モードのまま、レガシーなプロテクトモード向けのプログラムが実行できるものと考えてください。

セグメンテーション

IA-32 アーキテクチャのプロテクトモードでのセグメンテーション

論理アドレス

論理アドレス (別名: ファーポインタ) は、16-bit のセグメントセレクタと 32-bit のオフセットで構成される。

論理アドレスからリニアアドレスへの変換は、以下のステップで行われる。

  1. セグメントセレクタの値を使用して、ディスクリプタテーブル内のセグメントディスクリプタの位置を特定し、セグメントディスクリプタの値を読み込む。
  2. セグメントディスクリプタの内容を検査して、セグメントへのアクセス権やセグメントの範囲のチェックなどを行う。
  3. セグメントディスクリプタ内に保存されているセグメントのベースアドレスに、論理アドレスのオフセットを加算して、リニアアドレスを計算する。

セグメントセレクタ

16-bit のセグメントセレクタは、以下のようなデータ構造である。

  • Bits 0-1: Requested Privilege Level (RPL)
    • セレクタの特権レベル (アドレス変換には関係ないので詳細は割愛) 。
  • Bit 2: Table Indicator (TI) フラグ
    • 使用するディスクリプタテーブルを指定する。
    • 0 のときは GDT (Global Descriptor Table)、1 のとき LDT (Local Descriptor Table) が使用される。
  • Bits 3-15: インデックス
    • GDT または LDT 内にある 8192 個のディスクリプタの1つを指定する。
    • インデックスの値に 8 をかけて、それを GDT または LDT のベースアドレスに加算することで、セグメントディスクリプタの位置を計算する。
    • 8 = 2^3 なので、インデックスの値に 8 をかける操作は、実際にはセグメントセレクタの下位 3 bit をマスクすることで計算できる。
 15                        3  2  1  0
+---------------------------+--+-----+
|           Index           |TI| RPL |
+---------------------------+--+-----+

セグメントレジスタ

プロセッサは6個のセグメントレジスタ (CS, SS, DS, ES, FS, GS) を提供している。各セグメントレジスタは、コード、スタック、データのいずれかのメモリ参照をサポートする。プログラムが実行される際には、最低でもコードセグメント (CS)、データセグメント (DS)、スタックセグメント (SS) に有効なセグメントセレクタを読み込む必要がある。その他の 3 つのセグメントレジスタ (ES, FS, GS) は、追加のデータセグメントとして使用できる。

各セグメントレジスタは、見える部分と隠された部分 (ディスクリプタキャッシュ (descriptor cache) または シャドーレジスタ (shadow register) とも呼ばれる) がある。見える部分には、セグメントセレクタが読み込まれる。隠された部分には、セグメントセレクタが指しているセグメントディスクリプタから、ベースアドレス、セグメントリミット、アクセス制御情報が読み込まれキャッシュされる。よって、マルチプロセッサ環境では、セグメントディスクプリタが更新された場合には、キャッシュを更新するためにセグメントレジスタをリロードする必要がある。

セグメントディスクリプタ

セグメントディスクリプタは、ディスクリプタテーブル (GDT および LDT) 内のエントリとして保存されるデータ構造で、セグメントのサイズや開始アドレス、アクセス制御情報などが含まれる。セグメントディスクリプタは、通常コンパイラ、リンカ、ローダー、OS などによって作成される。

 63                 56  55  54  53  52  51            48  47  46  45  44  43          40  39                          32
+-------------------------------+---+---+---+---+-----------------+---+-------+---+---------------+-------------------------------+
|       Base Address 31:24      | G |D/B| L |AVL| Seg. Lim. 19:16 | P |  DPL  | S |      Type     |       Base Address 23:16      |
+-------------------------------+---+---+---+---+-----------------+---+-------+---+---------------+-------------------------------+

 31                                                            16  15                                                          00
+-----------------------------------------------------------------+---------------------------------------------------------------+
|                       Base Address 15:00                        |                        Segment Limit 15:00                    |
+-----------------------------------------------------------------+---------------------------------------------------------------+
  • セグメントリミット (Segment Limit)
    • セグメントのサイズを指定する 20-bit の値。
    • G フラグの値で粒度が変わる。
      • 0 のとき、1 Byte 単位 (範囲: 1 Byte ~ 1 MBytes)。
      • 1 のとき、4 KBytes 単位 (範囲: 4 KBytes)。
    • セグメントの伸びる方向によって、解釈が変わる。
      • 上方向に伸びる (expand-up) データセグメントの場合、オフセットは 0 ~ セグメントリミット の間の値をとる。
      • 下方向に伸びる (expand-down) データセグメントの場合、オフセットは セグメントリミット + 1 ~ 0xFFFF_FFFF もしくは 0xFFFF (B フラグに依存) の間の値をとる。セグメントリミットの値を減らすことによって、スタック領域を広げることができる。
  • ベースアドレス (Segment base address)
    • 4-GByte リニアアドレス空間におけるセグメントの開始位置。
    • 最大のパフォーマンスを引き出すには、16-Byte 境界に整列されていることが好ましい。
  • タイプ (Type)
    • セグメントのタイプ、許可されるアクセスの種類、セグメントが伸びる方向を指す。(詳細は後述)
  • S フラグ (Descriptor type)
    • 0 のとき、システムセグメント (アドレス変換には関係ないので詳細は割愛) 。
    • 1 のとき、コードセグメントまたはデータセグメント。
  • DPL (Descriptor Privilege Level)
    • セグメントの特権レベル (アドレス変換には関係ないので詳細は割愛) 。
  • P フラグ (Segment present)
    • 0 のとき、セグメントがメモリに存在ない。セグメントレジスタに読み込まれると、segment-not-present 例外 (#NP) が生成される。
    • 1 のとき、セグメントがメモリに存在する。
  • D/B フラグ (Default operation size / default stack pointer size and/or upper bound)
    • セグメントが、コードセグメントか、下に伸びるデータセグメントか、スタックセグメントかで解釈が変わる。
    • コードセグメント
      • 0 のとき、16-bit アドレス、16-bit or 8-bit オペランド。
      • 1 のとき、32-bit アドレス、32-bit or 8-bit オペランド。
      • 命令プレフィックスとして 66H をつけると、デフォルトとは異なるオペランドサイズを使用できる。
      • 命令プレフィックスとして 67H をつけると、デフォルトとは異なるアドレスサイズを使用できる。
    • スタックセグメント (SS レジスタで指定されるデータセグメント)
      • 0 のとき、16-bit のスタックポインタ (SP レジスタに保持される)
      • 1 のとき、32-bit のスタックポインタ (ESP レジスタに保持される)
      • 下方向に伸びるように設定されている場合、スタックセグメントの上限値も制御する。
    • 下に伸びるデータセグメント
      • 0 のとき、上限は 64 KBytes (0xFFFF)
      • 1 のとき、上限は 4 GBytes (0xFFFF_FFFF)
  • G フラグ (Granularity)
    • 0 のとき、セグメントリミットは 1 Byte 単位。
    • 1 のとき、セグメントリミットは 4 KByte 単位。
  • L フラグ (64-bit code segment)
    • IA-32e モードにおいて、コードセグメントが 64-bit モードがどうかを示す。
    • 0 のとき、互換モードで実行される。
    • 1 のとき、64-bit モードで実行される。
  • AVL ビット (Available for use by system software)
    • システムソフトウェア (OS) が自由に利用できるビット。

コードセグメント / データセグメントのディスクリプタタイプ

セグメントディスクリプタの S フラグが 1 の場合、コードセグメントまたはデータセグメントのいずれかであり、タイプは以下のように決まる。

Decimal Bit 43 Bit 42 Bit 41 Bit 40 Descriptor Type Description
E W A
0 0 0 0 0 Data Read-Only
1 0 0 0 1 Data Read-Only, accessed
2 0 0 1 0 Data Read/Write
3 0 0 1 1 Data Read/Write, accessed
4 0 1 0 0 Data Read-Only, expand-down
5 0 1 0 1 Data Read-Only, expand-down, accessed
6 0 1 1 0 Data Read/Write, expand-down
7 0 1 1 1 Data Read/Write, expand-down, accessed
C R A
8 1 0 0 0 Code Execute-Only
9 1 0 0 0 Code Execute-Only, accessed
10 1 0 0 0 Code Execute/Read
11 1 0 0 0 Code Execute/Read, accessed
12 1 0 0 0 Code Execute-Only, conforming
13 1 0 0 0 Code Execute-Only, conforming, accessed
14 1 0 0 0 Code Execute/Read, conforming
15 1 0 0 0 Code Execute/Read, conforming, accessed
  • データセグメント
    • A (accessed): OS が最後にこのビットをクリアしてから、セグメントセレクタがロードされたかどうか。
    • W (write-enable): 書き込み可能かどうか。
    • E (expansion-direction): 下方向に伸びるか、上方向に伸びるか。
  • コードセグメント
    • A (accessed): OS が最後にこのビットをクリアしてから、セグメントセレクタがロードされたかどうか。
    • R (read-enable): 読み取り可能かどうか。
    • C (conforming): アドレス変換に関係しないため詳細は割愛。

スタックセグメントは、読み書き可能なデータセグメントである必要がある。動的にスタックサイズを変更したい場合、下方向に伸びるように設定することができる。

セグメントディスクリプタテーブル

セグメントディスクリプタテーブルには、以下の2種類がある。

  • グローバルディスクリプタテーブル (GDT: Global Descriptor Table)
  • ローカルディスクリプタテーブル (LDT: Local Descriptor Table)

上述の通り、セグメントディスクリプタのサイズは 8 (= 2^3) Bytes であり、セグメントディスクリプタテーブルは 8,192 (= 2^13) 個のセグメントディスクリプタを含むことができる (合計サイズは 2^16) 。

システムは1つの GDT を持つ必要があり、システム内の全てのプログラムから利用される。オプションで、1つ以上の LDT を定義することができる。

GDT 自体はセグメントではなく、リニアアドレス空間内のデータ構造である。GDT のベースリニアアドレスとリミットは、GDTR レジスタに読み込む必要がある。パフォーマンスを最大化するために、GDT のベースアドレスは 8-Byte 境界に整列することが好ましい。リミットの値はバイト単位で表現され、ベースアドレスにリミットの値を加算することで、GDT の最後のバイトのアドレスを計算することができる。セグメントディスクリプタのサイズは 8 Bytes なので、セグメントディスクリプタの数を N としたとき、リミットの値は 8 * N - 1 Bytes となる。

GDT の最初のディスクリプタは使用されず、ヌルディスクリプタ (null descriptor) として扱われる。

LDT は、リニアアドレス空間に直接配置される GDT とは異なり、セグメント内に配置される。より具体的には、以下の通り。GDT 内のセグメントディスクリプタの S フラグが 0 の場合、(コードセグメントやデータセグメントとは異なり) システムセグメントとなる。さらにそのシステムセグメントのタイプフィールドが LDT である場合 (Type = 0b0010) に、LDT セグメントとなる。その LDT セグメントには、LDT を配置することができる。システム内で複数の LDT を配置することができるが、それぞれの LDT ごと対応するセグメントディスクリプタを GDT に定義する必要がある。

        +--------------------+----------------------+
        |                    |                      |
        |                    v                      v
+-----+-++----+         GDT (TI = 0)           LDT (TI = 1)
|     |TI|    |       +--------------+       +--------------+
+-----+--+----+       |              |       |              |
Segment Selector      +--------------+       +--------------+
                      |              |       |              |
                      ~~~~~~~~~~~~~~~~       ~~~~~~~~~~~~~~~~
                      ~~~~~~~~~~~~~~~~       ~~~~~~~~~~~~~~~~
                      |              |       |              |
                      +--------------+       +--------------+
                      |              +-----+ |              |
                      +--------------+     | +--------------+
                      |  null desc.  |     | |              |
                      +--------------+<--+ | +--------------+<---+
                                         | |                     |
                                         | |                     |
                           GDTR          | |       LDTR          |
                             +-------+   | +->       +-------+   |
                             | Limit |   |           | Limit |   |
                      +------+-------+   |    +------+-------+   |
                      | Base Address +---+    | Base Address +---+
                      +--------------+        +-----------+--+
                                              | Seg. Sel. |
                                              +-----------+

Intel 64 アーキテクチャの IA-32e モードでのセグメンテーション

セグメントレジスタ

Intel 64 アーキテクチャの IA-32e モードでは、セグメンテーションは、現在の動作モードが互換モード (compatibility mode) か 64-bit モードであるかによって決まる。

互換モードで動作している場合、(IA-32 アーキテクチャの) プロテクトモードと同じように、セグメンテーションは機能する。

64-bit モードで動作している場合、セグメンテーションは一般的には (完全にではないが) 無効化されており、セグメントに分割されていないフラットな 64-bit のリニアアドレス空間を形成する。プロセッサは、セグメントレジスタ CS, DS, ES, SS のセグメントベースを 0 として扱う。ただし、一部のセグメントレジスタ FS および GS は例外であり、ローカルデータや OS のデータ構造にアクセスするためのリニアアドレス計算で、ベースアドレスを提供するものとして利用できる。セグメントレジスタに関しては後述する。なお、64-bit モードでは、実行時のセグメントの範囲チェックは行われない。

論理アドレス

Intel 64 アーキテクチャにおける IA-32e モード では、IA-32 アーキテクチャと同じアドレス変換のプロセスを利用する。

ただし、64-bit モードでは、論理アドレスのオフセット および セグメントのベースアドレスのサイズが 64-bit となる。したがって、リニアアドレスのサイズも同様に 64-bit になる。

セグメントディスクリプタテーブル

IA-32e モードでも、セグメントディスクリプタテーブルは 8-Byte ディスクリプタを最大 8192 個保持できる。システムディスクリプタは 16 Bytes に拡張される。

ページング

ソフトウェアは、MOV 命令で CR0.PG をセットすることで、ページングを有効にできる。ただし、プロテクトモードを有効にする CR0.PE (Proteciton Enable) がセットされている場合に限る。

ソフトウェアは、ページングを有効にするために、アドレス変換で使用されるデータ構造を初期化し、アドレス変換処理の最初に使用されるデータ構造の物理アドレスを CR3 レジスタに含めておく必要がある。

ページングモード

ページングが有効化されると、CR4.PAE (Physical Address Enable)、CR4.LA57 (57-bit Linear Address)、IA32_EFER.LME (IA-32e Mode Active) の値に基づいて、4 つのページングモードのいずれかが使用される。

  • プロテクトモード
    • 32-bit ページング (CR4.PAE = 0)
    • PAE ページング (CR4.PAE = 1 かつ IA32_EFER.LME = 0)
  • IA-32e モード
    • 4 レベルページング (CR4.PAE = 1 かつ IA32_EFER.LME = 1 かつ CR4.LA57 = 0)
    • 5 レベルページング (CR4.PAE = 1 かつ IA32_EFER.LME = 1 かつ CR4.LA57 = 1)

ページングモードは、それぞれ以下のような点で異なる。

  • リニアアドレスの大きさ
  • 物理アドレスの大きさ
  • ページの大きさ
  • 実行保護機能 (execute-disable access right) のサポート (アドレス変換に関係ないので詳細は割愛)
  • PCID のサポート (アドレス変換に関係ないので詳細は割愛)
  • プロテクションキー (protection keys) のサポート (アドレス変換に関係ないので詳細は割愛)
Paging Modfe CR0.PG CR4.PAE IA32_EFER.LME CR4.LA57 Lin. Addr. Width Phys. Addr. Width Page Size
None 0 N/A N/A N/A 32 32 N/A
32-bit 1 0 0 N/A 32 Up to 40 4 KB / 4 MB
PAE 1 1 0 N/A 32 Up to 52 4 KB / 2 MB
4-level 1 1 1 0 48 Up to 52 4 KB / 2 MB / 1 GB
5-level 1 1 1 1 57 Up to 52 4 KB / 2 MB / 1 GB

32-bit ページングと PAE ページングはレガシーなプロテクトモードで使用され、レガシーなプロテクトモードは 32-bit より大きなリニアアドレスを生成できないので、これらは 32-bit リニアアドレスを変換する。

4 レベルページングと 5 レベルページングは IA-32e モードでのみ使用される。

  • 互換モード: 32-bit リニアアドレスを使用し、Bits 63:32 は 0 として解釈される。
  • 64-bit モード: プロセッサは標準化を強制する。4 レベルページングでは Bits 63:47 が同一 (全て 0 または 全て 1) であり、5 レベルページングでは Bits 63:56 が同一 (全て 0 または 全て 1) である。

物理アドレス空間

物理アドレス空間のビットサイズは、CPUID.80000008H:EAX[0:7] で定義されている。
CPUID leaf 80000008H 自体がサポートされていない場合、CPUID.01H:EDX.PAE [bit 6] = 1 のとき 36 bits (64 GBytes)、CPUID.01H:EDX.PAE [bit 6] = 0 のとき 32 bits (4 Gbytes) である。

物理アドレス空間のビットサイズを MAXPHYADDR と呼ぶ。

階層的なページング構造体

いずれのページングモードでも、階層的なページング構造体 (hierarchical paging structure) を使って、アドレス変換を行う。

各ページング構造体は 4096-Byte のサイズを持ち、複数のエントリから構成される。32-bit ページングでは、エントリの大きさは 32 bits (4 Bytes) で、合計 1024 個のエントリで構成される。それ以外のページングモードでは、エントリの大きさは 64 bits (8 Bytes) で、合計 512 個のエントリで構成される。

プロセッサは、リニアアドレスの上位ビットを利用して、ページング構造体内のエントリを特定する。最後のレベルのエントリでは、物理アドレス空間上のメモリ領域が特定され、これをページフレーム (page frame) と呼ぶ。リニアアドレスの下位ビットは、ページオフセット (page offset) と呼ばれ、ページ内での相対的な位置を指す。

各ページング構造体は物理アドレスを含んでおり、これは別のページング構造体のアドレスまたはページフレームのアドレスを指す。

ページングは、CR3 レジスタに保存された物理アドレスに配置されたページング構造体から変換処理が始まる。反復的な処理を通して、リニアアドレスは物理アドレスに変換されていく。リニアアドレスの上位アドレスビット列をインデックスとして使用して、ページング構造体内のエントリを特定する。そのエントリが別のページング構造体を指している場合は、同様にリニアアドレスの次に上位のアドレスビット列をインデックスとして使用して、次のページング構造体内のエントリを特定する。エントリが実際のページを指している場合は、オフセットを追加して、物理アドレスを得ることができる。

ページサイズが 4 KBytes の場合、それぞれのページングモードで以下のようにリニアアドレスは利用される。

  • 32-bit ページング
    • 各ページング構造体は、1024 (= 2^10) 個のエントリで構成され、32-bit リニアアドレスの 10 bits をアドレス変換に用いる。
    • 最初のページング構造体で Bits 31:22 を使い、次のページング構造体で Bits 21:12 を使用する。残りの Bits 11:0 はページ内オフセットとして使用する。
  • PAE ページング
    • 最初のページング構造体では、4 (=2^2) 個のエントリで構成され、Bits 31:30 が使用される。
    • 残りのページング構造体では、9 bits ずつ Bits 29:21、Bits 20:12 が使用され、残りの Bits 11:0 がページ内オフセットとなる。
  • 4 レベルページング
    • 各ページング構造体は 512 (=2^9) 個のエントリで構成され、48-bit リニアアドレスの上から Bits 47:39、Bits 38:30、Bits 29:21、Bits 20:12 が順に利用され、残りの Bits 11:0 はページ内オフセットとして利用される。
  • 5 レベルページング
    • 4 レベルページングとほぼ同様の動作をし、48-bit リニアアドレスに 9 bits 増えた 57-bit リニアアドレスが利用される。

ページング構造体を階層的に辿っていくことをページウォーク (page walk) または ページテーブルウォーク (page table walk) と呼ぶ。

最終的にページフレームを特定するまでの間で、このページテーブルウォークが中断される場合があり、これをページフォルト (page fault) と呼ぶ。ページフォルトは、辿ったページング構造体のエントリで "not present" ビット (P フラグ) が 0 の場合 または 予約ビット (reserved bit) がセットされている場合に発生し、ページフォルト例外が生成される。

ページング構造体のエントリが、別のページング構造体を指しているかどうかは、以下のように判定される (ページサイズが 4 KBytes の場合)。

  • まだ使用されていないリニアアドレスが 12 bits よりも多く残っており、現在のページング構造体のエントリで PS フラグ (bit 7) が 0 であれば、別のページング構造体を指していることになる。PS フラグが 1 である場合は、そのエントリはページフレームへマッピングされていることを意味する。
  • 使用されていないリニアアドレスが 12 bits である場合は、現在のページング構造体のエントリは常にページフレームへマップされている。

ページング構造体は、以下のような名前がつけれらている。

Paging Structure Entry Name
PML5 table PML5E
PML4 table PML4E
Page-directory-pointer table PDPTE
Page directory PDE
Page table PTE

ページング構造体の詳細

以下の表は、異なるページングモードで共通するフィールドを、ざっくりまとめたものである。
アドレス変換に関連するものは、P フラグと PS フラグくらいなのであまり気にしすぎる必要はない。

Bit Description
P Present; ページが現時点で物理メモリに存在するかどうか。例えば、ページがディスクストレージに退避されている場合に 0 にする。
R/W Read/Write; 1 の場合、読み書き可能。0 の場合、読み取りのみ。
U/S User/Supervisor; 1 の場合、どの特権レベルからでもアクセス可。0 の場合、スーパーバイザのみがアクセス可。
PWT Page-level Write-Through; 1 の場合、write-through caching が有効。0 の場合、write-back caching が有効。
PCD Page-level Cache Disable; 1 の場合、ページはキャッシュされない。0 の場合、キャッシュされる。
A Accessed; アドレス変換の過程でエントリがアクセスされたかどうか。
D Dirty; ページに対して書き込みが行われたかどうか。
PS Page Size; 1 の場合、そのエントリがページフレームを指している。0 の場合、別のページング構造体を指している。
G Global; CR3 に MOV 命令を実行した場合に TLB エントリを無効化しない。グローバルページを有効にするために CR4.PGE = 1 にしている必要がある。
PAT Page Attribute Table; PAT がサポートされている場合に、PWT / PCD と組み合わせてメモリキャッシュの挙動が決まる。
XD Execute-disable; EFER.NXE = 1 のとき、このページ内のアドレスにある命令を実行することができない。

32-bit ページング

 31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10  09  08  07  06  05  04  03  02  01  00
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                           Address of page directory                           |           Ignored         |PCD|PWT|  Ignored  | CR3
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|Bits 31:22 of address of 4MB page frame|      Reserved     |  Bits 39:32   |PAT|  Ignored  | G | 1 | D | A |PCD|PWT|U/S|R/W| 1 | PDE: 4MB page
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                             Address of page table                             |    Ignored    | 0 |Ign| A |PCD|PWT|U/S|R/W| 1 | PDE: page table
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                          Ignroed                                                          | 0 | PDE: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                           Address of 4KB page frame                           |  Ignored  | G |PAT| D | A |PCD|PWT|U/S|R/W| 1 | PTE: 4KB page
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                          Ignored                                                          | 0 | PTE: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

PAE ページング

 63  62  61  60  59  58  57  56  55  54  53  52  51  ..  M   M-1 ..  31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10  09  08  07  06  05  04  03  02  01  00
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                            Ignored                                |                            Address of page-directory pointer table                                        |      Ignored      | CR3
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                         Reserved                          |                        Address of page directory                                      |  Ignored  |   Reserved    |PCD|PWT| Rsrvd | 1 | PDPTE: present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                                                      Ignored                                                                                                  | 0 | PDPTE: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |                       Reserved                        |             Address of 2MB page frame             |          Reserved             |PAT|  Ignored  | G | 1 | D | A |PCD|PWT|U/S|R/W| 1 | PDE: 2MB page
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |                       Reserved                        |                                  Address of page table                                |    Ignored    | 0 |Ign| A |PCD|PWT|U/S|R/W| 1 | PDE: page table
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                                                      Ignored                                                                                                  | 0 | PDE: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |                       Reserved                        |                                Address of 4KB page frame                              |  Ignored  | G |PAT| D | A |PCD|PWT|U/S|R/W| 1 | PTE: 4KB page
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                                                      Ignored                                                                                                  | 0 | PTE: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

4 レベルページング / 5 レベルページング

 63  62  61  60  59  58  57  56  55  54  53  52  51  ..  M   M-1 ..  31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10  09  08  07  06  05  04  03  02  01  00
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                          Reserved                         |                            Address of PML4 table or PML5 table                        |          Ignored          |PCD|PWT|  Ignored  | CR3
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |                 Ignored                   | Reserved  |                                    Address of PML4 table                              | R |  Ignored  |Rsv|Ign| A |PCD|PWT|U/S|R/W| 1 | PML5E: present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                                                      Ignored                                                                                                  | 0 | PML5E: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |                 Ignored                   | Reserved  |                          Address of page-directory-pointer table                      | R |  Ignored  |Rsv|Ign| A |PCD|PWT|U/S|R/W| 1 | PML4E: present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                                                      Ignored                                                                                                  | 0 | PML4E: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |Protection Key |         Ignored           | Reserved  |Addr. of 1GB PF|                              Reseverd                             |PAT| R |Ignored| G | 1 | D | A |PCD|PWT|U/S|R/W| 1 | PDPTE: 1GB page
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |                 Ignored                   | Reserevd  |                                  Address of page directory                            | R |  Ignored  | 0 |Ign| A |PCD|PWT|U/S|R/W| 1 | PDPTE: page directory
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                                                      Ignored                                                                                                  | 0 | PDPTE: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |Protection Key |         Ignored           | Reserved  |            Address of 2MB page frame              |           Reserved            |PAT| R |Ignored| G | 1 | D | A |PCD|PWT|U/S|R/W| 1 | PDE: 2MB page
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |                 Ignored                   | Reserved  |                                    Address of page table                              | R |  Ignored  | 0 |Ign| A |PCD|PWT|U/S|R/W| 1 | PDE: page table
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                                                      Ignored                                                                                                  | 0 | PDE: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|XD |Protection Key |         Ignored           | Reserved  |                                  Address of 4KB page frame                            | R |Ignored| G |PAT| D | A |PCD|PWT|U/S|R/W| 1 | PTE: 4KB page
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                                                                                      Ignored                                                                                                  | 0 | PTE: not present
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
GitHubで編集を提案

Discussion