x86ページングは​​どのように機能しますか?


90

この質問は、主題に関する優れた無料情報の空白を埋めることを目的としています。

私は良い答えが1つの大きなSOの答え、または少なくともいくつかの答えに収まると信じています。

主な目標は、完全な初心者に十分な情報を提供して、自分でマニュアルを読み、ページングに関連するOSの基本的な概念を理解できるようにすることです。

推奨ガイドライン:

  • 答えは初心者に優しいはずです:
    • 具体的ですが、おそらく単純化された例が非常に重要です
    • 示された概念の適用は大歓迎です
  • 有用なリソースを引用することは良いことです
  • OSがページング機能をどのように使用するかについての小さな余談は大歓迎です
  • PAEおよびPSEの説明は大歓迎です
  • x86_64への小さな余談は大歓迎です

関連する質問と、なぜ私はそれらが偽物ではないと思うのか


1
これには「faq」というタグを付け、「community-wiki」とマークする必要があります。
Kerrek SB 2013

@KerrekSB私はこの種の質問をどうやって管理するか本当に知りません。答えはコミュニティウィキである必要があるということですか?faqタグが見つかりませんでした。
Ciro Santilli郝海东冠状病六四事件法轮功

3
簡単に言えば、「第3巻、第4章:インテルマニュアルのページング」を読んでください。それはかなり明確で簡潔でよく書かれていて、それ以上の権威はありません。
Kerrek SB 2013

4
@KerrekSBマニュアルは明確で信頼できるものだと私は同意しますが、最初に読んだときは少し厳しすぎたので、物事をよりよく理解するための簡単で具体的な例と根拠が必要でした。
Ciro Santilli郝海东冠状病六四事件法轮功

回答:


142

目次と内容が充実したこの回答のバージョン

報告されたエラーを修正します。大規模な変更を加えたり、不足している部分を追加したりする場合は、自分の答えに基づいて変更を加え、適切な担当者に依頼してください。小さな編集は直接マージできます。

サンプルコード

最小限の例:https : //github.com/cirosantilli/x86-bare-metal-examples/blob/5c672f73884a487414b3e21bd9e579c67cd77621/paging.S

プログラミングの他のすべてと同様に、これを本当に理解する唯一の方法は、最小限の例で遊ぶことです。

これを「難しい」主題にするのは、独自の小さなOSを作成する必要があるため、最小限の例が大きいということです。

Intelマニュアル

例がないと理解することはできませんが、できるだけ早くマニュアルに慣れるようにしてください。

Intelは、Intel Manual Volume 3システムプログラミングガイド-325384-056US 2015年9月の第4章「ページング」でページングについて説明しています。

特に興味深いのは、主要なデータ構造を示す図4-4「32ビットページングを使用したCR3およびページング構造エントリのフォーマット」です。

MMU

ページングは、CPU のメモリ管理ユニット(MMU)部分によって行われます。他の多くのように(例えば x87コプロセッサAPIC)、これは初期の頃は個別のチップでしたが、後でCPUに統合されました。しかし、この用語はまだ使用されています。

一般的な事実

論理アドレスは、「通常の」ユーザーランドコードで使用されるメモリアドレスです(たとえば、 rsimov eax, [rsi])。

最初のセグメンテーションはそれらを線形アドレスに変換し、次にページングは​​線形アドレスを物理アドレスに変換します。

(logical) ------------------> (linear) ------------> (physical)
             segmentation                 paging

ほとんどの場合、物理アドレスは実際のRAMハードウェアメモリセルにインデックスを付けると考えることができますが、次の理由により、これは100%正しくありません。

ページングは​​プロテクトモードでのみ使用できます。プロテクトモードでのページングの使用はオプションです。ページングがオンの場合PGcr0レジスタが設定さです。

ページングとセグメンテーション

ページングとセグメンテーションの主な違いの1つは次のとおりです。

  • ページングは​​RAMをページと呼ばれる同じサイズのチャンクに分割します
  • セグメンテーションはメモリを任意のサイズのチャンクに分割します

チャンクのサイズが等しいと物事が管理しやすくなるため、これがページングの主な利点です。

