見出し画像

ページング作成時に必要になる知識まとめ

カーネルの作成を行う上でページング機構をはじめに作成しようとしているのですが、コードだけ見てもなかなか理解できないのでページングについての理解を深めたいと思いここに記します。

結構適当な順序で書いてるので知りたいことだけ読む感じでいいと思います、目次置いときますね。



仮想アドレス変換の流れ


プログラム、もしくはユーザーが情報にアクセスすると仮想アドレスから物理アドレスへのアドレス変換が行われます。

TLBは特殊なキャッシュメモリで仮想アドレスから物理アドレスへの変換表を保存しています。その表の中に変換する物理アドレスが入っている場合、すぐにCPUに情報を渡すことができます。

入っていなかった場合はページテーブルという構造体から物理アドレスに変換しCPUに渡します。

仮想アドレスから物理アドレスの変換

参考資料:


TLBを詳しく


TLBはTranslation Lookaside Bufferの略でLookasideをgoogle翻訳にかけてみると横を見るという訳になった。Look aside…

Translationは翻訳でBufferはメモリなので
翻訳横を見るメモリです(???)

TLBはキャッシュメモリです。
キャッシュメモリはCPU内部についている高速に情報を扱える記憶装置のことです。

似たようなものにレジスタがありますがこちらは今プログラムが使っている値を入れます。レジスタはキャッシュメモリよりも高速に情報を扱えますが、容量が足りません。
なので今は使ってないけどすぐに使うかもしれない情報をキャッシュメモリに保存します。

TLBは最近使った仮想ページ番号と物理ページ番号の変換表が保存されます。

ページングの際、仮想アドレスは以下のような状態になっています。

[ 仮想ページ番号 | オフセット ]

仮想ページ番号にはどのページにその情報があるのかを表しています。
その情報をもとにページの保存場所を割り出します。

オフセットは見つけたページにおける目当ての情報が載っているバイト数です。オフセットが必要になるのはページを見つけた後なのでページを探すだけならオフセット情報は必要ありません。

そのため、TLBに乗っているのは仮想ページ番号とそれに対応する物理ページ番号のみになります。

仮想ページ番号はVPN、物理ページ番号はPPNと呼ぶこともあります。

TLBの内容

参考資料:


x86_64での仮想アドレスの構造

仮想アドレスは16進数の値でありこれを2進数に分解すると

0x00000000 = 0000 0000 0000 0000 0000 0000 0000 0000

のような値になります。
この値は概念的な話なのでx86_64で実際に使われるアドレスはもっと長いです。
2進数を分解すると以下のように分けられます。

     仮想ページ番号       |  ページオフセット
0000 0000 0000 0000 0000 | 0000 0000 0000

仮想ページ番号は複数のページがある中からどのページに必要な情報が載っているのかを表す番号です。
ページオフセットはページの中のどの場所にあるのかを表します。

ページを探すのに必要なのは仮想ページ番号のみでページオフセットはそのあとで値を探すために使用します。

仮想ページ番号についてはページテーブルをさかのぼることで得られますがページオフセットについては最初から分かっています。

それはアドレスの中に書かれています。

offset以外のところに入っているのはそれぞれは仮想ページ番号ではなく各ページのエントリ番号
それらを全部繋げたものが仮想ページ番号

|PML4|PDPT|PD  |PT  |offset|
|9bit|9bit|9bit|9bit|12bit|
|  仮想アドレス番号  |オフセット|


参考資料:


ページディレクトリとページテーブルの違い


ページディレクトリ
複数あるページテーブルの中からどのページテーブルにその仮想アドレスに対応する物理アドレスが保存されているのかが書かれている構造体のこと。

ページテーブル
実際に情報が保存してある物理アドレスが書かれている構造体です。

そのため、アドレスを探す際はページディレクトリ→ページテーブルの順番で探します。

x86_64のページングではPD(Page Directory)とPT(Page Table)に加えPML4PDPTという階層があります。

PML4はPage Map Level 4の略で最上位テーブルのことです。
PML4にはPDPTのアドレスが入っており、そこを伝ってPDPTへ飛びます。

PDPTはPage Directory Pointer Tableの略でPDのアドレスの保管場所です。

なので順番的には

PML4 → PDPT → PD → PT

の順番で値を探します。

このようにアドレスで分けるのは大きなテーブルを分解して探す手間を小さくするためです。
図書館から特定の本を見つけるのは難しいですが本棚で種類分けされていた場合、見つける手間が減ります。
同じように、情報を探すテーブルが大きいと探すのに時間がかかります。なのでアドレスによってテーブルを分けて1つのテーブルを小さくしています。

仮想アドレスから物理アドレスへの変換

参考資料:


メモリ保護ユニット(MPU)について

MPUはMemory Protection Unitの略で訳すとメモリ保護ユニットです。そのままですね。

