Skip to content

Instantly share code, notes, and snippets.

@kotet
Last active September 20, 2022 10:52
Show Gist options
  • Save kotet/ccdf1d6adb97de6b4e68c93c8db348c3 to your computer and use it in GitHub Desktop.
Save kotet/ccdf1d6adb97de6b4e68c93c8db348c3 to your computer and use it in GitHub Desktop.
RISC-V privileged ISA 3.1.6 Machine Status Registers (mstatus and mstatush) の日本語訳

mstatusレジスタはMXLENビットのレジスタであり、図3.6,3.7のようなフォーマットをしている。 mstatusレジスタはhartsの実行状態の保持と操作を行う。 SレベルISAにはmstatusレジスタの制限されたビューとしてsstatusレジスタが存在する。


図 3.6: RV32でのmstatusレジスタ

31 30 .. 23 22 21 20 19 18 17 16 .. 15 14 .. 13 12 .. 11 10 .. 9 8 7 6 5 4 3 2 1 0
SD WPRI TSR TW TVM MXR SUM MPRV XS[1:0] FS[1:0] MPP[1:0] VS[1:0] SPP MPIE UBE SPIE WPRI MIE WPRI SIE WPRI

(訳注: WPRIは予約領域。読み込み専用の0にしておく必要がある)


図 3.7: RV64でのmstatusレジスタ

63 62 .. 38 37 36 35 .. 34 33 .. 32 31 .. 23 22 21 20 19 18 17 16 .. 15 14 .. 13 12 .. 11 10 .. 9 8 7 6 5 4 3 2 1 0
SD WPRI MBE SBE SXL[1:0] UXL[1:0] WPRI TSR TW TVM MXR SUM MPRV XS[1:0] FS[1:0] MPP[1:0] VS[1:0] SPP MPIE UBE SPIE WPRI MIE WPRI SIE WPRI

RV32においてはmstatush30:4がRV64のmstatusレジスタのビット62:36を含む。

3.1.6.1 Privilege and Global Interrupt-Enable Stack in mstatus register

Global interrupt-enableビットがMモードとSモードに対してそれぞれMIESIEとして提供される。 このビットは割り込みハンドラのatomicityを保証するために使われる。

hartがモードxで実行されている時、割り込みはxIE==1のときglobally enabledであり、xIE==0のときglobally disabledである。 現在より低いモードw<xの割り込みは、wIEビットの値に関係なく無効である。 現在より高いモードy>xの割り込みは、yIEビットの値に関係なく有効である。 高い特権レベルのコードは、自分より低いレベルに制御を渡す前に各割り込み固有の有効ビットを設定することで自分のレベルの割り込みを無効化できる。

上位レベルの割り込みをすべて無効化することももちろん可能だが、同期トラップ、ノンマスカブル割り込み、リセットしか復帰の手段がなくなってしまうので通常はやらない。

ネストしたトラップをサポートするために、各特権モードはIEビットと特権モードの2レベルスタックを持つ。 xPIEはトラップの前のxIEビットの値を保持する。 xPPは前の特権モードを保持する。 xPPにはx以下のモードしか入らないため、MPPは2ビットでSPPは1ビットである。 特権モードyから特権モードxへのトラップが発生したとき、xPIEにはxIEの値が入り、xIEには0がセットされる。xPPyになる。

低い特権モードでは、任意のトラップは通常上位の特権モードで起き、割り込みは入るときに無効化される。 上位のトラップハンドラはトラップとリターンをスタック情報をもとに提供するか、または割り込まれたコンテキストに直ちに戻らない場合は、割り込みを再有効化する前にスタックを保存するため。スタックには1エントリしか必要ない。

MRETSRET命令はそれぞれMモードとSモードのトラップから帰るために使う。 xRET命令を実行したとき、xPPyだったならば、xIExPIEにセットされ、特権モードはyに変更され、xPIEは1になり、xPPはサポートされている中で最も低いモードになる(Uモードが実装されているならUになる)。 さらにxPP != Mのときは、MPRVに0をセットする。

xPPにサポートされる最も低い特権モードを入れることは、ソフトウェアバグの発見に役立つ。

xPPはWARLであり、x以下の特権モードが入る。モードxが実装されていない場合、xPPは読み込み専用の0でなければならない。