ページングは​​非常に人気が高まり、64ビットモードのx86-64では、IA32をエミュレートする互換モードでのみ存在する新しいソフトウェアの主要な動作モードである、セグメンテーションのサポートが削除されました。

応用

ページングは​​、最新のOSにプロセス仮想アドレス空間を実装するために使用されます。仮想アドレスを使用すると、OSは次の方法で単一のRAMに2つ以上の同時プロセスを適合させることができます。

  • 両方のプログラムが他のプログラムについて何も知る必要がない
  • 両方のプログラムのメモリは、必要に応じて拡大および縮小できます
  • プログラム間の切り替えは非常に高速です
  • あるプログラムが別のプロセスのメモリにアクセスすることはできません

ページングは​​歴史的にはセグメンテーション後に行われ、可変長セグメントではなくページの固定サイズのメモリチャンクを管理する方が簡単であるため、Linuxなどの最新のOSで仮想メモリを実装するために主に置き換えられました。

ハードウェアの実装

プロテクトモードでのセグメンテーションと同様に(セグメントレジスタを変更すると、GDTまたはLDTからのロードがトリガーされます)、ページングハードウェアはメモリ内のデータ構造を使用してジョブ(ページテーブル、ページディレクトリなど)を実行します。

これらのデータ構造の形式はハードウェアによって固定されていますが、これらのデータ構造をRAMに正しく設定および管理し、ハードウェアにそれらを見つける場所を(ハードウェアに指示する)のはOSの責任です。cr3です。

他の一部のアーキテクチャでは、ページングがほぼソフトウェアの手に委ねられているため、TLBミスはOS提供の関数を実行して、ページテーブルをウォークし、新しいマッピングをTLBに挿入します。これにより、OSがページテーブル形式を選択できるようになりますが、ハードウェアがページウォークと他の命令の順不同の実行をx86のようにオーバーラップさせることができなくなります

例:簡略化された単一レベルのページング方式

これは、ページングが単純化された仮想メモリ空​​間を実装するため x86アーキテクチャのバージョン。

ページテーブル

OSは次のページテーブルを提供できます。

OSによってプロセス1に与えられるページテーブル:

RAM location        physical address   present
-----------------   -----------------  --------
PT1 + 0       * L   0x00001            1
PT1 + 1       * L   0x00000            1
PT1 + 2       * L   0x00003            1
PT1 + 3       * L                      0
...                                    ...
PT1 + 0xFFFFF * L   0x00005            1

OSによってプロセス2に与えられるページテーブル:

RAM location       physical address   present
-----------------  -----------------  --------
PT2 + 0       * L  0x0000A            1
PT2 + 1       * L  0x0000B            1
PT2 + 2       * L                     0
PT2 + 3       * L  0x00003            1
...                ...                ...
PT2 + 0xFFFFF * L  0x00004            1

どこ:

  • PT1およびPT2:RAM上のテーブル1および2の初期位置。

    サンプル値:0x000000000x12345678など

    これらの値を決定するのはOSです。

  • L:ページテーブルエントリの長さ。

  • present:ページがメモリに存在することを示します。

ページテーブルはRAMにあります。たとえば、次のように配置できます。

--------------> 0xFFFFFFFF


--------------> PT1 + 0xFFFFF * L
Page Table 1
--------------> PT1


--------------> PT2 + 0xFFFFF * L
Page Table 2
--------------> PT2

--------------> 0x0

両方のページテーブルのRAM上の初期位置は任意であり、OSによって制御されます。それらが重複しないようにするのはOSの責任です!

各プロセスは、ページテーブルを直接変更することはできませんが、たとえば、より大きなスタックまたはヒープセグメントを要求するなど、OSにリクエストを出してページテーブルを変更させることはできません。

ページは4KB(12ビット)のチャンクであり、アドレスは32ビットなので、各ページを識別するために必要なのは20ビット(20 + 12 = 32、つまり16進表記で5文字)だけです。この値はハードウェアによって固定されています。

ページテーブルエントリ

ページテーブルは...ページテーブルエントリのテーブルです。

テーブルエントリの正確な形式は、ハードウェアによって固定されています

この単純化された例では、ページテーブルエントリには2つのフィールドしか含まれていません。

