[PATCH v2 13/39] xen/riscv: save and restore AIA state on vCPU context switch
Oleksii Kurochko <[email protected]>
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <32e8b81fd276498cfd339defd2720bce1745c1cf.1787838835.git.oleksii.kurochko@gmail.com> |
vsiselect and hviprio{1,2} are per-hart CSRs which a guest can change, so
they have to be part of the vCPU context:
- vsiselect is written directly by VS-mode through siselect;
- hviprio1 and hviprio2 hold the priorities of the local interrupts which
VS-mode reaches through the iprio array of vsiselect/vsireg, so writes
the guest performs there land in these CSRs.
Without saving them, one vCPU's selector leaks into another vCPU's vsireg
accesses and one guest's interrupt priorities apply to the next guest which
runs on the same hart.
Whether the CSRs may be touched at all is gated by hstateen0 when Smstateen
is implemented: SVSLCT for vsiselect/vsireg and AIA for the rest of the AIA
state. A bit staying clear in v->arch.hstateen0 means M-mode denied the
access (see vcpu_csr_init()), and in that case the CSR can't be accessed
from HS-mode either, hence the gating helper.
vsie, hviprio1 and hviprio2 are 64-bit registers on both RV32 and RV64, so
store them as uint64_t and use csr_{read,write}64() rather than truncating
them to XLEN.
Signed-off-by: Oleksii Kurochko <[email protected]>
---
Changes in v2:
- New patch.
---
---
xen/arch/riscv/domain.c | 44 +++++++++++++++++++++++++++--
xen/arch/riscv/include/asm/domain.h | 5 +++-
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/xen/arch/riscv/domain.c b/xen/arch/riscv/domain.c
index 91a46d630f44..4afdfb4d09ab 100644
--- a/xen/arch/riscv/domain.c
+++ b/xen/arch/riscv/domain.c
@@ -333,6 +333,28 @@ int arch_domain_create(struct domain *d,
return rc;
}
+/*
+ * vsiselect and hviprio{1,2} are per-hart, but the guest can change them:
+ * vsiselect directly through siselect, and hviprio{1,2} through the iprio
+ * array which vsiselect/vsireg give VS-mode access to. Hence they are part
+ * of the vCPU context.
+ *
+ * When Smstateen is implemented, hstateen0 gates that access: SVSLCT for
+ * vsiselect/vsireg and AIA for the rest of the AIA state. A bit staying clear
+ * in v->arch.hstateen0 means M-mode denied it (see vcpu_csr_init()), and then
+ * the corresponding CSR can't be accessed from HS-mode either.
+ */
+static bool vcpu_has_aia_state(const struct vcpu *v, register_t hstateen0_bit)
+{
+ if ( !riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ssaia) )
+ return false;
+
+ if ( !riscv_isa_extension_available(NULL, RISCV_ISA_EXT_smstateen) )
+ return true;
+
+ return v->arch.hstateen0 & hstateen0_bit;
+}
+
static void save_csr_regs(struct vcpu *vcpu)
{
/*
@@ -354,12 +376,21 @@ static void save_csr_regs(struct vcpu *vcpu)
vcpu->arch.hvip = csr_read(CSR_HVIP);
vcpu->arch.vsstatus = csr_read(CSR_VSSTATUS);
- vcpu->arch.vsie = csr_read(CSR_VSIE);
+ vcpu->arch.vsie = csr_read64(CSR_VSIE);
vcpu->arch.vstvec = csr_read(CSR_VSTVEC);
vcpu->arch.vsscratch = csr_read(CSR_VSSCRATCH);
vcpu->arch.vscause = csr_read(CSR_VSCAUSE);
vcpu->arch.vstval = csr_read(CSR_VSTVAL);
vcpu->arch.vsepc = csr_read(CSR_VSEPC);
+
+ if ( vcpu_has_aia_state(vcpu, SMSTATEEN0_SVSLCT) )
+ vcpu->arch.vsiselect = csr_read(CSR_VSISELECT);
+
+ if ( vcpu_has_aia_state(vcpu, SMSTATEEN0_AIA) )
+ {
+ vcpu->arch.hviprio1 = csr_read64(CSR_HVIPRIO1);
+ vcpu->arch.hviprio2 = csr_read64(CSR_HVIPRIO2);
+ }
}
static void restore_csr_regs(struct vcpu *vcpu)
@@ -375,12 +406,21 @@ static void restore_csr_regs(struct vcpu *vcpu)
csr_write(CSR_HSTATEEN0, vcpu->arch.hstateen0);
csr_write(CSR_VSSTATUS, vcpu->arch.vsstatus);
- csr_write(CSR_VSIE, vcpu->arch.vsie);
+ csr_write64(CSR_VSIE, vcpu->arch.vsie);
csr_write(CSR_VSTVEC, vcpu->arch.vstvec);
csr_write(CSR_VSSCRATCH, vcpu->arch.vsscratch);
csr_write(CSR_VSCAUSE, vcpu->arch.vscause);
csr_write(CSR_VSTVAL, vcpu->arch.vstval);
csr_write(CSR_VSEPC, vcpu->arch.vsepc);
+
+ if ( vcpu_has_aia_state(vcpu, SMSTATEEN0_SVSLCT) )
+ csr_write(CSR_VSISELECT, vcpu->arch.vsiselect);
+
+ if ( vcpu_has_aia_state(vcpu, SMSTATEEN0_AIA) )
+ {
+ csr_write64(CSR_HVIPRIO1, vcpu->arch.hviprio1);
+ csr_write64(CSR_HVIPRIO2, vcpu->arch.hviprio2);
+ }
}
static void ctxt_switch_from(struct vcpu *p)
diff --git a/xen/arch/riscv/include/asm/domain.h b/xen/arch/riscv/include/asm/domain.h
index 90ed584bb844..23e301782068 100644
--- a/xen/arch/riscv/include/asm/domain.h
+++ b/xen/arch/riscv/include/asm/domain.h
@@ -70,11 +70,14 @@ struct arch_vcpu {
register_t hstateen0;
uint64_t htimedelta;
register_t hvip;
+ uint64_t hviprio1;
+ uint64_t hviprio2;
register_t vsatp;
register_t vscause;
register_t vsepc;
- register_t vsie;
+ uint64_t vsie;
+ register_t vsiselect;
register_t vsscratch;
register_t vsstatus;
register_t vstval;
--
2.55.0