MモードのソフトウェアはMPPに値を書き込んでからそれを読むことで実装されている特権モードを検出できる。 マシンがUとMしか提供しない場合、MPPに必要なハードウェアストレージは00と11を表現するための1ビットしか必要ない。

3.6.1.2 Base ISA Control in mstatus register

RV64システムにおいて、SXLUXLフィールドはそれぞれSモードとUモードでのXLENを操作するWARLのフィールドである。 エンコーディングはmisaレジスタのMXLと同じである。(表3.1参照)


表3.1: misaのMXLフィールドのエンコーディング

MXL XLEN
1 32
2 64
3 128

RV32システムでは、SXLUXLフィールドは存在せず、SXLEN=32,UXLEN=32である。

RV64システムにおいて、Sモードがサポートされないとき、UXLは読み込み専用で0である。サポートされるときはSXLENの値をエンコードするWARLフィールドである。 実装はUXLを読み込み専用にして、常にUXLEN=MXLENUXLEN=SXLENにできる。

各モードのXLENはサポートされる最大のXLEN以下に設定される。 すべての操作は、ソースオペランドレジスタの、設定されたXLENより上のビットを無視しなければならない。 また、符号拡張はサポートされるXLENの最大までディスティネーションレジスタを埋めなければならない。 同様に、XLENより上のpcのビットは無視され、pcに書き込みがあった時は、符号拡張はサポートされる最大のXLENまで行われる。

実装依存の振る舞いを避けるため、仕様は常にハードウェアレジスタ全体を定義された値で埋めることを要求している。 ハードウェアの複雑性を削減するために、低い特権モードのXLENが上位の特権モードのXLEN以下かのチェックを課していない。 そのような設定はソフトウェアのバグだが、マシンの操作はwell-definedである。

MXLENが32から広がった時、mstatusSXLUXLフィールドは、single valueに制限されていない場合、サポートされている中で新しいMXLEN以下の最も広い値をとる。

3.1.6.3 Memory Privilege in mstatus Register

MPRV (Modify Privilege)ビットはeffective privilege mode、たとえばロードやストアを実行する特権モードを変更する。 MPRV==0のとき、ロードとストアは通常通り振る舞い、現在の特権モードの変換/保護メカニズムに従う。 MPRV==1のとき、ロードとストアのメモリアドレスは現在の特権モードがMPPにセットされた値であるかのように変換、保護、エンディアンが適用される。 命令アドレス変換と保護はMPRVの値の影響を受けない。 MPRVはUモードがサポートされないとき読み込み専用の0になる。

特権モードをMより低くするMRET命令やSRET命令はMPRV=0という設定をする。

MXR (Make Executable Readable)ビットは仮想メモリのロードアクセスを行う特権モードを変更する。 MXR==0のとき、読み込み可能なページ(ページテーブルでR==1と設定されているページ)のみ読み込める。 MXR==1のとき、ページの読み込みは読み込み可能または実行可能なもの(R==1 || X==1)が成功する。 MXRはページベース仮想メモリが働かないときには影響がない。 MXRはSモードがサポートされないときは読み込み専用の0になる。

MPRVMXRメカニズムはロードやストアのミスアラインのようなハードウェア機能の不足をエミュレートするMモードのルーチンの効率性のために考案された。 MPRVはソフトウェアでアドレス変換を行う必要をなくす。 MXRは実行のみが許可されているページから命令ワードを読むことを可能にする。 現在の特権モードと、MPPで指定されている特権モードのXLENは異なる可能性がある。 MPRV==1のとき、ロードとストアのメモリアドレスは3.1.6.2のルールに従い、現在のXLENMPPXLENであるかのようにふるまう。

SUM (Permit Supervisor User Memory Access) ビットはSモードの仮想メモリへのロードとストアの特権を変更する。 SUM==0のとき、SモードのUモードがアクセス可能なページ(U==1)へのメモリアクセスは失敗する。 SUM==1のとき、そのようなアクセスは許可される。 SUMは仮想メモリシステムの影響下にない場面では影響がない。 SUMはSモードで実行されている時以外は無視され、これはMPRV==1MPP==Sのときも同様である。 SUMはSモードがサポートされていないときやsatp.MODEが読み込み専用の0(訳注: アドレス変換/保護がサポートされない)になっているときは読み込み専用の0になる。