bits   function
-----  -----------------------------------------
20     physical address of the start of the page
1      present flag

したがって、この例では、ハードウェア設計者が選択できますL = 21

ほとんどの実際のページテーブルエントリには、他のフィールドがあります。

メモリはビットではなくバイトでアドレス指定できるので、21ビットで整列することは実際的ではありません。したがって、この場合は21ビットしか必要ない場合でも、ハードウェア設計者はL = 32アクセスを高速化することを選択し、残りのビットを後で使用するために予約するだけです。の実際の値Lx86では32ビットです。

シングルレベルスキームでのアドレス変換

OSによってページテーブルがセットアップされると、ハードウェアによってリニアアドレスと物理アドレス間のアドレス変換が行われます

OSは、アクティブプロセス1に望んでいるとき、それはセットcr3PT1、プロセスのいずれかのテーブルの開始を。

プロセス1がリニアアドレスにアクセスする0x00000001場合、ページングハードウェア回路はOSに対して次の処理を自動的に実行します。

  • 線形アドレスを2つの部分に分割します。

    | page (20 bits) | offset (12 bits) |
    

    したがって、この場合は次のようになります。

    • ページ= 0x00000
    • オフセット= 0x001
  • cr3それを指すので、ページテーブル1を調べます。

  • 0x00000それはページの一部なので、エントリを見てください。

    ハードウェアは、このエントリがRAMアドレスにあることを認識していますPT1 + 0 * L = PT1

  • 存在するため、アクセスは有効です

  • ページテーブルにより、ページ番号の場所が0x00000です0x00001 * 4K = 0x00001000

  • 最終的な物理アドレスを見つけるには、オフセットを追加するだけです。

      00001 000
    + 00000 001
      -----------
      00001 001
    

    これ00001は、テーブルで検索されたページの物理アドレスで001あり、オフセットです。

    名前が示すように、オフセットは常に単純にページの物理アドレスに追加されます。

  • 次に、ハードウェアはその物理的な場所にあるメモリを取得します。

同様に、プロセス1では次の変換が行われます。

linear     physical
---------  ---------
00000 002  00001 002
00000 003  00001 003
00000 FFF  00001 FFF
00001 000  00000 000
00001 001  00000 001
00001 FFF  00000 FFF
00002 000  00002 000
FFFFF 000  00005 000

アドレスにアクセスするとき、例えば00001000、ページの一部は、00001ハードウェアがそのページテーブルエントリはRAMのアドレスに配置されていることを知っています:PT1 + 1 * L1ページパーツのため)。

OSがプロセス2に切り替えたい場合は、cr3ページ2 をポイントするだけで済みます。これはとても簡単です。

ここで、プロセス2に対して次の変換が行われます。

linear     physical
---------  ---------
00000 002  00001 002
00000 003  00001 003
00000 FFF  00001 FFF
00001 000  00000 000
00001 001  00000 001
00001 FFF  00000 FFF
00003 000  00003 000
FFFFF 000  00004 000

同じ線形アドレスは、内部の値のみに応じて、異なるプロセスの異なる物理アドレスに変換さcr3ます。

このようにして、すべてのプログラムは、正確な物理アドレスを気にすることなく、データがで始まり、0で終わることを期待できFFFFFFFFます。

ページ違反

プロセス1が存在しないページ内のアドレスにアクセスしようとした場合はどうなりますか?

ハードウェアは、ページフォールト例外を介してソフトウェアに通知します。

その後、例外ハンドラを登録して何を実行する必要があるかを決定するのは、通常OSです。

テーブルにないページへのアクセスがプログラミングエラーである可能性があります。

int is[1];
is[2] = 1;

ただし、Linuxなどでは、次のような場合に許容される場合があります。

  • プログラムはスタックを増やしたいと考えています。

    特定の可能な範囲内の特定のバイトにアクセスしようとするだけであり、OSに問題がなければ、そのページがプロセスのアドレス空間に追加されます。

  • ページがディスクにスワップされました。

    OSは、ページをRAMに戻すために、プロセスの背後でいくつかの作業を行う必要があります。

    現在のフラグがクリアされている場合、ページテーブルエントリの他のエントリはOSが希望するものに完全に委ねられるため、OSはこれがページテーブルエントリの残りの内容に基づいていることを発見できます。

    たとえばLinuxでは、存在する場合= 0:

    • ページテーブルエントリのすべてのフィールドが0の場合、アドレスは無効です。

    • それ以外の場合、ページはディスクにスワップされ、それらのフィールドの実際の値はディスク上のページの位置をエンコードします。

