Spikeの実装を読みながらハイパーバイザー向けのレジスタ実装を確認する。
ハイパーバイザーステータスレジスタ (hstatus
)
VSモードでのゲストの例外動作および制御の記録を行っている。
命令での使用:ハイパーバイザーメモリアクセス命令において、
HSTATUS.HU
ビットに応じて実行許可条件が変わる。riscv-isa-sim/riscv/insns/hlv_b.h
require_extension('H');
require_novirt();
require_privilege(get_field(STATE.hstatus, HSTATUS_HU) ? PRV_U : PRV_S);
WRITE_RD(MMU.guest_load_int8(RS1));
- レジスタへの書き込み:書き込み可能な場所にのみ通常通り書き込む
- 例外・割り込み発生時:
mideleg
,medeleg
によってHSレベルに例外・割り込みが移譲される場合、現在のステートをHSTATUS
に書き込む。
void processor_t::take_trap(trap_t& t, reg_t epc) { /* ... 中略 ... */ } else if (state.prv <= PRV_S && bit < max_xlen && ((hsdeleg >> bit) & 1)) { // Handle the trap in HS-mode set_virt(false); reg_t vector = (state.stvec & 1) && interrupt ? 4*bit : 0; state.pc = (state.stvec & ~(reg_t)1) + vector; state.scause = t.cause(); /* ... 中略 ... */ set_csr(CSR_MSTATUS, s); s = state.hstatus; s = set_field(s, HSTATUS_SPVP, state.prv); s = set_field(s, HSTATUS_SPV, curr_virt); s = set_field(s, HSTATUS_GVA, t.has_gva()); set_csr(CSR_HSTATUS, s); set_privilege(PRV_S); } else { // Handle the trap in M-mode
- 例外からの復帰:
SRET
命令の場合、HSTATUS.SPV
をチェックして仮想化モードに戻るかどうかを設定している。 riscv-isa-sim/riscv/insns/sret.h
if (!STATE.v) {
reg_t prev_virt = get_field(STATE.hstatus, HSTATUS_SPV);
p->set_virt(prev_virt);
}
ハイパーバイザーTrap移譲レジスタ (hedeleg
/ hideleg
)
割り込み・例外移譲レジスタは割り込み・例外発生時の移譲条件の確認に使用されている。
riscv-isa-sim/riscv/processor.cc
void processor_t::take_interrupt(reg_t pending_interrupts) { reg_t enabled_interrupts, deleg, status, mie, m_enabled; reg_t hsie, hs_enabled, vsie, vs_enabled; /* ... 中略 ... */ if (enabled_interrupts == 0) { // HS-ints have higher priority over VS-ints deleg = state.mideleg & ~state.hideleg; status = (state.v) ? state.vsstatus : state.mstatus; hsie = get_field(status, MSTATUS_SIE); hs_enabled = state.prv < PRV_S || (state.prv == PRV_S && hsie); /* ... 中略 ... */ } } void processor_t::take_trap(trap_t& t, reg_t epc) { if (debug) { fprintf(log_file, "core %3d: exception %s, epc 0x%016" PRIx64 "\n", id, t.name(), epc); /* ... 中略 ... */ if (interrupt) { vsdeleg = (curr_virt && state.prv <= PRV_S) ? (state.mideleg & state.hideleg) : 0; hsdeleg = (state.prv <= PRV_S) ? state.mideleg : 0; bit &= ~((reg_t)1 << (max_xlen-1)); } else { vsdeleg = (curr_virt && state.prv <= PRV_S) ? (state.medeleg & state.hedeleg) : 0; hsdeleg = (state.prv <= PRV_S) ? state.medeleg : 0; }