Rocket-ChipのTLBの解析の続き。Rocket-ChipのPMAはTileLinkによって接続された各デバイスのアドレス情報を引っ張ってきてテーブルを作り、許可されるアドレス領域かどうかを判断していることが分かった。
具体的なテストケースを使って確認しよう。rv64mi-p-access
テストパタンをRocket-Chip(Chipyard)上で実行して確認してみよう。
./simulator-chipyard-RocketConfig-debug +verbose -v rv64mi-p-accses.vcd /home/msyksphinz/work/riscv/chipyard/riscv-tools-install/riscv64-unknown-elf/share/riscv-tests/isa/rv64mi-p-access 2>&1 | spike-dasm | tee rv64mi-p-accses.log
この時にテストケースは非常に大きなアドレスにジャンプしようとしてTLBエラーが発生している。 このエラーが発生する仕組みを追いかける。
C0: 424 [1] pc=[0000000080000194] W[r 5=ffffffffffffffff][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[fff0029b] addiw t0, zero, -1 C0: 425 [1] pc=[0000000080000198] W[r 5=8000000000000000][1] R[r 5=ffffffffffffffff] R[r 0=0000000000000000] inst=[03f29293] slli t0, t0, 63 C0: 426 [1] pc=[000000008000019c] W[r 5=80000000800001dc][1] R[r 5=8000000000000000] R[r 7=00000000800001dc] inst=[0072c2b3] xor t0, t0, t2 C0: 427 [1] pc=[00000000800001a0] W[r 3=0000000000000002][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[00200193] li gp, 2 C0: 428 [1] pc=[00000000800001a4] W[r 6=0000000000000001][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[00100313] li t1, 1 C0: 429 [1] pc=[00000000800001a8] W[r 9=00000000800001a8][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[00000497] auipc s1, 0x0 C0: 430 [1] pc=[00000000800001ac] W[r 9=00000000800001b8][1] R[r 9=00000000800001a8] R[r 0=0000000000000000] inst=[01048493] addi s1, s1, 16 C0: 431 [1] pc=[00000000800001b0] W[r 7=0000000000000000][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[00000393] li t2, 0 C0: 432 [1] pc=[00000000800001b4] W[r 7=00000000800001b8][1] R[r 5=80000000800001dc] R[r 0=0000000000000000] inst=[000283e7] jalr t2, t0, 0 // ここでアドレス0x80000000800001dcにジャンプする。非常に大きなアドレスでアクセス許可範囲外 C0: 436 [0] pc=[ffffff80800001dc] W[r 8=0000000000000000][0] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[00000000] c.addi4spn s0, sp, 0 C0: 441 [1] pc=[0000000080000004] W[r30=0000000000000001][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[34202f73] csrr t5, mcause C0: 442 [1] pc=[0000000080000008] W[r31=0000000000000008][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[00800f93] li t6, 8 C0: 444 [1] pc=[000000008000000c] W[r 0=0000000000000000][0] R[r30=0000000000000001] R[r31=0000000000000008] inst=[03ff0a63] beq t5, t6, pc + 52
波形を確認すると、この時にTLBのinst.ae
信号が落ちている。これにより命令フェッチアクセスエラーが発生していることが明らかになった。
このinst.ae
信号はテーブルのhit
信号と、さらにpx_array
信号のAND演算によって成り立っている。
io.resp.ae.inst := (~px_array & hits).orR
px_array
信号は、テーブル12を参照している時にはprot_x
を参照する。このprot_x
信号は以下のような感じでfastCheck()
という関数で作成されている。まあこれがTileLinkのデバイスチェックに繋がっている。
val pr_array = Cat(Fill(nPhysicalEntries, prot_r), normal_entries.map(_.pr).asUInt) & ~ptw_ae_array val pw_array = Cat(Fill(nPhysicalEntries, prot_w), normal_entries.map(_.pw).asUInt) & ~ptw_ae_array val px_array = Cat(Fill(nPhysicalEntries, prot_x), normal_entries.map(_.px).asUInt) & ~ptw_ae_array
def fastCheck(member: TLManagerParameters => Boolean) = legal_address && edge.manager.fastProperty(mpu_physaddr, member, (b:Boolean) => Bool(b)) val prot_x = fastCheck(_.executable) && !deny_access_to_debug && pmp.io.x
legal_address
というのは、各デバイスが当該アクセスを許可できるかどうかを探索していることを意味する。mpu_phyaddr
が当該物理アドレス。
val legal_address = edge.manager.findSafe(mpu_physaddr).reduce(_||_)
具体的に波形を観察すると、これまではlegal_address_T_49
(おそらくメモリ領域だと思う)までのアクセスが許可されていたが、物理アドレスが0x8080001DC
となりその領域を外れ、どのデバイスのアドレス領域でも無くなってしまった。これによりlegal_address
がすべて0となり、命令フェッチのアクセスエラーへとつながるようだ。