いずれの場合も、OSは問題に対処するためにページフォールトを生成したアドレスを知る必要があります。これが、優れたIA32開発者cr2がページ違反が発生するたびにそのアドレスにの値を設定する理由です。例外ハンドラーはcr2、アドレスを取得するために調べるだけです。

簡略化

この例を理解しやすくするための現実の簡略化:

  • すべての実際のページング回路はスペースを節約するためにマルチレベルページングを使用しますが、これは単純なシングルレベルスキームを示しています。

  • ページテーブルには、20ビットアドレスと1ビット存在フラグの2つのフィールドしか含まれていませんでした。

    実際のページテーブルには合計12のフィールドが含まれているため、省略されているその他の機能があります。

例:マルチレベルのページングスキーム

単一レベルのページング方式の問題は、RAMを大量に消費することです。4G/ 4K = プロセスあたり 1Mエントリ。各エントリが4バイト長の場合、プロセスごとに 4Mになります。これは、デスクトップコンピュータの場合でも多すぎます。ps -A | wc -l現在244のプロセスを実行しているため、RAMが約1GB必要です。

このため、x86開発者は、RAM使用量を削減するマルチレベルスキームを使用することを決定しました。

このシステムの欠点は、アクセス時間が少し長くなることです。

PAEなしの32ビットプロセッサに使用される単純な3レベルのページング方式では、32アドレスビットは次のように分割されます。

| directory (10 bits) | table (10 bits) | offset (12 bits) |

各プロセスには、1つだけのページディレクトリが関連付けられている必要があるため、少なくとも 2^10 = 1Kページディレクトリエントリます。これは、単一レベルのスキームで必要な最小1Mよりはるかに優れています。

ページテーブルは、OSが必要とする場合にのみ割り当てられます。各ページテーブルには2^10 = 1Kページディレクトリエントリがあります

ページディレクトリには...ページディレクトリエントリが含まれています!ページディレクトリエントリは、テーブルの物理アドレスではなく、ページテーブルのRAMアドレスを指すこと除いてページテーブルエントリと同じです。これらのアドレスは20ビット幅しかないため、ページテーブルは4KBページの先頭にある必要があります。

cr3 現在、ページテーブルではなく、現在のプロセスのページディレクトリのRAM上の場所をポイントしています。

ページテーブルのエントリは、単一レベルのスキーマからまったく変更されません。

次の理由により、ページテーブルは単一レベルのスキームから変更されます。

  • 各プロセスは、ページディレクトリエントリごとに1つ、最大1Kのページテーブルを持つことができます。
  • 各ページテーブルには、1Mエントリではなく、正確に1Kエントリが含まれています。

最初の2つのレベル(たとえば、で12 | 8 | 12はない)で10ビットを使用する理由は、各ページテーブルエントリが4バイト長であるためです。次に、ページディレクトリとページテーブルの2 ^ 10エントリが4Kbページにうまく収まります。これは、その目的のためにページを割り当てたり割り当て解除したりするのがより速くて簡単であることを意味します。

マルチレベルスキームでのアドレス変換

OSによってプロセス1に与えられたページディレクトリ:

RAM location     physical address   present
---------------  -----------------  --------
PD1 + 0     * L  0x10000            1
PD1 + 1     * L                     0
PD1 + 2     * L  0x80000            1
PD1 + 3     * L                     0
...                                 ...
PD1 + 0x3FF * L                     0

OSによってプロセス1に与えられたページテーブルPT1 = 0x100000000x10000* 4K):

RAM location      physical address   present
---------------   -----------------  --------
PT1 + 0     * L   0x00001            1
PT1 + 1     * L                      0
PT1 + 2     * L   0x0000D            1
...                                  ...
PT1 + 0x3FF * L   0x00005            1

OSによってプロセス1に与えられたページテーブルPT2 = 0x800000000x80000* 4K):

