Hstateen has different bits that can be enabled lazily at runtime. Most of them have similar functionality where the hstateen bit must be enabled if not enabled already. The correpsonding config bit in vcpu must be enabled as well so that hstateen CSR is updated correctly during the next vcpu load. In absesnce of Smstateen extension, exit to the userspace in the trap because CSR access control exists architecturally only if Smstateen extension is available. Add a common helper function to achieve the above said objective. Signed-off-by: Atish Patra <atishp@xxxxxxxxxxxx> --- arch/riscv/include/asm/kvm_vcpu_insn.h | 4 ++++ arch/riscv/kvm/vcpu_insn.c | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/riscv/include/asm/kvm_vcpu_insn.h b/arch/riscv/include/asm/kvm_vcpu_insn.h index 350011c83581..1125f3f1c8c4 100644 --- a/arch/riscv/include/asm/kvm_vcpu_insn.h +++ b/arch/riscv/include/asm/kvm_vcpu_insn.h @@ -6,6 +6,8 @@ #ifndef __KVM_VCPU_RISCV_INSN_H #define __KVM_VCPU_RISCV_INSN_H +#include <linux/kvm_types.h> + struct kvm_vcpu; struct kvm_run; struct kvm_cpu_trap; @@ -44,5 +46,7 @@ int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run, unsigned long fault_addr, unsigned long htinst); int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_riscv_vcpu_hstateen_lazy_enable(struct kvm_vcpu *vcpu, unsigned int csr_num, + uint64_t hstateen_feature_bit_mask); #endif diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index 97dec18e6989..3bc39572b79d 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -235,6 +235,27 @@ static int seed_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num, return KVM_INSN_EXIT_TO_USER_SPACE; } +int kvm_riscv_vcpu_hstateen_lazy_enable(struct kvm_vcpu *vcpu, unsigned int csr_num, + uint64_t hstateen_feature_bit_mask) +{ + /* Access from VS shouldn't trap if smstaeen is not present */ + if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) + return KVM_INSN_EXIT_TO_USER_SPACE; + + /* Enable the bit in hstateen0 lazily upon first access */ + if (!(vcpu->arch.cfg.hstateen0 & hstateen_feature_bit_mask)) { + vcpu->arch.cfg.hstateen0 |= hstateen_feature_bit_mask; + csr_set(CSR_HSTATEEN0, hstateen_feature_bit_mask); + if (IS_ENABLED(CONFIG_32BIT)) + csr_set(CSR_HSTATEEN0H, hstateen_feature_bit_mask >> 32); + } else { + return KVM_INSN_EXIT_TO_USER_SPACE; + } + + /* Let the guest retry the instruction read after hstateen0 is modified */ + return KVM_INSN_CONTINUE_SAME_SEPC; +} + static const struct csr_func csr_funcs[] = { KVM_RISCV_VCPU_AIA_CSR_FUNCS KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS -- 2.43.0