MXRSUMメカニズムはページテーブルエントリの許可の解釈にのみ影響する。 PMAPMPによるアクセスフォールト例外には影響しない。

3.1.6.4 Endianness Control in mstatus and mstatush Registers

MBE, SBE, UBEは命令フェッチ以外のメモリアクセスのエンディアンを制御する。 命令フェッチは常にリトルエンディアンである。 MBEはMモードからの非命令フェッチメモリアクセスを(mstatus.MPRV == 0であると仮定して)リトルエンディアン(MBE==0)かビッグエンディアン(MBE==1)にする。 Sモードがサポートされないとき、SBEは読み込み専用のゼロである。そうでないとき、SBEはUモードからの明示的ロードとストアがリトルエンディアン(SBE==0)かビッグエンディアン(SBE==1)かを制御する。 UBEも同様。

ページテーブルのようなメモリ管理データ構造への暗黙的アクセスのエンディアンは常にSBEによって制御される。 SBEの変更は実装がそのようなデータ構造をどのように解釈するかを変えるため、SBEが変更された後もデータ構造を利用するなら、MモードソフトウェアはSFENCE.VMA命令をrs1=x0,rs2=x0で実行することで変更に追従しなければならない。

メモリ管理データ構造がリトルエンディアンとビッグエンディアンの両方で解釈されるというのは非常に不自然な状況である。 実用上、SBEはworld switch(訳注: ゲストOSの切り替え)の実行時にのみ変更され、その場合においては新旧のメモリ管理データ構造はそれぞれ異なるエンディアンで再解釈される。 この場合において、world switchに必要な分以上のSFENCE.VMA命令は不要である。

Sモードがサポートされるとき、実装はSBEMBEの読み込み専用のコピーにできる。 Uモードがサポートされるとき、実装はUBEMBEかSBEの読み込み専用のコピーにできる。

MBE,SBE,UBEがすべて読み込み専用の0のとき、実装はリトルエンディアンのメモリアクセスのみをサポートする。 MBEが読み込み専用の1で、各モードがサポートされるときにSBEUBEがそれぞれ読み込み専用の1であるとき、実装はビッグエンディアンのメモリアクセスのみをサポートする。

Volume 1ではhartsのアドレス空間を連続したアドレスの2^XLENバイトのcircular sequenceであると定義した。 アドレスとバイトの配置の対応はエンディアンに影響されず、固定である。 エンディアンはメモリバイトとマルチバイト量(halfword, word, etc)の間のマッピングの順番を決定する。

標準RISC-V ABIはリトルエンディアンかビッグエンディアンのどちらかのみを期待しており、エンディアンの混在に適応しない。 しかしながらエンディアンの制御は定義され許可されている。 例として、OSをあるエンディアンで実行し、ユーザーモードアプリケーションを別のエンディアンで実行するといったことがありうる。 メモリアクセスのエンディアンを必要に応じてソフトウェアで反転させるような、非標準的な使用法も考慮されている。

RISC-V命令はエンディアンの設定から切り離され、一様にリトルエンディアンであり、これはハードウェアとソフトウェアにとって都合がよいためである。 エンディアンの設定に従うとすると、実行時にエンディアンが動的に変化する可能性があるため、RISC-Vアセンブラとディスアセンブラは常に現在のエンディアンを知る必要がある。 一方で、命令のエンディアンが固定されていれば、PIC (position-independent code)のようなエンディアンに依存しないよう注意して書かれたソフトウェアが可能になる。 しかし、命令をリトルエンディアンのみにするという選択はマシン命令をエンコード/デコードするRISC-Vソフトウェアに影響がある。 ビッグエンディアンモードでは、そのようなソフトウェアは命令の明示的ロード/ストアのエンディアンが逆であるという事実に直面し、ロード後やストア前にバイトオーダーをスワップする必要がある。

3.1.6.5 Virtualization Support in mstatus Register

TVM (Trap Virtual Memory)ビットはスーパーバイザ仮想メモリ管理操作のインターセプティングをサポートするWARLのフィールドである。 TVM==1のとき、Sモードで実行中に行われたsatp CSRへの読み書きやSFENCE.VMASINVAL.VMA命令は不正命令例外を引き起こす。 TVM==0のとき、これらの操作はSモードで許可される。 TVMはSモードがサポートされないとき読み込み専用の0になる。