RAM location      physical address   present
---------------   -----------------  --------
PT2 + 0     * L   0x0000A            1
PT2 + 1     * L   0x0000C            1
PT2 + 2     * L                      0
...                                  ...
PT2 + 0x3FF * L   0x00003            1

どこ:

  • PD1:RAM上のプロセス1のページディレクトリの初期位置。
  • PT1およびPT2:RAM上のプロセス1のページテーブル1およびページテーブル2の初期位置。

したがって、この例では、ページディレクトリとページテーブルを次のようなRAMに格納できます。

----------------> 0xFFFFFFFF


----------------> PT2 + 0x3FF * L
Page Table 1
----------------> PT2

----------------> PD1 + 0x3FF * L
Page Directory 1
----------------> PD1


----------------> PT1 + 0x3FF * L
Page Table 2
----------------> PT1

----------------> 0x0

線形アドレスを0x00801004段階的に変換してみましょう。

つまりcr3 = PD1、ここで説明したページディレクトリを指していると想定します。

バイナリでは、線形アドレスは次のとおりです。

0    0    8    0    1    0    0    4
0000 0000 1000 0000 0001 0000 0000 0100

10 | 10 | 12与えるようにグループ化:

0000000010 0000000001 000000000100
0x2        0x1        0x4

それは与える:

  • ページディレクトリエントリ= 0x2
  • ページテーブルエントリ= 0x1
  • オフセット= 0x4

したがって、ハードウェアはページディレクトリのエントリ2を探します。

ページディレクトリテーブルは、ページテーブルがにあることを示しています0x80000 * 4K = 0x80000000。これは、プロセスの最初のRAMアクセスです。

ページテーブルエントリは0x1であるため、ハードウェアはのページテーブルのエントリ1を調べ0x80000000、物理ページがアドレスにあることを通知します0x0000C * 4K = 0x0000C000。これは、プロセスの2番目のRAMアクセスです。

最後に、ページングハードウェアがオフセットを追加し、最終的なアドレスは0x0000C004です。

変換されたアドレスの他の例は次のとおりです。

linear    10 10 12 split   physical
--------  ---------------  ----------
00000001  000 000 001      00001001
00001001  000 001 001      page fault
003FF001  000 3FF 001      00005001
00400000  001 000 000      page fault
00800001  002 000 001      0000A001
00801008  002 001 008      0000C008
00802008  002 002 008      page fault
00B00001  003 000 000      page fault

ページフォールトは、ページディレクトリエントリまたはページテーブルエントリが存在しない場合に発生します。

OSが別のプロセスを同時に実行したい場合、2番目のプロセスに個別のページディレクトリを提供し、そのディレクトリを個別のページテーブルにリンクします。

64ビットアーキテクチャ

64ビットは、現在のRAMサイズに対してアドレスが多すぎるため、ほとんどのアーキテクチャではより少ないビットを使用します。

x86_64は48ビット(256 TiB)を使用し、レガシーモードのPAEはすでに52ビットアドレス(4 PiB)を許可しています。

これらの48ビットのうち12ビットは既にオフセット用に予約されており、36ビットが残ります。

2レベルのアプローチを採用する場合、最適な分割は2つの18ビットレベルです。

しかし、これはページディレクトリが 2^18 = 256K、これはエントリがあり、RAMが多すぎる。32ビットアーキテクチャの単一レベルのページングに近いです。

したがって、64ビットアーキテクチャでは、さらに多くのページレベル(通常は3または4)が作成されます。

x86_64は9 | 9 | 9 | 12スキームで4つのレベルを使用するため、上位レベルは2^9上位レベルのエントリのみを使用します。

PAE

物理アドレス拡張。

32ビットでは、4GBのRAMのみをアドレス指定できます。

これは大規模サーバーの制限になり始めたため、インテルはPentium ProにPAEメカニズムを導入しました。

この問題を解決するために、Intelは4つの新しいアドレス行を追加しました。これにより、64GBに対応できます。

PAEがオンの場合、ページテーブルの構造も変更されます。それが変更される正確な方法は、PSEがオンかオフかによって異なります。

PAEは、のPAEビットを介してオン/オフされcr4ます。

