Introduce functions required to perform a p2m context switch during a vCPU context switch.
As no mechanism is provided to atomically change vsatp and hgatp together. Hence, to prevent speculative execution causing one guest’s VS-stage translations to be cached under another guest’s VMID, world-switch code should zero vsatp in p2m_ctx_swith_from(), then construct new hgatp and write the new vsatp value in p2m_ctx_switch_to(). Signed-off-by: Oleksii Kurochko <[email protected]> --- xen/arch/riscv/include/asm/p2m.h | 4 ++ xen/arch/riscv/p2m.c | 81 ++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/xen/arch/riscv/include/asm/p2m.h b/xen/arch/riscv/include/asm/p2m.h index f63b5dec99b1..1d8c97326565 100644 --- a/xen/arch/riscv/include/asm/p2m.h +++ b/xen/arch/riscv/include/asm/p2m.h @@ -255,6 +255,10 @@ static inline bool p2m_is_locked(const struct p2m_domain *p2m) struct page_info *p2m_get_page_from_gfn(struct p2m_domain *p2m, gfn_t gfn, p2m_type_t *t); + +void p2m_ctx_switch_from(struct vcpu *p); +void p2m_ctx_switch_to(struct vcpu *n); + #endif /* ASM__RISCV__P2M_H */ /* diff --git a/xen/arch/riscv/p2m.c b/xen/arch/riscv/p2m.c index 0abeb374c110..af68497c4200 100644 --- a/xen/arch/riscv/p2m.c +++ b/xen/arch/riscv/p2m.c @@ -1434,3 +1434,84 @@ struct page_info *p2m_get_page_from_gfn(struct p2m_domain *p2m, gfn_t gfn, return get_page(page, p2m->domain) ? page : NULL; } + +void p2m_ctx_switch_from(struct vcpu *p) +{ + /* + * No mechanism is provided to atomically change vsatp and hgatp + * together. Hence, to prevent speculative execution causing one + * guest’s VS-stage translations to be cached under another guest’s + * VMID, world-switch code should zero vsatp, then swap hgatp, then + * finally write the new vsatp value. + */ + p->arch.vsatp = csr_read(CSR_VSATP); + csr_write(CSR_VSATP, 0); + + /* + * No need for VS-stage TLB flush here: + * Changing satp.MODE from Bare to other modes and vice versa also + * takes effect immediately, without the need to execute an + * SFENCE.VMA instruction. + * Note that VSATP is just VS-mode’s version of SATP, so the mentioned + * above should be true for VSATP. + */ + + /* + * Nothing to do with HGATP as it is constructed each time when + * p2m_ctx_switch_to() is called. + */ +} + +void p2m_ctx_switch_to(struct vcpu *n) +{ + struct vcpu_vmid *p_vmid = &n->arch.vmid; + uint16_t old_vmid, new_vmid; + bool need_flush; + + if ( is_idle_vcpu(n) ) + return; + + old_vmid = p_vmid->vmid; + need_flush = vmid_handle_vmenter(p_vmid); + new_vmid = p_vmid->vmid; + +#ifdef P2M_DEBUG + printk(XENLOG_INFO, "%pv: oldvmid(%d) new_vmid(%d), need_flush(%d)\n", + n, old_vmid, new_vmid, need_flush); +#endif + + csr_write(CSR_HGATP, construct_hgatp(p2m_get_hostp2m(current->domain), + new_vmid)); + + if ( unlikely(need_flush) ) + local_hfence_gvma_all(); + + /* + * According to the RISC-V specification, speculation can happen + * during an update of hgatp and vsatp: + * No mechanism is provided to atomically change vsatp and hgatp + * together. Hence, to prevent speculative execution causing one + * guest’s VS-stage translations to be cached under another guest’s + * VMID, world-switch code should zero vsatp, then swap hgatp, then + * finally write the new vsatp value. Similarly, if henvcfg.PBMTE + * need be world-switched, it should be switched after zeroing vsatp + * but before writing the new vsatp value, obviating the need to + * execute an HFENCE.VVMA instruction. + * So just flush TLBs for VS-Stage and G-stage after both of regs are + * touched. + */ + flush_tlb_guest_local(); + + /* + * The vsatp register is a VSXLEN-bit read/write register that is + * VS-mode’s version of supervisor register satp, so the following is + * true for VSATP registers: + * Changing satp.MODE from Bare to other modes and vice versa also takes + * effect immediately, without the need to execute an SFENCE.VMA + * instruction. Likewise, changes to satp.ASID take effect immediately. + * Considering the mentioned above and that VS-stage TLB flush has been + * already done there is no need to flush VS-stage TLB after an update + * of VSATP from Bare mode to what is written in `n->arch.vsatp`. + */ + csr_write(CSR_VSATP, n->arch.vsatp); +} -- 2.52.0
