この質問は、主題に関する無料の良い情報の空白を埋めるためのものです。
良い答えは、1つの大きなSOの答えまたは少なくともいくつかの答えに収まると信じています。
主な目標は、完全な初心者に十分な情報を提供して、マニュアルを自分で取り、ページングに関連する基本的なOSの概念を理解できるようにすることです。
推奨されるガイドライン:
関連する質問と、それらがtheyではないと思う理由:
x86ページテーブルはどのように機能しますか? :タイトルはこの質問とほぼ同じですが、本文はcr3とTLBに関連する特定の質問をします。その質問はこの質問のサブセットです。
x86仮想化の仕組み :bodyはソースのみを要求します。
Nice TOCおよびその他のコンテンツを含むこの回答のバージョン 。
報告されたエラーを修正します。大規模な修正を行うか、欠落している側面を追加する場合は、適切な担当者を得るために自分で答えを作成してください。マイナーな編集は直接マージできます。
プログラミングの他のすべてと同様に、これを本当に理解する唯一の方法は、最小限の例を試すことです。
これを「難しい」主題にしているのは、独自の小さなOSを作成する必要があるため、最小限の例が大きいということです。
例を念頭に置いて理解することは不可能ですが、できるだけ早くマニュアルに慣れるようにしてください。
インテルでは、ページングについて Intel Manual Volume 3 System Programming Guide-325384-056US September 2015 第4章「ページング」で説明しています。
特に興味深いのは、図4-4「32ビットページングを使用したCR3およびページング構造のエントリのフォーマット」です。これは、主要なデータ構造を示しています。
ページングは、CPUの メモリ管理ユニット (MMU)部分によって行われます。他の多くの例と同様(例 x87コプロセッサー 、 [〜#〜] apic [〜#〜] )、これは初期の頃は別々のチップでした。後でCPUに統合されました。しかし、この用語はまだ使用されています。
論理アドレスは、「通常の」ユーザーランドコードで使用されるメモリアドレスです(例:mov eax, [rsi]
のrsi
の内容)。
最初のセグメンテーションはそれらを線形アドレスに変換し、次にページングは線形アドレスを物理アドレスに変換します。
(logical) ------------------> (linear) ------------> (physical)
segmentation paging
ほとんどの場合、物理アドレスは実際のRAMハードウェアメモリセルのインデックス付けと考えることができますが、これは次の理由により100%真実ではありません。
ページングは保護モードでのみ使用できます。保護モードでのページングの使用はオプションです。 cr0
レジスタのPG
ビットが設定されている場合、ページングがオンになります。
ページングとセグメンテーションの大きな違いは次のとおりです。
これはページングの主な利点です。同じサイズのチャンクにより管理が容易になるためです。
ページングは非常に一般的になっているため、セグメンテーションのサポートは、IA32をエミュレートする互換モードでのみ存在する新しいソフトウェアのメイン操作モードである64ビットモードのx86-64で削除されました。
ページングは、最新のOSにプロセス仮想アドレススペースを実装するために使用されます。仮想アドレスを使用すると、OSは次の方法で単一のRAMに2つ以上の同時プロセスを適合させることができます。
歴史的にページングはセグメンテーション後に行われ、可変長セグメントの代わりにページの固定サイズのメモリチャンクを管理する方が簡単であるため、Linuxなどの最新のOSで仮想メモリを実装するために大幅に置き換えられました。
保護モードでのセグメンテーション(セグメントレジスタの変更がGDTまたはLDTからのロードをトリガーする)と同様に、ページングハードウェアはメモリ内のデータ構造を使用してジョブ(ページテーブル、ページディレクトリなど)を実行します。
これらのデータ構造の形式は固定されていますハードウェアによるですが、RAMのデータ構造を正しくセットアップおよび管理し、ハードウェアに場所を伝えるのはOS次第ですそれらを見つけるために(cr3
経由)。
他のいくつかのアーキテクチャでは、ページングをほぼ完全にソフトウェアの手に委ねているため、TLBミスはOSが提供する機能を実行してページテーブルを移動し、TLBに新しいマッピングを挿入します。これにより、ページテーブルの形式はOSによって選択されたままになりますが、 ハードウェアが他の命令の順不同の実行とページウォークをオーバーラップできる可能性は低く、x86のように です。
これは、仮想メモリ空間を実装するために、x86アーキテクチャのsimplifiedバージョンでページングがどのように動作するかの例です。
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の初期位置。
サンプル値:0x00000000
、0x12345678
など.
これらの値を決定するのは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
を選択してアクセスを高速化し、残りのビットを後で使用するために予約します。 x86上のL
の実際の値は32ビットです。
OSによってページテーブルが設定されると、線形アドレスと物理アドレス間のアドレス変換が行われますby the hardware。
OSはプロセス1をアクティブにしたい場合、cr3
をPT1
に設定します。これは、プロセス1のテーブルの始まりです。
プロセス1が線形アドレス0x00000001
にアクセスしたい場合、ページングハードウェア回路はOSに対して以下を自動的に実行します。
線形アドレスを2つの部分に分割します。
| page (20 bits) | offset (12 bits) |
したがって、この場合は次のようになります。
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 * L
(1
ページ部分のため)、それはそれがそれを探す場所です。
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は、ページフォールトを生成したアドレスを把握して、問題に対処する必要があります。これが、ページフォールトが発生するたびにNice IA32開発者がcr2
の値をそのアドレスに設定する理由です。例外ハンドラは、cr2
を調べるだけでアドレスを取得できます。
この例を理解しやすくする現実の単純化:
すべての実際のページング回路は、スペースを節約するためにマルチレベルページングを使用しますが、これは単純なシングルレベルスキームを示しています。
ページテーブルには、20ビットのアドレスと1ビットの存在フラグの2つのフィールドのみが含まれていました。
実ページのテーブルには合計12のフィールドが含まれているため、他の機能は省略されています。
単一レベルのページング方式の問題は、4G/4K = 1Mエントリperプロセスというように、RAMを大量に消費することです。各エントリの長さが4バイトの場合、4M プロセスごとになります。これはデスクトップコンピューターにとっても大きすぎます:ps -A | wc -l
は、現在244プロセスを実行していると言うので約1GBのRAMを使用してください!
このため、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上の場所を指すようになりました。
ページテーブルのエントリは、単一レベルのスキームからまったく変化しません。
ページテーブルは、次の理由でシングルレベルスキームから変更されます。
最初の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
PT1 = 0x10000000
(0x10000
* 4K)のOSによってプロセス1に与えられたページテーブル:
RAM location physical address present
--------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0
PT1 + 2 * L 0x0000D 1
... ...
PT1 + 0x3FF * L 0x00005 1
PT2 = 0x80000000
(0x80000
* 4K)のOSによってプロセス1に与えられたページテーブル:
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
与えるもの:
そのため、ハードウェアはページディレクトリのエントリ2を探します。
ページディレクトリテーブルは、ページテーブルが0x80000 * 4K = 0x80000000
にあることを示しています。これは、プロセスの最初のRAMアクセスです。
ページテーブルエントリは0x1
であるため、ハードウェアは0x80000000
のページテーブルのエントリ1を見て、物理ページがアドレス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ビットは、現在の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
上位レベルのエントリのみを使用します。
物理アドレス拡張。
32ビットでは、4GB RAMのみをアドレス指定できます。
これが大型サーバーの制限になり始めたため、IntelはPAEメカニズムをPentium Proに導入しました。
問題を緩和するために、Intelは4つの新しいアドレス行を追加し、64GBに対応できるようにしました。
PAEがオンの場合、ページテーブル構造も変更されます。変更される正確な方法は、PSEがオンかオフかによって異なります。
PAEは、cr4
のPAE
ビットを介してオンとオフを切り替えます。
アドレス可能なメモリの合計が64GBであっても、個々のプロセスは最大4GBまでしか使用できません。ただし、OSは異なる4GBチャンクに異なるプロセスを配置できます。
ページサイズ拡張。
ページの長さを4Kではなく4M(またはPAEがオンの場合は2M)にすることができます。
PSEは、cr4
のPAE
ビットを介してオンおよびオフになります。
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)と呼ばれる新しいページレベルです。これはpointsでディレクトリをページングし、32ビットの線形アドレスを入力するためです。 PDPTも64ビット幅です。
cr3
はPDPTを指すようになりました。PDPTは最初の4 GBのメモリ上にあり、効率を上げるために32ビットの倍数で整列する必要があります。これは、cr3
に20ではなく27の有効ビットがあることを意味します。32の倍数の2 ^ 5 *最初の4GBの2 ^ 32を完了するための2 ^ 27。
PAEおよびPSE:2 | 9 | 21
デザイナーは、1つのページに収まるように9ビット幅のフィールドを保持することにしました。
これにより23ビットが残ります。 PSEのないPAEケースで物事を均一に保つためにPDPTに2を残すと、オフセットに21が残ります。つまり、ページは4Mではなく2M幅になります。
Translation Lookahead Buffer(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
00007
から00009
への2回目の翻訳の後、次のようになります。
valid linear physical
------ ------- ---------
1 00003 00005
1 00007 00009
> 0 00000 00000
0 00000 00000
00003
を再度変換する必要がある場合、ハードウェアは最初にTLBを検索し、単一の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を使用すると、最初の変換に1回のアクセスが必要になるため、変換が高速になりますTLBレベルごと。これは、単純な32ビットスキームでは2、64ビットアーキテクチャでは3または4を意味します。
TLBは通常、Content-Addressable Memory(CAM)と呼ばれるRAMの高価なタイプとして実装されます。 CAMは、ハードウェア、つまりキー(線形アドレス)を指定して値を取得する構造体に、関連付けマップを実装します。
マッピングはRAMアドレスにも実装できますが、CAMマッピングに必要なエントリはRAMマッピングよりもはるかに少ない場合があります。
たとえば、次のマップ:
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は、単一のTLBエントリを明示的に無効にするinvlpg
命令も提供します。他のアーキテクチャでは、特定の範囲のすべてのエントリを無効にするなど、無効なTLBエントリにさらに多くの命令を提供します。
一部のx86 CPUは、x86仕様の要件を超えており、それが保証する以上の一貫性を提供します TLBにまだキャッシュされていない場合、ページテーブルエントリの変更と使用の間 。どうやらWindows 9xは正確性のためにこれに依存していましたが、最新のAMD CPUは一貫したページウォークを提供していません。 Intel CPUは、そうするために誤った推測を検出する必要がありますが。これを利用することはおそらく得策ではないので、おそらく悪い考えであり、デバッグが難しい微妙なタイミングに敏感な問題を引き起こす大きなリスクがあります。
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メモリアドレッシングの合理的な紹介。いくつかの良い簡単な例がありません。
非常に短い、高レベルの答えは次のとおりです。
X86プロセッサは、いくつかの可能なモード(大まかに言うと、実際の保護された64ビット)の1つで動作します。各モードは、いくつかの可能なメモリアドレス指定モデルのいずれかを使用できます(ただし、すべてのモードがすべてのモデルを使用できるわけではありません)。つまり、リアルモードアドレス指定、セグメントアドレス指定、フラットリニアアドレス指定です。
現代の世界では、保護モードまたは64ビットモードでのフラットリニアアドレッシングのみが関連しており、2つのモードは基本的に同じですが、主な違いはマシンワードのサイズ、したがってアドレス可能なメモリ量です。
現在、メモリアドレス指定モードは、マシン命令のメモリオペランドに意味を与えます(mov DWORD PTR [eax], 25
は、値が25の32ビット(別名dword
)整数を、アドレスがeax
32ビットレジスタに格納されているメモリに格納します。フラットリニアアドレッシングでは、eax
のこの数値は、ゼロから最大値までの単一の連続した範囲で実行できます(この場合は232− 1)。
ただし、フラットリニアアドレッシングはpagedまたはnot pagedのいずれかです。ページングを使用しない場合、アドレスは物理メモリを直接参照します。 Withページング、プロセッサのメモリ管理ユニット(またはMMU)は、目的のアドレス(現在は仮想アドレスと呼ばれる)をルックアップメカニズム、いわゆるページテーブル、および物理アドレスとして解釈される新しい値を取得します。元の操作は、ユーザーが仮想アドレスしか見ることができない場合でも、物理メモリ内のこの新しい変換されたアドレスで動作するようになりました。
ページングの主な利点は、ページテーブルがオペレーティングシステムによって管理されることです。したがって、オペレーティングシステムは、「タスクの切り替え」など、ページテーブルを任意に変更および置換できます。 「プロセス」ごとに1つのページテーブルのコレクション全体を保持でき、特定のプロセスが特定のCPUで実行されると判断するたびに、プロセスのページテーブルをそのCPUのMMU(各CPUには独自のページテーブルセットがあります。)結果は、各プロセスが独自の仮想を参照することです。物理メモリに直接アクセスできないため、他のプロセスのメモリについては決して知りません。
ページテーブルは、通常のメモリに格納されたネストされたツリーのようなデータ構造であり、OSによって書き込まれますが、ハードウェアによって直接読み取られるため、形式は固定されています。特別なCPU制御レジスタを設定して、最上位テーブルを指すことにより、MMUにロードされます。CPUはTLBと呼ばれるキャッシュを使用してルックアップを記憶するため、同じ数ページは、TLBミスの理由と通常のデータキャッシュの理由から、分散アクセスよりもはるかに高速です。 TLB。
また、プロセスがページングを無効にするか、ページテーブルを変更しようとするかもしれないと心配する場合は、x86が特権レベル(「リング」と呼ばれる)を実装し、ユーザーコードがCPUのページテーブルを変更するには低すぎる特権レベル。