アドレス可能なメモリの合計が64GBであっても、個々のプロセスは最大4GBしか使用できません。ただし、OSは異なるプロセスを異なる4GBチャンクに置くことができます。

PSE

ページサイズ拡張。

ページの長さを4Kではなく4M(PAEがオンの場合は2M)にすることができます。

PSEはのPAEビットを介してオン/オフされcr4ます。

PAEおよびPSEページテーブルスキーム

PAEとPSEのいずれかがアクティブな場合、異なるページングレベルスキームが使用されます。

  • PAEおよびPSEなし: 10 | 10 | 12

  • PAEおよびPSEなし:10 | 22

    22ビットは4Mbをアドレス指定するため、22は4Mbページ内のオフセットです。

  • PAEあり、PSEなし: 2 | 9 | 9 | 12

    10の代わりに9が2回使用される設計上の理由は、エントリが32ビットに収まらなくなったためです。これらのビットはすべて、20のアドレスビットと12の意味のある、または予約済みのフラグビットで埋められていました。

    その理由は、ページテーブルのアドレスを表すには20ビットではもう十分ではないためです。プロセッサに4本の追加のワイヤが追加されたため、24ビットが必要になりました。

    したがって、設計者はエントリサイズを64ビットに増やし、それらを単一のページテーブルに収めるには、エントリ数を2 ^ 10ではなく2 ^ 9に減らす必要があります。

    最初の2つは、ページディレクトリポインターテーブル(PDPT)と呼ばれる新しいページレベルです。これは、ページディレクトリを指し、32ビットの線形アドレスを入力するためです。PDPTも64ビット幅です。

    cr3アドレッシング効率のために、最初の4 GBのメモリ上にあり、32ビットの倍数で整列する必要があるPDPTを指すようになりました。これはcr3、最初の4GBの2 ^ 32を完成させるために、32の倍数* 2 ^ 27に対して20:2 ^ 5ではなく27の有効ビットがあることを意味します。

  • PAEおよびPSE: 2 | 9 | 21

    デザイナーは、1ページに収まるように9ビット幅のフィールドを維持することを決定しました。

    これは23ビットを残します。PSEなしのPAEケースで物事を均一に保つためにPDPTに2を残すと、オフセット用に21が残されます。つまり、ページの幅は4Mではなく2Mになります。

TLB

変換先読みバッファ(TLB)は、ページングアドレスのキャッシュです。

キャッシュであるため、結合性レベルなど、CPUキャッシュの設計上の問題の多くを共有します。

このセクションでは、4つの単一アドレスエントリを持つ単純化された完全に関連付けられたTLBについて説明します。他のキャッシュと同様に、実際のTLBは通常、完全には関連付けられていません。

基本的な操作

線形アドレスと物理アドレス間の変換が行われた後、TLBに格納されます。たとえば、4エントリのTLBは次の状態で始まります。

  valid   linear   physical
  ------  -------  ---------
> 0       00000    00000
  0       00000    00000
  0       00000    00000
  0       00000    00000

>交換する現在のエントリを示します。

ページリニアアドレス00003が物理アドレスに変換された00005後、TLBは次のようになります。

  valid   linear   physical
  ------  -------  ---------
  1       00003    00005
> 0       00000    00000
  0       00000    00000
  0       00000    00000

への2回目の変換後、次の00007よう00009になります。

  valid   linear   physical
  ------  -------  ---------
  1       00003    00005
  1       00007    00009
> 0       00000    00000
  0       00000    00000

次に、00003再度変換する必要がある場合、ハードウェアは最初にTLBを検索し、1回のRAMアクセスでアドレスを見つけます00003 --> 00005

もちろん、00000有効なエントリが00000キーとして含まれていないため、TLBにはありません。

交換ポリシー

TLBがいっぱいになると、古いアドレスが上書きされます。CPUキャッシュの場合と同様に、置換ポリシーは潜在的に複雑な操作ですが、最も古く使用されていないエントリ(LRU)を削除することが単純で合理的なヒューリスティックです。

LRUでは、状態から開始します。

  valid   linear   physical
  ------  -------  ---------
> 1       00003    00005
  1       00007    00009
  1       00009    00001
  1       0000B    00003