TVMメカニズムは、ゲストオペレーティングシステムをUモードを使った古典的な仮想化ではなく、Sモードで実行することを許可することで仮想化の効率化につながる。 このアプローチによってSモードのほとんどのCSRへのアクセスをトラップする必要がなくなる。 satpへのアクセスとSFENCE.VMASINVAL.VMA命令のトラップによって、シャドウページテーブルをlazyに設定するために必要なフックが提供される。

TW (Timeout Wait)ビットはWFI命令(訳注: Wait for Interrupt, 3.3.3節参照。実装はこの命令をヒントにしてストールできる?)のインターセプトをサポートするWARLのフィールドである。 TW==0のとき、WFI命令は他に阻害する理由がない限り低い特権モードで実行できる。 TW==1のとき、WFIが低い特権モードで実行され、実装固有の制限時間内に完了しなかった場合、WFI命令は不正命令例外を発生させる。 制限時間が常に0である場合には、WFITW==1で低い特権モードで実行された際は常に不正命令例外を発生させる。 TWはMより低い特権モードが無い場合読み込み専用の0になる。

WFI命令のトラップは、現在のゲストを無駄にアイドルさせることなく、別のゲストOSへ世界をスイッチするのに利用できる。

Sモードが実装されている時、WFIをUモードで実行すると、実装固有の制限時間内に完了しない場合不正命令例外を発生させる。 この仕様の今後のリビジョンではUモードでのWFIをSモードで許可する機能を追加する予定である。 そのような機能はTW==0のときのみアクティブになる。

TSR (Trap SRET)ビットはスーパーバイザ例外リターン命令SRETのインターセプトをサポートするWARLのフィールドである。TSR==1のとき、SモードでのSRETの実行は不正命令例外を発生させる。TSR==0のとき、この操作はSモードで許可される。TSRはSモードがサポートされないとき読み込み専用の0になる。

SRETのトラップはハイパーバイザ拡張(8章参照)を、それを提供しない実装上でエミュレートするために必要となる。

3.1.6.6 Extension Context Status in mstatus Register

拡張の充実したサポートはRISC-Vの主要なゴールのひとつであるため、スーパーバイザレベルのOSのような特権モードコードを変更することなく、任意のユーザーモードステート拡張をサポートするための標準インターフェースを定義している。

現在、標準拡張のなかでV拡張のみが浮動小数点数CSRとデータレジスタ以外の追加のステートを定義している。

FS[1:0]VS[1:0]はWARLのフィールドであり、XS[1:0]は読み込み専用のフィールドである。 これらはコンテキストセーブとリストアのコストを、浮動小数点数ユニットやその他のユーザーモード拡張の現在の状態を設定、トラッキングすることで削減するために使われる。 FSフィールドは浮動小数点数ユニットの、浮動小数点数レジスタf0-f31やCSR fcsr,frm, fflagsを含む状態をエンコードするフィールドである。 VSフィールドはベクタ拡張の、ベクタレジスタv0-v31やCSRvcsr,vxrm,vxsat,vstart,vl,vtype,vlenbを含む状態をエンコードするフィールドである。 XSフィールドは追加のユーザーモード拡張と関連する状態をエンコードする。 これらのフィールドはコンテキストスイッチルーチンがステートセーブとリストアが必要かどうかを素早く確認するために利用できる。 セーブやリストアが必要ならば、プロセスを達成/最適化するために通常は追加の命令とCSRが必要となる。

この設計は、浮動小数点数ユニットやその他の拡張の状態のセーブ/リストアのためのコンテキストスイッチがほとんどの場合で不要であると想定しており、そのため素早いチェックのためのSDビットを提供している。

FS,VS,XSフィールドはすべて同じ表3.3のようなエンコードを使う。 これはOff, Initial, Clean, Dirtyの4状態を表現する。


表3.3: FS[1:0], VS[1:0], XS[1:0]ステータスフィールドのエンコーディング

