[PATCH v2] RISC-V: KVM: Do not touch the envcfg CSRs on the SiFive P550
Davidlohr Bueso
dave at stgolabs.net
Fri Oct 23 10:37:31 PDT 2026
The SiFive P550 (ESWIN EIC7700X) implements the hypervisor extension
on a privileged spec 1.11 base, so it has neither henvcfg nor senvcfg.
KVM swaps senvcfg on every guest entry and writes henvcfg on vCPU load
regardless, and the host dies on the first guest entry:
Oops - illegal instruction [#1]
Modules linked in: kvm
CPU: 2 UID: 0 PID: 127 Comm: qemu-system-ris Not tainted 7.2.0+ #4 PREEMPTLAZY
Hardware name: Unknown Unknown Product/Unknown Product, BIOS 2024.01 01/01/2024
epc : kvm_riscv_vcpu_enter_exit+0x26/0xcf8 [kvm]
ra : kvm_arch_vcpu_ioctl_run+0x4ce/0x5a6 [kvm]
status: 0000000200000100 badaddr: 0000000010a797f3 cause: 0000000000000002
[<ffffffff01df432e>] kvm_riscv_vcpu_enter_exit+0x26/0xcf8 [kvm]
[<ffffffff01deb3b0>] kvm_arch_vcpu_ioctl_run+0x4ce/0x5a6 [kvm]
[<ffffffff01dd7914>] kvm_vcpu_ioctl+0x180/0x5e4 [kvm]
[<ffffffff8025702e>] __riscv_sys_ioctl+0x84/0x9a
[<ffffffff80dfdc72>] do_trap_ecall_u+0x1d8/0x38a
[<ffffffff80e08644>] handle_exception+0x168/0x174
Code: 84aa 892e b703 8887 1773 1067 3023 16e5 b783 8907 (97f3) 10a7
Introduce a hardware quirk for this core, similar to the Andes AX66 TLB one,
and skip both CSRs when it is set. The FWFT features that KVM implements
with henvcfg bits then disabled.
Fixes: db3c01c7a308 ("RISCV: KVM: Add senvcfg context save/restore")
Suggested-by: Anup Patel <anup at brainfault.org>
Signed-off-by: Davidlohr Bueso <dave at stgolabs.net>
---
changes from v1: disable FWFT features accordingly (Anup)
arch/riscv/include/asm/kvm_host.h | 1 +
arch/riscv/kvm/main.c | 9 +++++++++
arch/riscv/kvm/vcpu.c | 6 ++++--
arch/riscv/kvm/vcpu_config.c | 16 ++++++++++------
arch/riscv/kvm/vcpu_sbi_fwft.c | 20 +++++++++++++++-----
5 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index a30600579231..51b6d1f76626 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -331,5 +331,6 @@ void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu);
/* Flags representing implementation specific details */
DECLARE_STATIC_KEY_FALSE(kvm_riscv_vsstage_tlb_no_gpa);
+DECLARE_STATIC_KEY_FALSE(kvm_riscv_no_xenvcfg);
#endif /* __RISCV_KVM_HOST_H__ */
diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c
index 89568ccce01d..0725c8e03c6a 100644
--- a/arch/riscv/kvm/main.c
+++ b/arch/riscv/kvm/main.c
@@ -15,11 +15,13 @@
#include <asm/kvm_mmu.h>
#include <asm/kvm_nacl.h>
#include <asm/sbi.h>
+#include <asm/vendorid_list.h>
#include <asm/kvm_vcpu_vector.h>
static DEFINE_PER_CPU(bool, kvm_riscv_virtualization_enabled);
DEFINE_STATIC_KEY_FALSE(kvm_riscv_vsstage_tlb_no_gpa);
+DEFINE_STATIC_KEY_FALSE(kvm_riscv_no_xenvcfg);
static void kvm_riscv_setup_vendor_features(void)
{
@@ -29,6 +31,13 @@ static void kvm_riscv_setup_vendor_features(void)
static_branch_enable(&kvm_riscv_vsstage_tlb_no_gpa);
kvm_info("VS-stage TLB does not cache guest physical address and VMID\n");
}
+
+ /* SiFive P550 (ESWIN EIC7700X): H on a 1.11 base, no henvcfg/senvcfg */
+ if (riscv_cached_mvendorid(0) == SIFIVE_VENDOR_ID &&
+ riscv_cached_marchid(0) == 0x8000000000000008ULL) {
+ static_branch_enable(&kvm_riscv_no_xenvcfg);
+ kvm_info("henvcfg and senvcfg CSRs not implemented\n");
+ }
}
long kvm_arch_dev_ioctl(struct file *filp,
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index 7f1636c44d41..e5f877284026 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -772,7 +772,8 @@ static __always_inline void kvm_riscv_vcpu_swap_in_guest_state(struct kvm_vcpu *
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
vcpu->arch.host_scounteren = csr_swap(CSR_SCOUNTEREN, csr->scounteren);
- vcpu->arch.host_senvcfg = csr_swap(CSR_SENVCFG, csr->senvcfg);
+ if (!static_branch_unlikely(&kvm_riscv_no_xenvcfg))
+ vcpu->arch.host_senvcfg = csr_swap(CSR_SENVCFG, csr->senvcfg);
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
vcpu->arch.host_sstateen0 = csr_swap(CSR_SSTATEEN0, smcsr->sstateen0);
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFISS))
@@ -786,7 +787,8 @@ static __always_inline void kvm_riscv_vcpu_swap_in_host_state(struct kvm_vcpu *v
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
csr->scounteren = csr_swap(CSR_SCOUNTEREN, vcpu->arch.host_scounteren);
- csr->senvcfg = csr_swap(CSR_SENVCFG, vcpu->arch.host_senvcfg);
+ if (!static_branch_unlikely(&kvm_riscv_no_xenvcfg))
+ csr->senvcfg = csr_swap(CSR_SENVCFG, vcpu->arch.host_senvcfg);
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
smcsr->sstateen0 = csr_swap(CSR_SSTATEEN0, vcpu->arch.host_sstateen0);
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFISS))
diff --git a/arch/riscv/kvm/vcpu_config.c b/arch/riscv/kvm/vcpu_config.c
index b68aa830aaf5..9b8e4f1f12f4 100644
--- a/arch/riscv/kvm/vcpu_config.c
+++ b/arch/riscv/kvm/vcpu_config.c
@@ -82,9 +82,11 @@ void kvm_riscv_vcpu_config_load(struct kvm_vcpu *vcpu)
nsh = nacl_shmem();
nacl_csr_write(nsh, CSR_HEDELEG, cfg->hedeleg);
nacl_csr_write(nsh, CSR_HIDELEG, cfg->hideleg);
- nacl_csr_write(nsh, CSR_HENVCFG, cfg->henvcfg);
- if (IS_ENABLED(CONFIG_32BIT))
- nacl_csr_write(nsh, CSR_HENVCFGH, cfg->henvcfg >> 32);
+ if (!static_branch_unlikely(&kvm_riscv_no_xenvcfg)) {
+ nacl_csr_write(nsh, CSR_HENVCFG, cfg->henvcfg);
+ if (IS_ENABLED(CONFIG_32BIT))
+ nacl_csr_write(nsh, CSR_HENVCFGH, cfg->henvcfg >> 32);
+ }
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) {
nacl_csr_write(nsh, CSR_HSTATEEN0, cfg->hstateen0);
if (IS_ENABLED(CONFIG_32BIT))
@@ -93,9 +95,11 @@ void kvm_riscv_vcpu_config_load(struct kvm_vcpu *vcpu)
} else {
csr_write(CSR_HEDELEG, cfg->hedeleg);
csr_write(CSR_HIDELEG, cfg->hideleg);
- csr_write(CSR_HENVCFG, cfg->henvcfg);
- if (IS_ENABLED(CONFIG_32BIT))
- csr_write(CSR_HENVCFGH, cfg->henvcfg >> 32);
+ if (!static_branch_unlikely(&kvm_riscv_no_xenvcfg)) {
+ csr_write(CSR_HENVCFG, cfg->henvcfg);
+ if (IS_ENABLED(CONFIG_32BIT))
+ csr_write(CSR_HENVCFGH, cfg->henvcfg >> 32);
+ }
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) {
csr_write(CSR_HSTATEEN0, cfg->hstateen0);
if (IS_ENABLED(CONFIG_32BIT))
diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index 7d0aaeff537b..d339f7384497 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -132,6 +132,12 @@ static long kvm_sbi_fwft_envcfg_flag_get(struct kvm_vcpu *vcpu,
return SBI_SUCCESS;
}
+/* features implemented by setting bits in henvcfg need the CSR to exist */
+static bool kvm_sbi_fwft_have_henvcfg(void)
+{
+ return !static_branch_unlikely(&kvm_riscv_no_xenvcfg);
+}
+
static bool kvm_sbi_fwft_misaligned_delegation_supported(struct kvm_vcpu *vcpu)
{
return misaligned_traps_can_delegate();
@@ -208,7 +214,8 @@ static long kvm_sbi_fwft_set_cfi(struct kvm_vcpu *vcpu,
static bool kvm_sbi_fwft_landing_pad_supported(struct kvm_vcpu *vcpu)
{
- return riscv_isa_extension_available(vcpu->arch.isa, ZICFILP);
+ return kvm_sbi_fwft_have_henvcfg() &&
+ riscv_isa_extension_available(vcpu->arch.isa, ZICFILP);
}
static void kvm_sbi_fwft_reset_landing_pad(struct kvm_vcpu *vcpu)
@@ -236,7 +243,8 @@ static long kvm_sbi_fwft_get_landing_pad(struct kvm_vcpu *vcpu,
static bool kvm_sbi_fwft_shadow_stack_supported(struct kvm_vcpu *vcpu)
{
- return riscv_isa_extension_available(vcpu->arch.isa, ZICFISS);
+ return kvm_sbi_fwft_have_henvcfg() &&
+ riscv_isa_extension_available(vcpu->arch.isa, ZICFISS);
}
static void kvm_sbi_fwft_reset_shadow_stack(struct kvm_vcpu *vcpu)
@@ -264,8 +272,9 @@ static long kvm_sbi_fwft_get_shadow_stack(struct kvm_vcpu *vcpu,
static bool kvm_sbi_fwft_pte_ad_hw_updating_supported(struct kvm_vcpu *vcpu)
{
- return riscv_isa_extension_available(vcpu->arch.isa, SVADU) &&
- riscv_isa_extension_available(vcpu->arch.isa, SVADE);
+ return kvm_sbi_fwft_have_henvcfg() &&
+ riscv_isa_extension_available(vcpu->arch.isa, SVADU) &&
+ riscv_isa_extension_available(vcpu->arch.isa, SVADE);
}
static void kvm_sbi_fwft_reset_pte_ad_hw_updating(struct kvm_vcpu *vcpu)
@@ -305,7 +314,8 @@ static bool try_to_set_pmm(unsigned long value)
static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu)
{
- return riscv_isa_extension_available(vcpu->arch.isa, SMNPM);
+ return kvm_sbi_fwft_have_henvcfg() &&
+ riscv_isa_extension_available(vcpu->arch.isa, SMNPM);
}
static bool kvm_sbi_fwft_pointer_masking_pmlen_init(struct kvm_vcpu *vcpu)
--
2.39.5
More information about the kvm-riscv
mailing list