追加する0000D -> 0000Aと次のようになります:

  valid   linear   physical
  ------  -------  ---------
  1       0000D    0000A
> 1       00007    00009
  1       00009    00001
  1       0000B    00003

カム

TLBを使用すると、TLB レベルごとに1つのアクセスが必要になるため、変換が速くなります。これは、単純な32ビットスキームでは2、64ビットアーキテクチャでは3または4であることを意味します。

TLBは通常、連想メモリ(CAM)と呼ばれる高価なタイプのRAMとして実装されます。CAMは、ハードウェアに連想マップを実装します。つまり、キー(線形アドレス)を指定して、値を取得する構造です。

マッピングはRAMアドレスに実装することもできますが、CAMマッピングはRAMマッピングよりもはるかに少ないエントリで済みます。

たとえば、次のようなマップ。

  • キーと値の両方が20ビットです(単純なページング方式の場合)。
  • 毎回最大4つの値を保存する必要があります

4つのエントリを持つTLBに格納できます。

linear   physical
-------  ---------
00000    00001
00001    00010
00010    00011
FFFFF    00000

ただし、これをRAMで実装するには、2 ^ 20のアドレスが必要です。

linear   physical
-------  ---------
00000    00001
00001    00010
00010    00011
... (from 00011 to FFFFE)
FFFFF    00000

これはTLBを使用するよりもさらにコストがかかります。

無効なエントリ

ときcr3変更は、すべてのTLBエントリが無効化される新しいプロセスのための新しいページテーブルが使用されようとしているので、古いエントリのいずれかが何らかの意味を持っていることはほとんどありません。

x86は、invlpg単一のTLBエントリを明示的に無効にする命令も提供します。他のアーキテクチャは、特定の範囲のすべてのエントリを無効にするなど、無効化されたTLBエントリにさらに多くの命令を提供します。

一部のx86 CPUは、x86仕様の要件を超え、ページテーブルエントリの変更とTLBにまだキャッシュされていない場合の使用との間で、保証するよりも一貫性を提供します。どうやらWindows 9xは正確さのためにこれに依存していましたが、最近のAMD CPUは一貫したページウォークを提供していません。Intel CPUは、推測を誤検出する必要があるにもかかわらず、そうします。これを利用することはおそらく得策ではなく、デバッグするのが難しい微妙なタイミングに敏感な問題を引き起こす大きなリスクがあるため、おそらく悪い考えです。

Linuxカーネルの使用

Linuxカーネルは、x86のページング機能を広範囲に使用して、小さなデータの断片化による高速のプロセス切り替えを可能にします。

v4.2、下を見てくださいarch/x86/

  • include/asm/pgtable*
  • include/asm/page*
  • mm/pgtable*
  • mm/page*

ページを表すために定義された構造体はなく、マクロのみinclude/asm/page_types.hがあるようです。特に興味深いものです。抜粋:

#define _PAGE_BIT_PRESENT   0   /* is present */
#define _PAGE_BIT_RW        1   /* writeable */
#define _PAGE_BIT_USER      2   /* userspace addressable */
#define _PAGE_BIT_PWT       3   /* page write through */

arch/x86/include/uapi/asm/processor-flags.h定義しCR0、特にPGビット位置:

#define X86_CR0_PG_BIT      31 /* Paging */

参考文献

自由:

  • rutgers-pxk-416の章「メモリ管理:講義ノート」

    古いOSで使用されているメモリ編成手法の優れた履歴レビュー。

非フリー:

  • bovet05の章「メモリアドレス指定」

    x86メモリアドレス指定の合理的な紹介。いくつかの良いシンプルな例がありません。


正解ですが、LRUがどのように決定されるかはまだわかりません。MRU以外のページにアクセスするたびにOSを呼び出すのは、負荷がかかるようです。あるいは、ハードウェアがLRUのページテーブルを並べ替えるのを見ることができました。これは、並行プログラムにとって危険かもしれません。これらのどちらが正しいですか?OSは、ページフォールトが発生したときに、どのページがLRUであるかをどのように認識しますか?
Keynan

