[PATCH 1/5] RISC-V: KVM: Lazy enable hstateen IMSIC & ISEL bit
Atish Patra
atishp at rivosinc.com
Mon May 5 14:39:26 PDT 2025
Currently, we enable the smstateen bit at vcpu configure time by
only checking the presence of required ISA extensions.
These bits are not required to be enabled if the guest never uses
the corresponding architectural state. Enable the smstaeen bits
at runtime lazily upon first access.
Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
arch/riscv/include/asm/kvm_aia.h | 1 +
arch/riscv/kvm/aia.c | 43 ++++++++++++++++++++++++++++++++++++++++
arch/riscv/kvm/aia_imsic.c | 8 ++++++++
3 files changed, 52 insertions(+)
diff --git a/arch/riscv/include/asm/kvm_aia.h b/arch/riscv/include/asm/kvm_aia.h
index 1f37b600ca47..760a1aef09f7 100644
--- a/arch/riscv/include/asm/kvm_aia.h
+++ b/arch/riscv/include/asm/kvm_aia.h
@@ -112,6 +112,7 @@ int kvm_riscv_aia_aplic_has_attr(struct kvm *kvm, unsigned long type);
int kvm_riscv_aia_aplic_inject(struct kvm *kvm, u32 source, bool level);
int kvm_riscv_aia_aplic_init(struct kvm *kvm);
void kvm_riscv_aia_aplic_cleanup(struct kvm *kvm);
+bool kvm_riscv_aia_imsic_state_hw_backed(struct kvm_vcpu *vcpu);
#ifdef CONFIG_32BIT
void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu);
diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c
index 19afd1f23537..1e0d2217ade7 100644
--- a/arch/riscv/kvm/aia.c
+++ b/arch/riscv/kvm/aia.c
@@ -241,6 +241,8 @@ int kvm_riscv_vcpu_aia_rmw_topei(struct kvm_vcpu *vcpu,
unsigned long new_val,
unsigned long wr_mask)
{
+ bool vsfile_present = kvm_riscv_aia_imsic_state_hw_backed(vcpu);
+
/* If AIA not available then redirect trap */
if (!kvm_riscv_aia_available())
return KVM_INSN_ILLEGAL_TRAP;
@@ -249,6 +251,26 @@ int kvm_riscv_vcpu_aia_rmw_topei(struct kvm_vcpu *vcpu,
if (!kvm_riscv_aia_initialized(vcpu->kvm))
return KVM_INSN_EXIT_TO_USER_SPACE;
+ /* Continue if smstaeen is not present */
+ if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
+ goto skip_hstateen;
+
+ /* Enable the bit in hstateen0 lazily upon first access */
+ if (!(vcpu->arch.cfg.hstateen0 & SMSTATEEN0_AIA_IMSIC)) {
+ vcpu->arch.cfg.hstateen0 |= SMSTATEEN0_AIA_IMSIC;
+ if (IS_ENABLED(CONFIG_32BIT))
+ csr_set(CSR_HSTATEEN0H, SMSTATEEN0_AIA_IMSIC >> 32);
+ else
+ csr_set(CSR_HSTATEEN0, SMSTATEEN0_AIA_IMSIC);
+ if (vsfile_present)
+ return KVM_INSN_CONTINUE_SAME_SEPC;
+ } else if (vsfile_present) {
+ pr_err("Unexpected trap for CSR [%x] with hstateen0 enabled and valid vsfile\n",
+ csr_num);
+ return KVM_INSN_EXIT_TO_USER_SPACE;
+ }
+
+skip_hstateen:
return kvm_riscv_vcpu_aia_imsic_rmw(vcpu, KVM_RISCV_AIA_IMSIC_TOPEI,
val, new_val, wr_mask);
}
@@ -400,11 +422,32 @@ int kvm_riscv_vcpu_aia_rmw_ireg(struct kvm_vcpu *vcpu, unsigned int csr_num,
unsigned long wr_mask)
{
unsigned int isel;
+ bool vsfile_present = kvm_riscv_aia_imsic_state_hw_backed(vcpu);
/* If AIA not available then redirect trap */
if (!kvm_riscv_aia_available())
return KVM_INSN_ILLEGAL_TRAP;
+ /* Continue if smstaeen is not present */
+ if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
+ goto skip_hstateen;
+
+ /* Enable the bit in hstateen0 lazily upon first access */
+ if (!(vcpu->arch.cfg.hstateen0 & SMSTATEEN0_AIA_ISEL)) {
+ vcpu->arch.cfg.hstateen0 |= SMSTATEEN0_AIA_ISEL;
+ if (IS_ENABLED(CONFIG_32BIT))
+ csr_set(CSR_HSTATEEN0H, SMSTATEEN0_AIA_ISEL >> 32);
+ else
+ csr_set(CSR_HSTATEEN0, SMSTATEEN0_AIA_ISEL);
+ if (vsfile_present)
+ return KVM_INSN_CONTINUE_SAME_SEPC;
+ } else if (vsfile_present) {
+ pr_err("Unexpected trap for CSR [%x] with hstateen0 enabled and valid vsfile\n",
+ csr_num);
+ return KVM_INSN_EXIT_TO_USER_SPACE;
+ }
+
+skip_hstateen:
/* First try to emulate in kernel space */
isel = ncsr_read(CSR_VSISELECT) & ISELECT_MASK;
if (isel >= ISELECT_IPRIO0 && isel <= ISELECT_IPRIO15)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 29ef9c2133a9..d8e6f14850c0 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -361,6 +361,14 @@ static int imsic_mrif_rmw(struct imsic_mrif *mrif, u32 nr_eix,
return 0;
}
+bool kvm_riscv_aia_imsic_state_hw_backed(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu_aia *vaia = &vcpu->arch.aia_context;
+ struct imsic *imsic = vaia->imsic_state;
+
+ return imsic && imsic->vsfile_cpu >= 0;
+}
+
struct imsic_vsfile_read_data {
int hgei;
u32 nr_eix;
--
2.43.0
More information about the kvm-riscv
mailing list