FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RISC-V Testに実装されているページテーブルの実装を調査する (2. 仮想アドレスからのジャンプを調査する)

pop_tf()によるジャンプで、仮想アドレスで言う所の0x2ac8へのジャンプとなる。これによりユーザモードに移るわけだが、この時のアドレス計算を見てみよう。ジャンプ先は0x2ac8(仮想アドレス)なので、以下のような計算となる。

  • SATP0x8000000000080004なので、0x8000_4000が仮想アドレス計算の起点となっている(これはページテーブルの起点:ptの場所となっている )
  • 0x80004000pt[0]の起点なので、以下のコードによりpt[1]の先頭へのジャンプとなっている。
    • 0x8000_5000へのページテーブルのジャンプとなっている。
  • 0x80005000pt[1]の先頭なので、pt[3]へのジャンプとなっている。
  • ところがpt[3]は初期化されていないので、ページテーブル例外が発生する。
f:id:msyksphinz:20210320230939p:plain

ページテーブル例外を処理するのは、handle_trap()である。さらにページテーブル例外のためのhandle_fault()を呼び出す。

このhandle_fault()medelegによりスーパーバイザーモードで処理される。スーパーバイザーモードの例外での飛び先はstvecにより指定されている。

void handle_trap(trapframe_t* tf)
{
  if (tf->cause == CAUSE_USER_ECALL)
  /* ... 中略 ... */
  else if (tf->cause == CAUSE_ILLEGAL_INSTRUCTION)
  /* ... 中略 ... */
  else if (tf->cause == CAUSE_FETCH_PAGE_FAULT || tf->cause == CAUSE_LOAD_PAGE_FAULT || tf->cause == CAUSE_STORE_PAGE_FAULT)
    handle_fault(tf->badvaddr, tf->cause);
  else
    assert(!"unexpected exception");

  pop_tf(tf);
}

stvecの計算方法は以下の通り。pa2kva()を使っているのでkernel_l2pt()を経由してジャンプする仕組みになっている。

  write_csr(stvec, pa2kva(trap_entry));
f:id:msyksphinz:20210320231008p:plain

handle_fault()の仕組みは以下のようになっている。

f:id:msyksphinz:20210320231100p:plain

すでにページが割り当てられていない場合には、新たなページをfreelistから割り当て、PTEにそのページを設定する。

f:id:msyksphinz:20210320231127p:plain

さらにそこから先のuser_mappingへの割り当ては、さらに何をやっているのか良く分からない。