@Keynanそれを行うのはハードウェアだと私は思うので、かかる時間は問題ではありません。並行性に関しては、それがどのように管理されているのかわかりません。プロセッサごとに1つのCR3とキャッシュがあると思います。OSは、メモリページがオーバーラップしないようにする必要があります。
Ciro Santilli郝海东冠状病六四事件法轮功

1
real TLBs are not usually fully associativeThe TLB is usually implemented as … CAMこれら2つのステートメントは矛盾していませんか?
a3f

>>> x86_64は9で4レベルを使用します| 9 | 9 | 12スキームは9でなければなりません| 9 | 9 | 9 | 12?
monklof

@monklofこれは正しいと思います:9 9 9 12は、512GBのRAMをすでに許可しています。5レベルのスキームは、サーバーのみを対象とした最近の開発であり、これは私のWebサイトの回答に記載されています。
Ciro Santilli郝海东冠状病六四事件法轮功

20

これは非常に短い、高レベルの答えです:

x86プロセッサーは、いくつかの可能なモードのいずれかで動作します(大まかに:リアル、保護、64ビット)。各モードは、いくつかの可能なメモリアドレス指定モデルの1つを使用できます(ただし、すべてのモードがすべてのモデルを使用できるわけではありません)。つまり、リアルモードアドレス指定、セグメントアドレス指定、およびフラットリニアアドレス指定です。

現代の世界では、プロテクトモードまたは64ビットモードのフラットリニアアドレス指定のみが関連し、2つのモードは基本的に同じですが、主な違いはマシンワードのサイズであり、したがってメモリのアドレス指定可能な量です。

現在、メモリアドレッシングモードは、マシン命令のメモリオペランドに意味を与えmov DWORD PTR [eax], 25ます(dword値25の32ビット(別名)整数をeax32ビットレジスタにアドレスが格納されているメモリに格納するなど)。フラットリニアアドレッシングでは、この数値はeax、ゼロから最大値(この場合は2 32  − 1)までの単一の連続した範囲で実行できます。

しかし、フラットリニアアドレッシングがいずれかのことができるページングページングされません。ページングがない場合、アドレスは直接物理メモリを参照します。ページング、プロセッサのメモリ管理ユニット(MMUまたは)透過(今呼ばれる所望のアドレスフィード仮想アドレスを、ルックアップメカニズムに)いわゆるページ・テーブル、及び物理アドレスとして解釈される新しい値を取得します。ユーザーが仮想アドレスしか表示しない場合でも、元の操作は物理メモリ内のこの新しい変換されたアドレスで動作します。

ページングの主な利点は、ページテーブルがオペレーティングシステムによって管理されることです。したがって、オペレーティングシステムは、「タスクの切り替え」時など、ページテーブルを任意に変更および置換できます。「プロセス」ごとに1つずつ、ページテーブルのコレクション全体を保持できます。特定のプロセスが特定のCPUで実行されると判断した場合は常に、プロセスのページテーブルをそのCPUのMMUにロードします(各CPUには独自のプロセスがあります)ページテーブルのセット)。その結果、OSがメモリを割り当てる必要があったときにどの物理ページが空いているかに関係なく、各プロセスは同じに見える独自の仮想アドレス空間を認識します。物理メモリに直接アクセスできないため、他のプロセスのメモリを認識しません。

ページテーブルは、通常のメモリに格納されたネストされたツリーのようなデータ構造であり、OSによって書き込まれますが、ハードウェアによって直接読み取られるため、形式は固定されています。それらは、最上位のテーブルを指すように特別なCPU制御レジスターを設定することにより、MMUに「ロード」されます。CPUはTLBと呼ばれるキャッシュを使用してルックアップを記憶するため、TLBミスの理由と通常のデータキャッシュの理由により、同じ数ページへの繰り返しアクセスは分散アクセスよりもはるかに高速です。TLBにキャッシュされていない場合でも、ページテーブルエントリを指すのに「TLBエントリ」という用語が使用されるのはよくあることです。

また、プロセスがページングを無効にしたり、ページテーブルを変更したりすることが心配な場合は、これは許可されていません。x86は特権レベル(「リング」と呼ばれます)を実装しており、ユーザーコードは実行するには低すぎる特権レベルで実行されるためです。 CPUのページテーブルを変更します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.