RISC-V IOMMUの構成について、概略をざっくり理解するためのメモ。
何回か読もうとして挫折してきたので、もう一度ちゃんと読んでみようと思う。
デバイスコンテキストの場所を特定するプロセス
device_idを使ってトランザクションのDevice-contextを見つけるプロセスは以下の通りである:
aをddtp.PPN x 212とし、i = LEVELS - 1とする。ddtp.iommu_modeが3LVLのとき、LEVELSは3である。ddtp.iommu_modeが2LVLのとき、LEVELSは2である。ddtp.iommu_modeが1LVLの場合、LEVELSは1である。- もし
i == 0ならステップ8に進む。 ddteをアドレスa + DDI[i] x 8の8バイトの値とする。ddteへのアクセスが PMA または PMP チェックに違反するならば、停止して "DDT entry load access fault" (cause = 257) を報告する。ddteアクセスがデータ破損(poison データ)を検出した場合、停止して"DDTデータ破損"(cause= 268)を報告する。ddte.V == 0なら、停止して "DDT entry not valid" (cause = 258) と報告する。ddte内に将来の標準使用のために予約されているビットやエンコーディングが設定されている場合、停止して"DDT entry misconfigured" (cause = 259) と報告する。i = i - 1とし、a = ddte.PPN x 212とする。 ステップ2に進む。DCをアドレスa + DDI[0] * DC_SIZEのDC_SIZEバイトの値とする。もしcapabilities.MSI_FLATが1ならば、DC_SIZEは64バイトであり、そうでなければ32バイトである。 もしDC へのアクセスがPMAまたはPMPチェックに違反するならば、停止し、"DDT entry load access fault" (cause = 257)を報告する。もしDCのアクセスがデータ破損(毒データ)を検出したら、停止して"DDTデータ破損"(cause=268)を報告する。DC.tc.V == 0の場合、停止し、"DDT entry not valid" (cause = 258)と報告する。- DC が ???に概説された規則によって決定されるように誤って設定されている場合、停止して "DDT entry misconfigured" (cause = 259) と報告する。
- デバイスコンテキストの位置は正常に特定される。
プロセスコンテキストを見つけるプロセス
device-contextはPDTルートページPPN(pdtp.ppn)を提供する。
DC.iohgatp.mode が Bare でない場合、 pdtp.PPN と pdte.PPN はゲスト物理アドレス(GPA)であり、 DC.iohgatp が指す第2ステージのページ・テーブルを使用して、スーパーバイザ物理アドレス(SPA)に変換されなければならない。
PDTへのメモリ・アクセスは、第2ステージによって暗黙の読み取りメモリ・アクセスとして扱われる。
process_id を使ってトランザクションのProcess-contextを見つける処理は以下の通りである:
aをpdtp.PPN x 212とし、i = LEVELS - 1とする。pdtp.MODEがPD20のとき、LEVELSは3である。pdtp.MODEがPD17のとき、LEVELSは2つです。pdtp.MODEがPD8の場合、LEVELSは1である。DC.iohgatp.mode != Bareならば、aは GPA である。aを暗黙のメモリアクセスとしてSPAに変換するプロセスを呼び出す。 もしaの第2段アドレス変換中にフォルトが発生したら、第2段アドレス変換プロセスによって検出されたフォルトを停止して報告する。変換されたaは以降のステップで使用される。- もし
i == 0ならステップ9に進む。 pdteをアドレスa + PDI[i] x 8の8バイトの値とする。pdteへのアクセスが PMA または PMP チェックに違反するならば、停止して"PDT entry load access fault" (cause = 265) を報告する。- もし
pdteアクセスがデータ破損(poisonデータ)を検出したなら、停止して "PDTデータ破損"(cause=269)を報告する。 pdte.V == 0の場合、停止して "PDT entry not valid"(cause=266)と報告する。pdte内に将来の標準使用のために予約されているビットやエンコーディングが設定されている場合、停止して"PDT entry misconfigured" (cause = 267) と報告する。i = i - 1とし、a = pdte.PPN x 212とする。 ステップ2に進む。- PC をアドレス
a + PDI[0] x 16の16バイトの値とする。PCへのアクセスが PMA または PMP チェックに違反するならば、停止して"PDT entry load access fault" (cause = 265) を報告する。もしPCアクセスがデータ破損(poisonデータ)を検出するならば、停止して"PDTデータ破損"(cause=269)を報告する。 PC.ta.V == 0の場合、停止し、"PDT entry not valid" (cause = 266)と報告する。PCが誤って設定されている場合、停止して"PDT entry misconfigured"(cause=267)と報告する。- プロセス・コンテキストの位置が正常に特定される。
MSI のアドレスを変換するプロセス
I/OデバイスがゲストOSによって直接設定される場合、デバイスからのMSIは、ゲストOSの仮想マシン内の仮想IMSICをターゲットとし、実マシンには不適切で安全でないゲスト物理アドレスを使用することが予想される。 IOMMUは、そのようなデバイスからの特定の着信書き込みをMSIとして認識し、実マシン用に必要に応じて変換しなければならない。
変換を必要とする1つのデバイスから発信されるMSIは、1つのRISC-V仮想マシン内で実行される1つのゲストOSによってデバイスに設定されていることが期待される。 VM自体がRISC-V Advanced Interrupt Architectureに準拠していると仮定すると、MSIは仮想IMSICの割り込みファイルのメモリ・マップされたレジスタに書き込むことで、VM内の仮想HARTに送信される。 これらの仮想割り込みファイルはそれぞれ、VMのゲスト物理アドレス空間内の個別の4KiBページを占有する。 このため、ゲスト物理アドレスへの書き込みが、VM内の仮想IMSICの割り込みファイルによって占有されているページへの書き込みであれば、仮想HARTへのMSIとして認識することができる。
MSI アドレス変換がサポートされている場合 (capabilities.MSI_FLAT, [CAP]) 、入力された IOVA を仮想割り込みファイルのアドレスとして識別し、MSI ページテーブルを使用してアドレスを変換するプロセスは次のようになる:
AをGPAとする。DCを Process to locate the Device-context に概説されているプロセスを使用してデバイスのdevice_idを使用して見つけられたデバイスコンテキストとする。- アドレス
AがMSIアドレスマスク(msi_addr_mask)とパターン(msi_addr_pattern)で指定された仮想割り込みファイルへのアクセスかどうかを判断する。 - もしアドレスが仮想割り込みファイルのものであると判断されなかった場合は、この処理を停止し、代わりにアドレス変換を行うために通常の変換データ構造を使用する。
Aから割り込みファイル番号IをI = extract(A >> 12, DC.msi_addr_mask)として抽出する。ビット抽出関数extract(x, y)は、マスクxの同じ位置にある一致するビットがゼロであるyからのすべてのビットを破棄する、 そして、xからの残りのビットを、xと同じビット順序を保ちながら、結果の最下位端で連続的にパックし、結果の最上位端にある他のビットをゼロで埋める。例えば、xとyのビットが次のような場合:x = a b c d e f g hy = 1 0 1 0 0 1 1 0- とすると、
extract(x, y)の値はビット0 0 0 a c f gを持つ。
mを(DC.msiptp.PPN x 2^12)とする。msipteをアドレス(m|(I×16))の16バイトの値とする。` msipt`eへのアクセスが PMA または PMP チェックに違反する場合、停止して "MSI PTE load access fault" (cause = 261) を報告する。msipteアクセスがデータ破損 (毒データ) を検出した場合、停止して "MSI PT データ破損" (cause = 270) を報告する。msipte.V == 0の場合、停止して "MSI PTE not valid"(cause = 262)と報告する。msipte.C == 1の場合、PTEを解釈するためのさらなる処理は実装で定義されている。msipte.C == 0の場合、処理は以降のステップで概説される。msipte.M == 0またはmsipte.M == 2の場合、停止し、"MSI PTE misconfigured" (cause = 263)を報告する。msipte.M == 3の場合、PTEは基本トランスレートモードであり、トランスレート処理は以下のようになる:msipte内に将来の標準使用のために予約されているビットまたはエンコーディングが設定されている場合、停止し、"MSI PTE misconfigured" (cause = 263)と報告する。msipte.PPN << 12 | A[11:0]として変換されたアドレスを計算する。msipte.M == 1の場合、PTEはMRIFモードであり、変換処理は以下のようになる:capabilities.MSI_MRIF == 0の場合、停止し、"MSI PTE misconfigured" (cause = 263) と報告する。msipte内に将来の標準使用のために予約されているビットまたはエンコーディングが設定されている場合、停止して "MSI PTE misconfigured" (cause = 263) を報告する。- 宛先MRIFのアドレスは
msipte.MRIF_Address[55:9] * 512である。 - 通知MSIの宛先アドレスは
msipte.NPPN << 12である。 NIDを(msipte.N10 << 10) | msipte.N[9:0]とする。 通知MSIのデータ値は11ビットのNID値をゼロ拡張して32ビットにしたものです。
- このプロセスによって決定される変換に関連するアクセス許可は、
R=W=U=1および X=0 を持つ通常のRISC-VセカンドステージPTEと同等である。 セカンドステージPTEと同様に、U ビットをチェックするとき、トランザクションはスーパーバイザ特権を要求していないものとして扱われる。 - トランザクションが未変更または変更された実行読み出しの場合は、停止して「命令アクセス・フォールト」(cause = 1)を報告する。
- MSI アドレス変換処理は完了する。
MRIF モードでは、Advanced Interrupt Architecture Specification に、受信 MSI を宛先 MRIF に格納し、通知 MSI を生成する動作が定義されている。 これらの動作はIOMMU自身が実行してもよいし、IOMMUが変換要求に応答してデスティネーションMRIFアドレス、通知MSIアドレス、通知MSIデータ値をI/Oブリッジに提供し、I/Oブリッジがその動作を実行してもよい。