状態 FSとVSの意味 XSの意味
0 Off すべてOff
1 Initial DirtyやCleanのものが無く、オンのものがある
2 Clean Dirtyのものが無く、Cleanのものがある
3 Dirty Dirtyのものがある

F拡張が実装されている場合、FSフィールドは読み込み専用の0にしてはならない。

F拡張かSモードが実装されていない場合、FSは読み込み専用の0になる。 Sモードが実装されておりF拡張が実装されていない場合、FSは読み込み専用の0にしてもよい。

F拡張がなく、Sモードのある実装は許可されているが、その場合にFSフィールドを読み込み専用の0にすることは要求されていない。 Mモードへの不可視のトラップによるSモードとUモードにおけるF拡張のエミュレーションを有効にするために、実装はFSフィールドを読み込み専用の0にしない選択をできる。

vレジスタが実装されているとき、VSフィールドは読み込み専用の0にしてはならない。 vレジスタかSモードが実装されていないとき、VSは読み込み専用の0になる。 Sモードが実装されていてvレジスタが実装されていないとき、VSは読み込み専用の0にできる。

新しい状態を必要とする追加のユーザ拡張の無いシステムでは、XSフィールドは読み込み専用の0になる。 状態を持つすべての追加拡張はXSフィールドと等価なエンコードのCSRを提供する。 XSフィールドはすべての拡張のサマリを表現する。

各拡張はXSと異なるエンコーディングを使えるが、XSフィールドはすべてのユーザ拡張ステータスフィールドの最大の状態値を効率的に報告する。

SDビットはFS,VS,XSフィールドの中の、拡張ユーザコンテキストをメモリに保存する必要のあるダーティステートの存在を要約する読み込み専用のビットである。 FS,XS,VSがすべて読み込み専用のゼロならば、SDも常にゼロである。

拡張の状態がOffに設定されている時、関連する状態への読み書きは不正命令例外を発生させる。 状態がInitialの時、関連する状態は初期定数値にすべきである。 状態がCleanの時、関連する状態は初期値ではない可能性があるが、コンテキストスワップで最後にストアされた値とマッチする。 状態がDirtyのとき、関連する状態は最後のコンテキストセーブから変更された可能性がある。

コンテキストセーブの間、その責務を負う特権コードが書き出す必要のあるのは状態がDirtyである関連ステートのみであり、その後拡張の状態をCleanにリセットできる。 コンテキストリストアの間、メモリからロードする必要のあるコンテキストは状態がCleanのもののみである(リストア時にはDirtyにはならない)。 状態がInitialのとき、セキュリティホールを避けるために、コンテキストリストア時にコンテキストは初期定数値に設定されなければならないが、これはメモリにアクセスすることなく行える。 たとえば、浮動小数点レジスタはすべて即値0で初期化できる。

FSXSフィールドはコンテキストの保存前に特権コードによって読まれる。 FSフィールドはユーザーコンテキストから復帰する際に特権コードによって直接設定され、XSフィールドは各拡張のステータスレジスタへの書き込みによって間接的に設定される。 特権モードにかかわらず、ステータスフィールドも命令実行時に更新される。

ユーザーモードISAの拡張はしばしば追加のユーザーモードステートを含み、そのステートはベース整数レジスタよりも大きくなりうる。 拡張は特定のアプリケーションでのみ使われたり、ごく短い期間しか使われないことがある。 パフォーマンスの改善のために、ユーザーモード拡張はユーザーモードソフトウェアがユニットを初期状態にしたりオフにしたりできる追加命令を定義できる。

たとえば、利用前に設定が必要で、利用後は「未設定」状態にできるようなコプロセッサがありうる。 未設定状態はコンテキストセーブに対して初期状態として表現すべきである。 同じアプリケーションが未設定状態から次に設定が行われる(状態をDirtyとして設定する)までの間走り続けるとき、設定解除命令で実際に状態を初期化する必要はない。 たとえば、初期状態はコプロセッサの状態を設定解除ごとにおいてではなく、コンテキストリストアにおいて定数で初期化するのみである場合である。

ユニットを無効化しOff状態にするユーザーモード命令を実行すると、それに続く命令がユニットを有効化する前に利用しようとした際に不正命令例外を発生させる。 ユニットをオンにするユーザーモード命令はユニットの状態を適切に初期化しなければならない。 これはユニットをオンにするまでの間に他のコンテキストがユニットを利用している可能性があるためである。