MMUは物理アドレスを仮想アドレスに変換して扱いますがMPUは物理アドレスを変換せずそのままの値で扱います。

実際には以下のような役割を持っているようです。

  • キャッシュの動作管理

  • メモリアクセス管理

  • セキュリティ

  • セーフティ

キャッシュの動作管理は限られた資源であるキャッシュメモリを有効活用するためにキャッシュメモリに保存される情報を判別するという機能です。

もっと細かく言うと一部のフラッシュメモリだけがキャッシュされるようにするための機能です。
高速化したいコードをフラッシュメモリの特定のアドレスに置くとそのコードの内容だけがキャッシュに保存されます。

そして重要なのはそれ以外のフラッシュメモリ内のデータは
キャッシュ禁止です。

キャッシュは早いですが管理が難しいのでキャッシュする情報を絞ることで安全性、リアルタイム性、性能を両立しやすくなります。

メモリアクセス管理はメモリにどのようなアクセスを許すかを管理する機能です。

セキュリティはデータへのアクセス制限をかけることで不正なアクセスを防止します。

セーフティはプログラムがバグで暴走した時などに重要メモリを書き換え禁止にしておくことで重大破損を防ぐための機能です。

MPUは主に組み込みOSに使われる機能で、OSでは代わりにMMUが使われています。そのためめちゃくちゃ簡単に書きましたが詳しく知りたい方は以下の参考資料をご覧ください。


参考資料:


ページングの種類

プログラムやユーザー側から見るとCPUは仮想アドレスを使っているように見えますが実際には仮想アドレスを物理アドレスに変換する必要があります。

その方式としてセグメントやページングなどの方法があり、現在ではページングが主流です。

ページングの種類には以下のようなものがあります。

  • 32-bit

  • PAE

  • PML4

  • PML5 

32-bitページングは昔のページング方式であり主に32bit CPUモードで動作するOSや、古いOS、組み込みOSで使われています。
Windows XP、Windows 7、Linux、FreeBSDなどですね

PAEページングはPhysical Address Extensionsの略でExtensionsをgoogle翻訳にかけると拡張機能という意味でした。直訳すると物理アドレス拡張機能ですね。
その名の通り、32bitページングの拡張版です。
主にWindows 2000 Advanced Server、Windows Server 2003、Windows Server 2008ですね、全部サーバー用途のOSです。

PML4ページングはPage Map Level 4の略で現在のページング方式の主流です。主にWindows 10、Windows 11、Windows Server 2022、Ubuntuなどです。

PML5ページングはPage Map Level 5の略でLinuxなどで対応しています。


参考資料:


仮想環境時のEPT

EPTはExtended Page Tableの略です。Extendedは拡張という意味なのでExtended Page Tableは拡張されたページテーブルという意味になります。

仮想環境上で仮想化されたOSをゲストOSと言います。逆に仮想環境を動かしているOSをホストOSと言います。
EPTは仮想環境時にゲストOSが仮想アドレスから変換した物理アドレスをホストOSが扱う物理アドレスに変換するための構造体です。


参考資料:


CPUの実行サイクルについて

CPUがプログラムを実行する際の処理について説明します。

最初にプログラムカウンタから命令が保存されている主記憶のアドレスを取り出してそれをもとに命令の位置を探します。

その後、命令を取り出して命令レジスタに保存します。

命令は処理内容と処理に使う値のアドレス(計算が必要)で出来ています。
処理内容を取り出して命令デコーダという制御装置でコードを解析し必要な装置に制御信号を送ります。

命令がALUに送られ処理に使う値のアドレスが計算されアドレスから値の位置を探します。
その値は汎用レジスタに保存されます。

汎用レジスタの中の値をALUに読み込んで実行します。
その演算結果を汎用レジスタに書き込みそれをもとにメモリに書き込みます。


参考資料:



identity mapping

仮想アドレスと物理アドレスを同じにすることです。
CPUがページングを読み込んだ直後、CPUのレジスタは書き換わりません。

プログラムカウンタにある値は変わってないので、一瞬だけ仮想アドレスと物理アドレスを同じにするページングを行う必要があります。

それがidentity mappingです。日本語だと同一性マッピングです。

identity mappingを行わない場合

ただしその状態のままだと完全なページングとは言えないのでページングテーブルを切り替える必要があります。

その後、完全版のページテーブルを作りそのメモリアドレスにジャンプしてからIdentityMappingのページングを消して再ロードする。

それでページング移行は終了です

ページング作成時の流れ


参考資料:

https://f.osdev.org/viewtopic.php?t=57323


おわりに

今回はいろいろ書きました。
これからも短くてもいいからちょくちょく気になったことをまとめていきましょうかね。ではまたいつか……

いいなと思ったら応援しよう!