Closed keigo1216 closed 11 months ago
それぞれのページテーブルのサイズは1ページに収まるように設定する. 今回実装しているOSのページサイズは4KB. AArch64アーキテクチャなので, 一つのアドレスに8バイト(64bit)の値が入る. つまり, 一つのテーブルのエントリ数を512(9bit)に設定すれば, 512 ・8 = 4096 ( = 4KB)になる 二段のページテーブルを構成する場合
| level1 [29:21] | level2 [20:12] | PA [11:0] |
level1
level2
PA
これは中段のページテーブルエントリに使う
| upper attributes [63:48] | Next-level table address [47:12] | ignore[11:2] | 1 | 1 |
upper attibutesの中身は
| NSTable [63] | AP Table [62:61] | UXN Table [60] | PXNTable [59] | ignore [58:52] |
NS Table セキュアレベルで実行するときに使うビット. OSやユーザーアプリケーションはノンセキュアなのでこのビットは無視される
NS Table
AP Table
00
01
10
EL0
EL3
11
UXN Table 下位レベルのルックアップで特定されて領域からフェッチされた命令のEL0の実行が許可されるかどうか決定する
UXN Table
0
1
PXN Table 下位レベルのルックアップで特定された領域からフェッチされた命令の特権状態の実行が許可されるかどうかを決定する
PXN Table
| Upper attributes [63:52] | UNK/SBZP [51:48] | Output address [47:12] | Lower attributes [11:2] | 1 | 1 |
UNK/SBZPはres0(reserved, should be zero)としてARMV8-Aで定義されている.これは「予約済みでゼロに設定されるべき」ことを示している.その他のビットは同じ(たぶん)
UNK/SBZP
res0
ARMV8-A
ページテーブルエントリの0bit目が1のとき、有効なエントリ. 0のとき、無効なエントリ
TTBR0_EL1(ユーザー用)とTTBR1_EL1(カーネル用)にページテーブルのベースアドレス(物理アドレス)を設定する.
TTBR0_EL1
TTBR1_EL1
| ASID [63:48] | BADDR[47:1] | CnP [0] |
CnP : 別々のプロセッサでページテーブルを共有するかどうか
CnP
TCR_EL1レジスタに設定する
TCR_EL1
TG0 [15:14] : EL0のページサイズ TG1 [31:30] : EL1のページサイズ T0SZ [5:0] : 64bitの仮想アドレスのうち、無視する上位ビットの長さを設定する(EL0) T1SZ [21:16] : 64bitの仮想アドレスのうち、無視する上位ビットの長さを設定する(EL1)
TG0 [15:14]
TG1 [31:30]
EL1
T0SZ [5:0]
T1SZ [21:16]
__free_ram
table
map
ARMではページテーブルのベースアドレスを保存するレジスタが二つ(ユーザー空間用、カーネル空間用)がある 基本的にはカーネル空間のマッピングはブート時に行いそれ以降変更しない ユーザー領域のページテーブルレジスタTTBR0_EL1レジスタにセットする
https://qiita.com/eggman/items/a8862d165cc0b4965f70
(これは4KBで三段のページテーブルを構成している例であることに注意)
中段のテーブルのエントリに使うもの
ページテーブルの最後に使うエントリ
SCTLR_EL1レジスタのWXN, bit [19] ここは, 書き込み可能領域に設定されているページは実行可能にしない設定のこと 悪意のあるコードを実行しないようにするため
SCTLR_EL1
WXN, bit [19]
https://grasslab.github.io/NYCU_Operating_System_Capstone/labs/lab8.html
ページテーブルと仮想アドレスの実装
ARMv8-Aの仮想アドレスの仕様
それぞれのページテーブルのサイズは1ページに収まるように設定する. 今回実装しているOSのページサイズは4KB. AArch64アーキテクチャなので, 一つのアドレスに8バイト(64bit)の値が入る. つまり, 一つのテーブルのエントリ数を512(9bit)に設定すれば, 512 ・8 = 4096 ( = 4KB)になる 二段のページテーブルを構成する場合
level1
で一段目のページテーブルのオフセット(9bit)level2
で二段目のページテーブルのオフセット(9bit)PA
が物理アドレスの下位12bit カーネルの仮想アドレスを指定するときは, 残りのビットを全て1にする必要がある(ページテーブルのベースアドレスを変更するため)ページテーブルエントリの仕様
テーブルディスクリプタ (Table descriptor)
これは中段のページテーブルエントリに使う
upper attibutesの中身は
NS Table
セキュアレベルで実行するときに使うビット. OSやユーザーアプリケーションはノンセキュアなのでこのビットは無視されるAP Table
00
: 後続のルックアップレベルにおける権限に影響を与えない. 後続のテーブルレベルで定義されたアクセス権限がそのまま適応される01
: EL0でのアクセスが許可されていないことを意味し, 後続のルックアップレベルの権限に関わらずこの設定が適応される(読み込みと書き込みが共にユーザーレベルでは許可されない)10
: どの例外レベル(EL0
からEL3
)でも書き込みアクセスが許可されておらず, 後続のルックアップレベルの権限に関わらずにこの設定が適応される11
: 後続のルックアップレベルの権限に関わらずEL0
での読み取りアクセスは許可されないUXN Table
下位レベルのルックアップで特定されて領域からフェッチされた命令のEL0
の実行が許可されるかどうか決定する0
: 後続のルックアップテーブルに影響なし1
: 後続のルックアップテーブルの全てのUXN Table
が、そこに設定されている値に関係なく1
として見られる(つまりユーザー空間での実行が禁止される)PXN Table
下位レベルのルックアップで特定された領域からフェッチされた命令の特権状態の実行が許可されるかどうかを決定する0
: 後続のルックアップテーブルに影響なし1
: 後続のルックアップテーブルの全てのPXN Table
が, そこに設定されている値に関係なく1
として見られるページディスクリプタ
UNK/SBZP
はres0
(reserved, should be zero)としてARMV8-A
で定義されている.これは「予約済みでゼロに設定されるべき」ことを示している.その他のビットは同じ(たぶん)有効化ビット
ページテーブルエントリの0bit目が
1
のとき、有効なエントリ.0
のとき、無効なエントリページテーブルのベースアドレスの登録
TTBR0_EL1
(ユーザー用)とTTBR1_EL1
(カーネル用)にページテーブルのベースアドレス(物理アドレス)を設定する.CnP
: 別々のプロセッサでページテーブルを共有するかどうか0
: 共有しない1
: 共有する コンテキストスイッチ時にTTBR0_EL1
にページテーブルのベースアドレスを設定するMMUの各種設定
TCR_EL1
レジスタに設定するTG0 [15:14]
:EL0
のページサイズTG1 [31:30]
:EL1
のページサイズT0SZ [5:0]
: 64bitの仮想アドレスのうち、無視する上位ビットの長さを設定する(EL0
)T1SZ [21:16]
: 64bitの仮想アドレスのうち、無視する上位ビットの長さを設定する(EL1
)実装方法
__free_ram
上に配置されればいいはずなので, 動的に確保してもいいはずtable
フィールドを作成して, ページテーブルの最上段の先頭アドレスを保持する(4KBで揃える)TTBR0_EL1
にページテーブルのベースアドレスを保存する。この際に、特殊な命令を打たないといけないらしいのでチェックするmap
関数を作成するRISC-Vでの実装と異なる点
ARMではページテーブルのベースアドレスを保存するレジスタが二つ(ユーザー空間用、カーネル空間用)がある 基本的にはカーネル空間のマッピングはブート時に行いそれ以降変更しない ユーザー領域のページテーブルレジスタ
TTBR0_EL1
レジスタにセットする参考文献
https://qiita.com/eggman/items/a8862d165cc0b4965f70