[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260120080013.2153519-23-anup.patel@oss.qualcomm.com>
Date: Tue, 20 Jan 2026 13:30:08 +0530
From: Anup Patel <anup.patel@....qualcomm.com>
To: Paolo Bonzini <pbonzini@...hat.com>, Atish Patra <atish.patra@...ux.dev>
Cc: Palmer Dabbelt <palmer@...belt.com>, Paul Walmsley <pjw@...nel.org>,
Alexandre Ghiti <alex@...ti.fr>, Shuah Khan <shuah@...nel.org>,
Anup Patel <anup@...infault.org>,
Andrew Jones <andrew.jones@....qualcomm.com>,
kvm-riscv@...ts.infradead.org, kvm@...r.kernel.org,
linux-riscv@...ts.infradead.org, linux-kernel@...r.kernel.org,
linux-kselftest@...r.kernel.org,
Anup Patel <anup.patel@....qualcomm.com>
Subject: [PATCH 22/27] RISC-V: KVM: Add CSR emulation for nested virtualization
The Guest HS-mode (aka L1/guest hypervisor) needs H-extension CSRs
for hypervisor functionality so add corresponding CSR emulation.
Both, Guest HS-mode (aka L1/guest hypervisor) and Guest VS-mode (aka
L2/nested guest) will be running in actual VS-mode which complicates
receiving Guest HS-mode interrupts while Guest VS-mode is running.
To simplify this, trap-n-emulate SIE and SIP CSRs for Guest VS-mode
(aka L2/nested guest) using hvictl.VTI bit.
Signed-off-by: Anup Patel <anup.patel@....qualcomm.com>
---
arch/riscv/include/asm/csr.h | 17 ++
arch/riscv/include/asm/kvm_vcpu_nested.h | 42 +++
arch/riscv/kvm/Makefile | 1 +
arch/riscv/kvm/vcpu_insn.c | 2 +
arch/riscv/kvm/vcpu_nested.c | 3 +-
arch/riscv/kvm/vcpu_nested_csr.c | 361 +++++++++++++++++++++++
6 files changed, 424 insertions(+), 2 deletions(-)
create mode 100644 arch/riscv/kvm/vcpu_nested_csr.c
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 4a37a98398ad..7fba082d4a26 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -17,6 +17,7 @@
#define SR_SPP _AC(0x00000100, UL) /* Previously Supervisor */
#define SR_MPP _AC(0x00001800, UL) /* Previously Machine */
#define SR_SUM _AC(0x00040000, UL) /* Supervisor User Memory Access */
+#define SR_MXR _AC(0x00080000, UL) /* Make eXecutable Readable */
#define SR_FS _AC(0x00006000, UL) /* Floating-point Status */
#define SR_FS_OFF _AC(0x00000000, UL)
@@ -59,6 +60,7 @@
/* SATP flags */
#ifndef CONFIG_64BIT
#define SATP_PPN _AC(0x003FFFFF, UL)
+#define SATP_MODE _AC(0x80000000, UL)
#define SATP_MODE_32 _AC(0x80000000, UL)
#define SATP_MODE_SHIFT 31
#define SATP_ASID_BITS 9
@@ -66,6 +68,7 @@
#define SATP_ASID_MASK _AC(0x1FF, UL)
#else
#define SATP_PPN _AC(0x00000FFFFFFFFFFF, UL)
+#define SATP_MODE _AC(0xF000000000000000, UL)
#define SATP_MODE_39 _AC(0x8000000000000000, UL)
#define SATP_MODE_48 _AC(0x9000000000000000, UL)
#define SATP_MODE_57 _AC(0xa000000000000000, UL)
@@ -74,6 +77,8 @@
#define SATP_ASID_SHIFT 44
#define SATP_ASID_MASK _AC(0xFFFF, UL)
#endif
+#define SATP_MODE_OFF _AC(0, UL)
+#define SATP_ASID (SATP_ASID_MASK << SATP_ASID_SHIFT)
/* Exception cause high bit - is an interrupt if set */
#define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))
@@ -151,11 +156,13 @@
#define HGATP_MODE_SV57X4 _AC(10, UL)
#define HGATP32_MODE_SHIFT 31
+#define HGATP32_MODE GENMASK(31, 31)
#define HGATP32_VMID_SHIFT 22
#define HGATP32_VMID GENMASK(28, 22)
#define HGATP32_PPN GENMASK(21, 0)
#define HGATP64_MODE_SHIFT 60
+#define HGATP64_MODE GENMASK(63, 60)
#define HGATP64_VMID_SHIFT 44
#define HGATP64_VMID GENMASK(57, 44)
#define HGATP64_PPN GENMASK(43, 0)
@@ -167,11 +174,13 @@
#define HGATP_VMID_SHIFT HGATP64_VMID_SHIFT
#define HGATP_VMID HGATP64_VMID
#define HGATP_MODE_SHIFT HGATP64_MODE_SHIFT
+#define HGATP_MODE HGATP64_MODE
#else
#define HGATP_PPN HGATP32_PPN
#define HGATP_VMID_SHIFT HGATP32_VMID_SHIFT
#define HGATP_VMID HGATP32_VMID
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
+#define HGATP_MODE HGATP32_MODE
#endif
/* VSIP & HVIP relation */
@@ -237,6 +246,14 @@
#define MSECCFG_PMM_PMLEN_7 ENVCFG_PMM_PMLEN_7
#define MSECCFG_PMM_PMLEN_16 ENVCFG_PMM_PMLEN_16
+#define CSR_NUM_PRIV_SHIFT 8
+#define CSR_NUM_PRIV_MASK 0x3
+
+#define CSR_PRIV_USER 0
+#define CSR_PRIV_SUPERVISOR 1
+#define CSR_PRIV_HYPERVISOR 2
+#define CSR_PRIV_MACHINE 3
+
/* symbolic CSR names: */
#define CSR_CYCLE 0xc00
#define CSR_TIME 0xc01
diff --git a/arch/riscv/include/asm/kvm_vcpu_nested.h b/arch/riscv/include/asm/kvm_vcpu_nested.h
index 4935ab0db1a2..5262ec4f37b7 100644
--- a/arch/riscv/include/asm/kvm_vcpu_nested.h
+++ b/arch/riscv/include/asm/kvm_vcpu_nested.h
@@ -65,6 +65,48 @@ struct kvm_vcpu_nested {
int kvm_riscv_vcpu_nested_insn_sret(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn);
+int kvm_riscv_vcpu_nested_smode_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num,
+ unsigned long *val, unsigned long new_val,
+ unsigned long wr_mask);
+int kvm_riscv_vcpu_nested_hext_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num,
+ unsigned long *val, unsigned long new_val,
+ unsigned long wr_mask);
+
+#define KVM_RISCV_VCPU_NESTED_SMODE_CSR_FUNCS \
+{ .base = CSR_SIE, .count = 1, .func = kvm_riscv_vcpu_nested_smode_csr_rmw }, \
+{ .base = CSR_SIEH, .count = 1, .func = kvm_riscv_vcpu_nested_smode_csr_rmw }, \
+{ .base = CSR_SIP, .count = 1, .func = kvm_riscv_vcpu_nested_smode_csr_rmw }, \
+{ .base = CSR_SIPH, .count = 1, .func = kvm_riscv_vcpu_nested_smode_csr_rmw },
+
+#define KVM_RISCV_VCPU_NESTED_HEXT_CSR_FUNCS \
+{ .base = CSR_HSTATUS, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HEDELEG, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HIDELEG, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HIE, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HTIMEDELTA, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HCOUNTEREN, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HGEIE, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HENVCFG, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HTIMEDELTAH, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HENVCFGH, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HTVAL, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HIP, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HVIP, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HTINST, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HGATP, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_HGEIP, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSSTATUS, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSIE, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSTVEC, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSSCRATCH, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSEPC, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSCAUSE, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSTVAL, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSIP, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw }, \
+{ .base = CSR_VSATP, .count = 1, .func = kvm_riscv_vcpu_nested_hext_csr_rmw },
+
+void kvm_riscv_vcpu_nested_csr_reset(struct kvm_vcpu *vcpu);
+
int kvm_riscv_vcpu_nested_swtlb_xlate(struct kvm_vcpu *vcpu,
const struct kvm_cpu_trap *trap,
struct kvm_gstage_mapping *out_map,
diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile
index c0534d4a469e..40f385f229f4 100644
--- a/arch/riscv/kvm/Makefile
+++ b/arch/riscv/kvm/Makefile
@@ -26,6 +26,7 @@ kvm-y += vcpu_exit.o
kvm-y += vcpu_fp.o
kvm-y += vcpu_insn.o
kvm-y += vcpu_nested.o
+kvm-y += vcpu_nested_csr.o
kvm-y += vcpu_nested_insn.o
kvm-y += vcpu_nested_swtlb.o
kvm-y += vcpu_onereg.o
diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
index ebd0cfc1bf30..0246ca2d5e93 100644
--- a/arch/riscv/kvm/vcpu_insn.c
+++ b/arch/riscv/kvm/vcpu_insn.c
@@ -142,6 +142,8 @@ static const struct csr_func csr_funcs[] = {
KVM_RISCV_VCPU_AIA_CSR_FUNCS
KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS
{ .base = CSR_SEED, .count = 1, .func = seed_csr_rmw },
+ KVM_RISCV_VCPU_NESTED_SMODE_CSR_FUNCS
+ KVM_RISCV_VCPU_NESTED_HEXT_CSR_FUNCS
};
/**
diff --git a/arch/riscv/kvm/vcpu_nested.c b/arch/riscv/kvm/vcpu_nested.c
index 9b2b3369a232..1b4898d9c72c 100644
--- a/arch/riscv/kvm/vcpu_nested.c
+++ b/arch/riscv/kvm/vcpu_nested.c
@@ -224,11 +224,10 @@ void kvm_riscv_vcpu_nested_vsirq_process(struct kvm_vcpu *vcpu)
void kvm_riscv_vcpu_nested_reset(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_nested *ns = &vcpu->arch.nested;
- struct kvm_vcpu_nested_csr *ncsr = &vcpu->arch.nested.csr;
ns->virt = false;
kvm_riscv_vcpu_nested_swtlb_reset(vcpu);
- memset(ncsr, 0, sizeof(*ncsr));
+ kvm_riscv_vcpu_nested_csr_reset(vcpu);
}
int kvm_riscv_vcpu_nested_init(struct kvm_vcpu *vcpu)
diff --git a/arch/riscv/kvm/vcpu_nested_csr.c b/arch/riscv/kvm/vcpu_nested_csr.c
new file mode 100644
index 000000000000..0e427f224954
--- /dev/null
+++ b/arch/riscv/kvm/vcpu_nested_csr.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026 Qualcomm Technologies, Inc.
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/pgtable.h>
+#include <asm/csr.h>
+
+#define NESTED_SIE_WRITEABLE (BIT(IRQ_S_SOFT) | BIT(IRQ_S_TIMER) | BIT(IRQ_S_EXT))
+#define NESTED_HVIP_WRITEABLE (BIT(IRQ_VS_SOFT) | BIT(IRQ_VS_TIMER) | BIT(IRQ_VS_EXT))
+#define NESTED_HIDELEG_WRITEABLE NESTED_HVIP_WRITEABLE
+#define NESTED_HEDELEG_WRITEABLE \
+ (BIT(EXC_INST_MISALIGNED) | \
+ BIT(EXC_INST_ACCESS) | \
+ BIT(EXC_INST_ILLEGAL) | \
+ BIT(EXC_BREAKPOINT) | \
+ BIT(EXC_LOAD_MISALIGNED) | \
+ BIT(EXC_LOAD_ACCESS) | \
+ BIT(EXC_STORE_MISALIGNED) | \
+ BIT(EXC_STORE_ACCESS) | \
+ BIT(EXC_SYSCALL) | \
+ BIT(EXC_INST_PAGE_FAULT) | \
+ BIT(EXC_LOAD_PAGE_FAULT) | \
+ BIT(EXC_STORE_PAGE_FAULT))
+#define NESTED_HCOUNTEREN_WRITEABLE -1UL
+#define NESTED_VSIE_WRITEABLE NESTED_SIE_WRITEABLE
+#define NESTED_VSCAUSE_WRITEABLE GENMASK(4, 0)
+
+int kvm_riscv_vcpu_nested_smode_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num,
+ unsigned long *val, unsigned long new_val,
+ unsigned long wr_mask)
+{
+ struct kvm_vcpu_nested_csr *nsc = &vcpu->arch.nested.csr;
+ unsigned long *csr, csr_rdor = 0;
+ unsigned long writeable_mask = 0;
+#ifdef CONFIG_32BIT
+ unsigned long zero = 0;
+#endif
+ int csr_shift = 0;
+
+ /*
+ * These CSRs should never trap for virtual-HS/U modes because
+ * we only emulate these CSRs for virtual-VS/VU modes.
+ */
+ if (!kvm_riscv_vcpu_nested_virt(vcpu))
+ return -EINVAL;
+
+ /*
+ * Access of these CSRs from virtual-VU mode should be forwarded
+ * as illegal instruction trap to virtual-HS mode.
+ */
+ if (!(vcpu->arch.guest_context.hstatus & HSTATUS_SPVP))
+ return KVM_INSN_ILLEGAL_TRAP;
+
+ switch (csr_num) {
+ case CSR_SIE:
+ csr = &nsc->vsie;
+ writeable_mask = NESTED_SIE_WRITEABLE & (nsc->hideleg >> VSIP_TO_HVIP_SHIFT);
+ break;
+#ifdef CONFIG_32BIT
+ case CSR_SIEH:
+ csr = &zero;
+ break;
+#endif
+ case CSR_SIP:
+ csr = &nsc->hvip;
+ csr_shift = VSIP_TO_HVIP_SHIFT;
+ writeable_mask = BIT(IRQ_VS_EXT) & nsc->hideleg;
+ break;
+#ifdef CONFIG_32BIT
+ case CSR_SIPH:
+ csr = &zero;
+ break;
+#endif
+ default:
+ return KVM_INSN_ILLEGAL_TRAP;
+ }
+
+ if (val)
+ *val = (csr_shift < 0) ? (*csr | csr_rdor) << -csr_shift :
+ (*csr | csr_rdor) >> csr_shift;
+
+ if (wr_mask) {
+ writeable_mask = (csr_shift < 0) ?
+ writeable_mask >> -csr_shift :
+ writeable_mask << csr_shift;
+ wr_mask = (csr_shift < 0) ?
+ wr_mask >> -csr_shift : wr_mask << csr_shift;
+ new_val = (csr_shift < 0) ?
+ new_val >> -csr_shift : new_val << csr_shift;
+ wr_mask &= writeable_mask;
+ *csr = (*csr & ~wr_mask) | (new_val & wr_mask);
+ }
+
+ return KVM_INSN_CONTINUE_NEXT_SEPC;
+}
+
+static int __riscv_vcpu_nested_hext_csr_rmw(struct kvm_vcpu *vcpu,
+ bool priv_check, unsigned int csr_num,
+ unsigned long *val, unsigned long new_val,
+ unsigned long wr_mask)
+{
+ unsigned int csr_priv = (csr_num >> CSR_NUM_PRIV_SHIFT) & CSR_NUM_PRIV_MASK;
+ struct kvm_vcpu_nested_csr *nsc = &vcpu->arch.nested.csr;
+ unsigned long mode, zero = 0, writeable_mask = 0;
+ bool read_only = false, nuke_swtlb = false;
+ unsigned long *csr, csr_rdor = 0;
+ int csr_shift = 0;
+
+ /*
+ * If H-extension is not available for VCPU then forward trap
+ * as illegal instruction trap to virtual-HS mode.
+ */
+ if (!riscv_isa_extension_available(vcpu->arch.isa, h))
+ return KVM_INSN_ILLEGAL_TRAP;
+
+ /*
+ * Trap from virtual-VS and virtual-VU modes should be forwarded
+ * to virtual-HS mode as a virtual instruction trap.
+ */
+ if (priv_check && kvm_riscv_vcpu_nested_virt(vcpu))
+ return (csr_priv == CSR_PRIV_HYPERVISOR) ?
+ KVM_INSN_VIRTUAL_TRAP : KVM_INSN_ILLEGAL_TRAP;
+
+ /*
+ * H-extension CSRs not allowed in virtual-U mode so forward trap
+ * as illegal instruction trap to virtual-HS mode.
+ */
+ if (priv_check && !(vcpu->arch.guest_context.hstatus & HSTATUS_SPVP))
+ return KVM_INSN_ILLEGAL_TRAP;
+
+ switch (csr_num) {
+ case CSR_HSTATUS:
+ csr = &nsc->hstatus;
+ writeable_mask = HSTATUS_VTSR | HSTATUS_VTW | HSTATUS_VTVM |
+ HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV |
+ HSTATUS_GVA;
+ if (wr_mask & HSTATUS_SPV) {
+ /*
+ * If hstatus.SPV == 1 then enable host SRET
+ * trapping for the virtual-HS mode which will
+ * allow host to do nested world-switch upon
+ * next SRET instruction executed by the
+ * virtual-HS-mode.
+ *
+ * If hstatus.SPV == 0 then disable host SRET
+ * trapping for the virtual-HS mode which will
+ * ensure that host does not do any nested
+ * world-switch for SRET instruction executed
+ * virtual-HS mode for general interrupt and
+ * trap handling.
+ */
+ vcpu->arch.guest_context.hstatus &= ~HSTATUS_VTSR;
+ vcpu->arch.guest_context.hstatus |= (new_val & HSTATUS_SPV) ?
+ HSTATUS_VTSR : 0;
+ }
+ break;
+ case CSR_HEDELEG:
+ csr = &nsc->hedeleg;
+ writeable_mask = NESTED_HEDELEG_WRITEABLE;
+ break;
+ case CSR_HIDELEG:
+ csr = &nsc->hideleg;
+ writeable_mask = NESTED_HIDELEG_WRITEABLE;
+ break;
+ case CSR_HVIP:
+ csr = &nsc->hvip;
+ writeable_mask = NESTED_HVIP_WRITEABLE;
+ break;
+ case CSR_HIE:
+ csr = &nsc->vsie;
+ csr_shift = -VSIP_TO_HVIP_SHIFT;
+ writeable_mask = NESTED_HVIP_WRITEABLE;
+ break;
+ case CSR_HIP:
+ csr = &nsc->hvip;
+ writeable_mask = BIT(IRQ_VS_SOFT);
+ break;
+ case CSR_HGEIP:
+ csr = &zero;
+ read_only = true;
+ break;
+ case CSR_HGEIE:
+ csr = &zero;
+ break;
+ case CSR_HCOUNTEREN:
+ csr = &nsc->hcounteren;
+ writeable_mask = NESTED_HCOUNTEREN_WRITEABLE;
+ break;
+ case CSR_HTIMEDELTA:
+ csr = &nsc->htimedelta;
+ writeable_mask = -1UL;
+ break;
+#ifndef CONFIG_64BIT
+ case CSR_HTIMEDELTAH:
+ csr = &nsc->htimedeltah;
+ writeable_mask = -1UL;
+ break;
+#endif
+ case CSR_HTVAL:
+ csr = &nsc->htval;
+ writeable_mask = -1UL;
+ break;
+ case CSR_HTINST:
+ csr = &nsc->htinst;
+ writeable_mask = -1UL;
+ break;
+ case CSR_HGATP:
+ csr = &nsc->hgatp;
+ writeable_mask = HGATP_MODE | HGATP_VMID | HGATP_PPN;
+ if (wr_mask & HGATP_MODE) {
+ mode = (new_val & HGATP_MODE) >> HGATP_MODE_SHIFT;
+ switch (mode) {
+ /*
+ * Intentionally support only Sv39x4 on RV64 and
+ * Sv32x4 on RV32 for guest G-stage so that software
+ * page table walks on guest G-stage are faster.
+ */
+#ifdef CONFIG_64BIT
+ case HGATP_MODE_SV39X4:
+ if (kvm_riscv_gstage_mode != HGATP_MODE_SV57X4 &&
+ kvm_riscv_gstage_mode != HGATP_MODE_SV48X4 &&
+ kvm_riscv_gstage_mode != HGATP_MODE_SV39X4)
+ mode = HGATP_MODE_OFF;
+ break;
+#else
+ case HGATP_MODE_SV32X4:
+ if (kvm_riscv_gstage_mode != HGATP_MODE_SV32X4)
+ mode = HGATP_MODE_OFF;
+ break;
+#endif
+ default:
+ mode = HGATP_MODE_OFF;
+ break;
+ }
+ new_val &= ~HGATP_MODE;
+ new_val |= (mode << HGATP_MODE_SHIFT) & HGATP_MODE;
+ if ((new_val ^ nsc->hgatp) & HGATP_MODE)
+ nuke_swtlb = true;
+ }
+ if (wr_mask & HGATP_VMID) {
+ if ((new_val ^ nsc->hgatp) & HGATP_VMID)
+ nuke_swtlb = true;
+ }
+ break;
+ case CSR_HENVCFG:
+ csr = &nsc->henvcfg;
+#ifdef CONFIG_64BIT
+ writeable_mask = ENVCFG_STCE;
+#endif
+ break;
+#ifdef CONFIG_32BIT
+ case CSR_HENVCFGH:
+ csr = &nsc->henvcfgh;
+ writeable_mask = ENVCFG_STCE >> 32;
+ break;
+#endif
+ case CSR_VSSTATUS:
+ csr = &nsc->vsstatus;
+ writeable_mask = SR_SIE | SR_SPIE | SR_SPP | SR_SUM | SR_MXR | SR_FS | SR_VS;
+ break;
+ case CSR_VSIP:
+ csr = &nsc->hvip;
+ csr_shift = VSIP_TO_HVIP_SHIFT;
+ writeable_mask = BIT(IRQ_VS_SOFT) & nsc->hideleg;
+ break;
+ case CSR_VSIE:
+ csr = &nsc->vsie;
+ writeable_mask = NESTED_VSIE_WRITEABLE & (nsc->hideleg >> VSIP_TO_HVIP_SHIFT);
+ break;
+ case CSR_VSTVEC:
+ csr = &nsc->vstvec;
+ writeable_mask = -1UL;
+ break;
+ case CSR_VSSCRATCH:
+ csr = &nsc->vsscratch;
+ writeable_mask = -1UL;
+ break;
+ case CSR_VSEPC:
+ csr = &nsc->vsepc;
+ writeable_mask = -1UL;
+ break;
+ case CSR_VSCAUSE:
+ csr = &nsc->vscause;
+ writeable_mask = NESTED_VSCAUSE_WRITEABLE;
+ break;
+ case CSR_VSTVAL:
+ csr = &nsc->vstval;
+ writeable_mask = -1UL;
+ break;
+ case CSR_VSATP:
+ csr = &nsc->vsatp;
+ writeable_mask = SATP_MODE | SATP_ASID | SATP_PPN;
+ if (wr_mask & SATP_MODE) {
+ mode = new_val & SATP_MODE;
+ switch (mode) {
+#ifdef CONFIG_64BIT
+ case SATP_MODE_57:
+ if (!pgtable_l5_enabled)
+ mode = SATP_MODE_OFF;
+ break;
+ case SATP_MODE_48:
+ if (!pgtable_l5_enabled && !pgtable_l4_enabled)
+ mode = SATP_MODE_OFF;
+ break;
+ case SATP_MODE_39:
+ break;
+#else
+ case SATP_MODE_32:
+ break;
+#endif
+ default:
+ mode = SATP_MODE_OFF;
+ break;
+ }
+ new_val &= ~SATP_MODE;
+ new_val |= mode & SATP_MODE;
+ }
+ break;
+ default:
+ return KVM_INSN_ILLEGAL_TRAP;
+ }
+
+ if (val)
+ *val = (csr_shift < 0) ? (*csr | csr_rdor) << -csr_shift :
+ (*csr | csr_rdor) >> csr_shift;
+
+ if (read_only) {
+ return KVM_INSN_ILLEGAL_TRAP;
+ } else if (wr_mask) {
+ writeable_mask = (csr_shift < 0) ?
+ writeable_mask >> -csr_shift :
+ writeable_mask << csr_shift;
+ wr_mask = (csr_shift < 0) ?
+ wr_mask >> -csr_shift : wr_mask << csr_shift;
+ new_val = (csr_shift < 0) ?
+ new_val >> -csr_shift : new_val << csr_shift;
+ wr_mask &= writeable_mask;
+ *csr = (*csr & ~wr_mask) | (new_val & wr_mask);
+ }
+
+ if (nuke_swtlb)
+ kvm_riscv_vcpu_nested_swtlb_gvma_flush(vcpu, 0, 0, 0);
+
+ return KVM_INSN_CONTINUE_NEXT_SEPC;
+}
+
+int kvm_riscv_vcpu_nested_hext_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num,
+ unsigned long *val, unsigned long new_val,
+ unsigned long wr_mask)
+{
+ return __riscv_vcpu_nested_hext_csr_rmw(vcpu, true, csr_num, val, new_val, wr_mask);
+}
+
+void kvm_riscv_vcpu_nested_csr_reset(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu_nested_csr *nsc = &vcpu->arch.nested.csr;
+
+ memset(nsc, 0, sizeof(*nsc));
+}
--
2.43.0
Powered by blists - more mailing lists