FSの設定を変更しても浮動小数点レジスタの状態は変化しない。 特に、FS=Offは状態を破壊せず、FS=Initialは内容をクリアしない。 同様に、VSの設定はベクタレジスタファイルの内容に影響を及ぼさない。 ただし、他の拡張はOffに設定した際に状態を保持するとは限らない。

実装は、実際に変更が行われていないにもかかわらず状態をDirtyにすることで、浮動小数点レジスタの状態を不正確にトラックすることを選択できる。 実装によっては、浮動小数点レジスタの状態を変えない命令が状態をInitialCleanからDirtyに変えることがありうる。 また他の実装では、dirtinessをまったくトラックせず、有効なFSの状態をOffDirtyのみにして、FSInitialCleanを設定するとDirtyになるようにできる。

このFSの定義はFSを間違った予測によってDirtyにすることを禁止していない。プラットフォームはサイドチャネルのポテンシャルを閉ざすためにFSに投機的に書き込むことを禁止できる。

命令が明示的/暗黙的に浮動小数点レジスタやfcsrへ書き込みを行ったがその内容が変わらず、かつFS=InitialまたはFS=Cleanのとき、FSがDirtyになるかどうかは実装依存である。

実装はベクタレジスタのdirtinessを、ソフトウェアがVS=initialVS=Cleanに設定しようとしたときにVSDirtyにすることを含め、不正確な方法でトラックすることを選択できる。 VS=InitialまたはVS=Cleanのとき、ベクタレジスタやベクタCSRへの書き込みがあったがその内容が変化しなかった際にVSDirtyになるかどうかは実装依存である。

表3.4はFS,VS,XS状態ビットの可能なすべての状態遷移である。 標準浮動小数点数とベクタ拡張はユーザーモード設定解除や無効化/有効化命令をサポートしないことに注意。


表3.4: FS, VS, XSの状態遷移

mstatus-table34


拡張の状態を初期化、保存、リストアする標準特権命令は、状態を等価的オブジェクトとして扱うことで追加拡張の詳細を特権コードから隠蔽するために提供される。

多くのコプロセッサ拡張は、ソフトウェアが利用終了時に安全に設定解除や無効化を行えるような制限されたコンテキストでのみ使われる。 これによって大きなステートフルコプロセッサのコンテキストスイッチのオーバーヘッドが削減される。 仕様は浮動小数点の状態を他の拡張の状態から分離している。 これは浮動小数点ユニットが存在するとき浮動小数点レジスタは標準呼び出し規約の一部であり、ユーザーモードソフトウェアは浮動小数点ユニットを安全に無効化できるか知ることができないからである。

XSフィールドはすべての追加拡張ステートの要約を提供するが、コンテキストセーブとリストアのオーバーヘッドをさらに削減するために追加のマイクロアーキテクチャビットを持つこともできる。

SDビットは読み込み専用であり、FS, VS, XSビットのどれかひとつでもDirtyのときにセットされる(SD=((FS == 11) || (XS == 11) || (VS == 11)))。 これによって特権コードは整数レジスタやPC以上に追加のコンテキストセーブが必要かどうかを素早く判断できる。

浮動小数点ユニットステートは常に標準命令を使って初期化、保存、復元され(F,D, and/or Q)、特権コードは各fレジスタを保持するための適切な領域を判断するためにFLENに気をつけなければならない。

マシンモードとスーパーバイザモードはFS, VS, XSビットのコピーを共有する。 スーパーバイザレベルソフトウェアは通常、FS, VS, XSビットをスーパーバイザレベルで保存されるコンテキストを記録するために直接利用する。 マシンレベルソフトウェアは拡張の状態のセーブとリストアを、それらに対応するコンテキストのバージョンにおいてより保守的に行わなくてはならない。

合理的に考えられるあらゆるユースケースにおいて、ユーザーレベルとハイパーバイザレベルの間のコンテキストスイッチの数は他の権限レベルへのコンテキストスイッチよりもはるかに多いはずである。 コプロセッサは非同期例外を提供するために、その非同期例外がユーザレベルコンテキストスワップを引き起こさない限り、コンテキストのセーブとリストアを行う必要はない。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment