From 165a50429e9f319e4a3bbc396cbec7c3f336ae5f Mon Sep 17 00:00:00 2001 From: jinrui Date: Thu, 13 Aug 2026 10:29:30 +0000 Subject: [PATCH 01/15] KVM: selftests: riscv: Add lazy V extension enablement for guests When the cross-compiler defaults to an -march that includes the V (vector) extension, -O2 auto-vectorization generates vector instructions (e.g. vsetvli, vadd.vv) in guest code. Executing such an instruction with sstatus.VS Off raises EXC_INST_ILLEGAL (scause=2); KVM's hedeleg forwards it to the guest, but the bare-metal selftest cannot handle it, so all guest tests fail. A real kernel handles this via riscv_v_first_use_handler(), which enables V and re-executes the instruction. Fix it in processor.c: 1. Delete the now-unused guest_unexp_trap() handler, replaced by the full exception vector table. 2. In vm_arch_vcpu_add(), advertise V to KVM via __vcpu_set_reg(V, 1) (best-effort, errors ignored on hardware without V) and install the full exception vector table instead of a raw stvec handler. 3. In route_exception(), decode the faulting instruction (stval) with insn_is_vector() and, when it is a vector instruction while sstatus.VS is Off, set VS to Initial and sret to re-execute it, before any test-registered handler. Genuinely illegal instructions still reach the unexpected-exception path. 4. Make vm_init_vector_tables() idempotent by checking vm->handlers before allocating, so tests that call it directly (ebreak_test, arch_timer, sbi_pmu_test) do not leak memory. Tested on a riscv64 host with KVM enabled. Signed-off-by: jinrui Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20EA6EE00884FB87+20260813102930.3892251-1-jinrui@haiwei.tech Signed-off-by: Anup Patel --- .../selftests/kvm/include/riscv/processor.h | 13 +++ .../selftests/kvm/lib/riscv/processor.c | 99 ++++++++++++++++--- 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index e3acf2ae9881..685baefebdb1 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -25,6 +25,19 @@ #define GET_RM(insn) (((insn) & INSN_MASK_FUNCT3) >> INSN_SHIFT_FUNCT3) #define GET_CSR_NUM(insn) (((insn) & INSN_CSR_MASK) >> INSN_CSR_SHIFT) +/* Vector (V) instruction decoding, matching arch/riscv/include/asm/insn.h */ +#define RV_INSN_OPCODE_MASK 0x7f +#define RVG_OPCODE_SYSTEM 0x73 +#define RVV_OPCODE_VECTOR 0x57 +#define RVV_OPCODE_VL 0x07 +#define RVV_OPCODE_VS 0x27 +#define RVV_VL_VS_WIDTH_8 0 +#define RVV_VL_VS_WIDTH_16 5 +#define RVV_VL_VS_WIDTH_32 6 +#define RVV_VL_VS_WIDTH_64 7 +#define RVV_EXTRACT_VL_VS_WIDTH(insn) (((insn) >> 12) & 0x7) +#define RVG_EXTRACT_SYSTEM_CSR(insn) (((insn) >> 20) & 0xfff) + static inline u64 __kvm_reg_id(u64 type, u64 subtype, u64 idx, u64 size) { return KVM_REG_RISCV | type | subtype | idx | size; diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index ded5429f3448..d00ac997291c 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -17,6 +17,11 @@ static gva_t exception_handlers; +struct handlers { + exception_handler_fn exception_handlers[NR_VECTORS][NR_EXCEPTIONS]; + bool v_available; +}; + bool __vcpu_has_ext(struct kvm_vcpu *vcpu, u64 ext) { unsigned long value = 0; @@ -298,13 +303,6 @@ void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, u8 indent) core.regs.t3, core.regs.t4, core.regs.t5, core.regs.t6); } -static void __aligned(16) guest_unexp_trap(void) -{ - sbi_ecall(KVM_RISCV_SELFTESTS_SBI_EXT, - KVM_RISCV_SELFTESTS_SBI_UNEXP, - 0, 0, 0, 0, 0, 0); -} - void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) { vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code); @@ -348,8 +346,26 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, u32 vcpu_id) /* Setup sscratch for guest_get_vcpuid() */ vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(sscratch), vcpu_id); - /* Setup default exception vector of guest */ - vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)guest_unexp_trap); + /* + * Advertise V to KVM so -O2 auto-vectorization in guest code is valid; + * ignore errors since the tests work without V too. Use the full + * exception vector table (which lazily enables V in route_exception()) + * as the default handler; vm_init_vector_tables() is idempotent. + */ + __vcpu_set_reg(vcpu, RISCV_ISA_EXT_REG(KVM_RISCV_ISA_EXT_V), 1); + vm_init_vector_tables(vm); + vcpu_init_vector_tables(vcpu); + + /* + * Record V availability for route_exception(), which runs in guest + * context. V is enabled uniformly for every vCPU, so this is a + * VM-wide property. + */ + { + struct handlers *h = addr_gva2hva(vm, vm->handlers); + + h->v_available = __vcpu_has_isa_ext(vcpu, KVM_RISCV_ISA_EXT_V); + } return vcpu; } @@ -408,19 +424,43 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) struct ucall uc; if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) { + vcpu_dump(stderr, vcpu, 2); TEST_FAIL("Unexpected exception (vector:0x%lx, ec:0x%lx)", uc.args[0], uc.args[1]); } } -struct handlers { - exception_handler_fn exception_handlers[NR_VECTORS][NR_EXCEPTIONS]; -}; +static bool insn_is_vector(u32 insn) +{ + u32 opcode = insn & RV_INSN_OPCODE_MASK; + u32 width, csr; + + /* All V-related instructions are 4-byte, i.e. not compressed. */ + if ((insn & 0x3) != 0x3) + return false; + + switch (opcode) { + case RVV_OPCODE_VECTOR: + return true; + case RVV_OPCODE_VL: + case RVV_OPCODE_VS: + width = RVV_EXTRACT_VL_VS_WIDTH(insn); + return width == RVV_VL_VS_WIDTH_8 || width == RVV_VL_VS_WIDTH_16 || + width == RVV_VL_VS_WIDTH_32 || width == RVV_VL_VS_WIDTH_64; + case RVG_OPCODE_SYSTEM: + csr = RVG_EXTRACT_SYSTEM_CSR(insn); + return (csr >= CSR_VSTART && csr <= CSR_VCSR) || + (csr >= CSR_VL && csr <= CSR_VLENB); + } + + return false; +} void route_exception(struct pt_regs *regs) { struct handlers *handlers = (struct handlers *)exception_handlers; - int vector = 0, ec; + int vector = 0; + unsigned long ec; ec = regs->cause & ~CAUSE_IRQ_FLAG; if (ec >= NR_EXCEPTIONS) @@ -432,6 +472,36 @@ void route_exception(struct pt_regs *regs) ec = 0; } + /* + * Lazily enable V on the first vector instruction: if the faulting + * instruction decodes as vector while VS is off, set VS to Initial + * and re-execute it, like the kernel's riscv_v_first_use_handler(). + * Genuinely illegal instructions continue to the unexpected-exception + * path. + */ + if (!(regs->cause & CAUSE_IRQ_FLAG) && ec == EXC_INST_ILLEGAL && + handlers && handlers->v_available && !(regs->status & SR_VS)) { + u32 insn = (u32)regs->badaddr; + + /* + * stval is not guaranteed to hold the faulting instruction. + * Vector instructions are always 32-bit, so check the first + * 16-bit halfword and, for a 32-bit instruction, assemble it + * from two halfwords to avoid an unaligned 32-bit access. + */ + if (!insn) { + u16 half = *(u16 *)regs->epc; + + if ((half & 0x3) == 0x3) + insn = (u32)half | ((u32)*(u16 *)(regs->epc + 2) << 16); + } + + if (insn_is_vector(insn)) { + regs->status |= SR_VS_INITIAL; + return; + } + } + if (handlers && handlers->exception_handlers[vector][ec]) return handlers->exception_handlers[vector][ec](regs); @@ -448,6 +518,9 @@ void vcpu_init_vector_tables(struct kvm_vcpu *vcpu) void vm_init_vector_tables(struct kvm_vm *vm) { + if (vm->handlers) + return; + vm->handlers = __vm_alloc(vm, sizeof(struct handlers), vm->page_size, MEM_REGION_DATA); From a84c5e0c31462588d2ec0fba17d9380ed9be6fcf Mon Sep 17 00:00:00 2001 From: Jinyu Tang Date: Fri, 14 Aug 2026 08:35:41 -0400 Subject: [PATCH 02/15] KVM: riscv: Avoid redundant interrupt check for pending timers The kvm_vcpu_check_block() calls kvm_arch_vcpu_runnable() before checking whether a timer is pending. On RISC-V, kvm_arch_vcpu_runnable() already checks all pending guest interrupts through kvm_riscv_vcpu_has_interrupts(vcpu, -1UL), including IRQ_VS_TIMER. Drop the repeated IRQ_VS_TIMER pending-interrupt check from kvm_riscv_vcpu_timer_pending() and keep the helper focused on the timer deadline state. If the timer becomes pending after the runnable check, the timer path still injects IRQ_VS_TIMER and kicks the vCPU through the normal wakeup path. Signed-off-by: Jinyu Tang Reviewed-by: Nutty Liu Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260814123541.593613-1-jinyu.tang@linux.dev Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_timer.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c index a2cd277a4059..adbd1617b78a 100644 --- a/arch/riscv/kvm/vcpu_timer.c +++ b/arch/riscv/kvm/vcpu_timer.c @@ -135,11 +135,7 @@ bool kvm_riscv_vcpu_timer_pending(struct kvm_vcpu *vcpu) struct kvm_vcpu_timer *t = &vcpu->arch.timer; struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; - if (!kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t) || - kvm_riscv_vcpu_has_interrupts(vcpu, 1UL << IRQ_VS_TIMER)) - return true; - else - return false; + return !kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t); } static void kvm_riscv_vcpu_timer_blocking(struct kvm_vcpu *vcpu) From e8b32e3779513e9ceed73f09c3f53db423140193 Mon Sep 17 00:00:00 2001 From: Jinyu Tang Date: Fri, 14 Aug 2026 07:45:05 -0400 Subject: [PATCH 03/15] KVM: riscv: Implement KVM_PRE_FAULT_MEMORY The generic KVM_PRE_FAULT_MEMORY ioctl lets userspace populate KVM page tables before running a vCPU over a GPA range. x86 already supports the ioctl, but RISC-V does not expose the capability and has no arch hook. Add the RISC-V arch hook and reuse the existing G-stage fault mapping path with a read access. Report progress using the G-stage mapping returned by the map path, so the ioctl can advance by the actual leaf size that covers the requested GPA. Retry until a mapping is installed or a signal, VM-dead request, or real error is observed. Signed-off-by: Jinyu Tang Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260814114507.583424-2-jinyu.tang@linux.dev Signed-off-by: Anup Patel --- arch/riscv/kvm/Kconfig | 1 + arch/riscv/kvm/gstage.c | 6 +++--- arch/riscv/kvm/mmu.c | 42 +++++++++++++++++++++++++++++++++++++++++ arch/riscv/kvm/vm.c | 1 + 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig index ec2cee0a39e0..8ac209e8ac87 100644 --- a/arch/riscv/kvm/Kconfig +++ b/arch/riscv/kvm/Kconfig @@ -28,6 +28,7 @@ config KVM select KVM_COMMON select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_GENERIC_HARDWARE_ENABLING + select KVM_GENERIC_PRE_FAULT_MEMORY select KVM_MMIO select VIRT_XFER_TO_GUEST_WORK select SCHED_INFO diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c index e5002cb9cbef..be70607a33ea 100644 --- a/arch/riscv/kvm/gstage.c +++ b/arch/riscv/kvm/gstage.c @@ -216,12 +216,10 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage, pte_t *ptep; int ret; - out_map->addr = gpa; - out_map->level = 0; - ret = gstage_page_size_to_level(gstage, page_size, &out_map->level); if (ret) return ret; + out_map->addr = ALIGN_DOWN(gpa, page_size); /* * A RISC-V implementation can choose to either: @@ -280,6 +278,8 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage, out_map->level, true); } else if (ALIGN_DOWN(PFN_PHYS(pte_pfn(ptep_get(ptep))), page_size) == hpa) { kvm_riscv_gstage_update_pte_prot(gstage, ptep_level, gpa, ptep, prot); + out_map->level = ptep_level; + out_map->pte = ptep_get(ptep); return 0; } } diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index 3e955d808743..78a1826c466d 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -754,6 +754,48 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot, return ret; } +long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, + struct kvm_pre_fault_memory *range) +{ + struct kvm_gstage_mapping out_map = { 0 }; + struct kvm_memory_slot *memslot; + unsigned long map_size; + unsigned long hva; + gpa_t end; + gfn_t gfn; + int ret; + + gfn = gpa_to_gfn(range->gpa); + memslot = kvm_vcpu_gfn_to_memslot(vcpu, gfn); + if (!memslot) + return -ENOENT; + + hva = gfn_to_hva_memslot_prot(memslot, gfn, NULL); + if (kvm_is_error_hva(hva)) + return -ENOENT; + + for (;;) { + if (signal_pending(current)) + return -EINTR; + + if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu)) + return -EIO; + + cond_resched(); + ret = kvm_riscv_mmu_map(vcpu, memslot, range->gpa, hva, false, &out_map); + if (ret) + return ret; + + if (pte_val(out_map.pte)) + break; + } + + map_size = PAGE_SIZE << (out_map.level * kvm_riscv_gstage_index_bits); + end = ALIGN_DOWN(range->gpa, map_size) + map_size; + + return min_t(u64, range->size, end - range->gpa); +} + int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm) { struct page *pgd_page; diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c index a9f083feeb76..58500a19b33b 100644 --- a/arch/riscv/kvm/vm.c +++ b/arch/riscv/kvm/vm.c @@ -187,6 +187,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_MP_STATE: case KVM_CAP_IMMEDIATE_EXIT: case KVM_CAP_SET_GUEST_DEBUG: + case KVM_CAP_PRE_FAULT_MEMORY: r = 1; break; case KVM_CAP_NR_VCPUS: From 0971048f467ef2f52f8e05ab4488705e27f9024e Mon Sep 17 00:00:00 2001 From: Jinyu Tang Date: Fri, 14 Aug 2026 07:45:06 -0400 Subject: [PATCH 04/15] KVM: selftests: Add RISC-V Sv57 page table indexing RISC-V selftests can create guests with five page-table levels, for example when the selected guest mode is Sv57. The RISC-V page-table walker only had index arrays for levels 0 through 3, so virt_arch_pg_map() indexed past the end of the arrays when level 4 was used. Add the missing L4 index mask and shift so selftests can build guest page tables for Sv57 VMs. Reviewed-by: Nutty Liu Reviewed-by: Anup Patel Signed-off-by: Jinyu Tang Link: https://lore.kernel.org/r/20260814114507.583424-3-jinyu.tang@linux.dev Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/include/riscv/processor.h | 3 +++ tools/testing/selftests/kvm/lib/riscv/processor.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index 685baefebdb1..5d242f063147 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -140,6 +140,9 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handl void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler); +/* L4 index Bit[56:48] */ +#define PGTBL_L4_INDEX_MASK 0x01FF000000000000ULL +#define PGTBL_L4_INDEX_SHIFT 48 /* L3 index Bit[47:39] */ #define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL #define PGTBL_L3_INDEX_SHIFT 39 diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index d00ac997291c..8f0b619fcded 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -48,6 +48,7 @@ static u64 pte_index_mask[] = { PGTBL_L1_INDEX_MASK, PGTBL_L2_INDEX_MASK, PGTBL_L3_INDEX_MASK, + PGTBL_L4_INDEX_MASK, }; static u32 pte_index_shift[] = { @@ -55,6 +56,7 @@ static u32 pte_index_shift[] = { PGTBL_L1_INDEX_SHIFT, PGTBL_L2_INDEX_SHIFT, PGTBL_L3_INDEX_SHIFT, + PGTBL_L4_INDEX_SHIFT, }; static u64 pte_index(struct kvm_vm *vm, gva_t gva, int level) From eb28015d47fd06e55a3bd84cf70d0e4362c0efe6 Mon Sep 17 00:00:00 2001 From: Jinyu Tang Date: Fri, 14 Aug 2026 07:45:07 -0400 Subject: [PATCH 05/15] KVM: selftests: Enable pre_fault_memory_test for RISC-V RISC-V now supports KVM_PRE_FAULT_MEMORY, so include the generic pre_fault_memory_test in the RISC-V KVM selftest build. The test uses PAGE_SIZE from the architecture processor header. Define the normal 4K RISC-V selftest page size so the generic test can build for RISC-V. Reviewed-by: Nutty Liu Reviewed-by: Anup Patel Signed-off-by: Jinyu Tang Link: https://lore.kernel.org/r/20260814114507.583424-4-jinyu.tang@linux.dev Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/Makefile.kvm | 1 + tools/testing/selftests/kvm/include/riscv/processor.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 6a1482e3a286..4cfb63854955 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -232,6 +232,7 @@ TEST_GEN_PROGS_riscv += coalesced_io_test TEST_GEN_PROGS_riscv += dirty_log_perf_test TEST_GEN_PROGS_riscv += get-reg-list TEST_GEN_PROGS_riscv += mmu_stress_test +TEST_GEN_PROGS_riscv += pre_fault_memory_test TEST_GEN_PROGS_riscv += rseq_test TEST_GEN_PROGS_riscv += steal_time diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index 5d242f063147..a5f101039a21 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -12,6 +12,9 @@ #include #include "kvm_util.h" +#define PAGE_SHIFT 12 +#define PAGE_SIZE BIT_ULL(PAGE_SHIFT) + #define INSN_OPCODE_MASK 0x007c #define INSN_OPCODE_SHIFT 2 #define INSN_OPCODE_SYSTEM 28 From 3da5289d8d19e5a5398e725ad6186e5686e18737 Mon Sep 17 00:00:00 2001 From: Yong-Xuan Wang Date: Mon, 31 Aug 2026 20:57:31 -0700 Subject: [PATCH 06/15] KVM: riscv: selftests: Dump sepc/scause/stval on vcpu_arch_dump() vcpu_arch_dump() omits trap-related CSRs, making it hard to diagnose unexpected guest exceptions from the dump output alone. Print sepc, scause, and stval alongside the existing register dump. Signed-off-by: Yong-Xuan Wang Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260831-kvm_kselftest_dump-v1-1-55b022c6ef8e@sifive.com Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/lib/riscv/processor.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index 8f0b619fcded..bd753e9a76cd 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -242,6 +242,7 @@ void riscv_vcpu_mmu_setup(struct kvm_vcpu *vcpu) void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, u8 indent) { struct kvm_riscv_core core; + struct kvm_riscv_csr general_csr; core.mode = vcpu_get_reg(vcpu, RISCV_CORE_REG(mode)); core.regs.pc = vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.pc)); @@ -277,6 +278,10 @@ void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, u8 indent) core.regs.t5 = vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t5)); core.regs.t6 = vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t6)); + general_csr.sepc = vcpu_get_reg(vcpu, RISCV_GENERAL_CSR_REG(sepc)); + general_csr.scause = vcpu_get_reg(vcpu, RISCV_GENERAL_CSR_REG(scause)); + general_csr.stval = vcpu_get_reg(vcpu, RISCV_GENERAL_CSR_REG(stval)); + fprintf(stream, " MODE: 0x%lx\n", core.mode); fprintf(stream, @@ -303,6 +308,9 @@ void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, u8 indent) fprintf(stream, " T3: 0x%016lx T4: 0x%016lx T5: 0x%016lx T6: 0x%016lx\n", core.regs.t3, core.regs.t4, core.regs.t5, core.regs.t6); + fprintf(stream, + "SEPC: 0x%016lx SCAUSE: 0x%016lx STVAL: 0x%016lx\n", + general_csr.sepc, general_csr.scause, general_csr.stval); } void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) From a01f4c27a6ff5133408952aefd6289584a67ca67 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 25 Sep 2026 18:03:00 +0200 Subject: [PATCH 07/15] RISC-V: KVM: Reject vCPU creation after AIA initialization AIA initialization sets up per-vCPU IMSIC state by iterating over all online vCPUs. Creating another vCPU afterwards leaves it without initialized IMSIC state, but KVM currently permits that sequence. Reject KVM_CREATE_VCPU once AIA initialization succeeds. Both paths are serialized by kvm->lock, so checking the initialized state from kvm_arch_vcpu_precreate() freezes the vCPU set used by AIA. Fixes: 89d01306e34d ("RISC-V: KVM: Implement device interface for AIA irqchip") Signed-off-by: Andrew Jones Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260925160300.467884-1-andrew.jones@oss.qualcomm.com Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 7f1636c44d41..dd786f758eb7 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -138,6 +138,9 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset) int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) { + if (kvm_riscv_aia_initialized(kvm)) + return -EBUSY; + return 0; } From 2ddd9c19780f60a4251f8bfd447efe811e62811b Mon Sep 17 00:00:00 2001 From: Zhanpeng Zhang Date: Tue, 22 Sep 2026 10:18:24 +0800 Subject: [PATCH 08/15] RISC-V: KVM: Fix build with vector support disabled The kernel-mode vector context handling added unconditional calls to get_cpu_vector_context(), put_cpu_vector_context() and __kvm_riscv_vector_restore() in vcpu.c. With CONFIG_RISCV_ISA_V=n, these calls fail to build due to missing declarations. The get/put helpers already have no-op definitions in asm/vector.h, but kvm_vcpu_vector.h only includes that header when CONFIG_RISCV_ISA_V is enabled. Include it unconditionally and provide a no-op implementation of __kvm_riscv_vector_restore() for the disabled configuration, matching the other vector context helpers. The paths that set RISCV_V_VCPU_NEED_RESTORE are compiled out when vector support is disabled, so the restore stub does not discard any live vector state. Keep it __always_inline for its noinstr caller. The vector enabled implementation is unchanged. Fixes: b5060a4aa33d ("RISC-V: KVM: fix vcpu vector context handling for kernel-mode vector") Signed-off-by: Zhanpeng Zhang Reviewed-by: Charlie Jenkins Tested-by: Charlie Jenkins Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260922021823.44251-2-zhangzhanpeng.jasper@bytedance.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_vector.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h index 6371d5ea5392..50d4789b9cac 100644 --- a/arch/riscv/include/asm/kvm_vcpu_vector.h +++ b/arch/riscv/include/asm/kvm_vcpu_vector.h @@ -11,9 +11,9 @@ #define __KVM_VCPU_RISCV_VECTOR_H #include +#include #ifdef CONFIG_RISCV_ISA_V -#include #include static __always_inline void __kvm_riscv_vector_save(struct kvm_cpu_context *context) @@ -55,6 +55,10 @@ static inline void kvm_riscv_v_exit(void) struct kvm_cpu_context; +static __always_inline void __kvm_riscv_vector_restore(struct kvm_cpu_context *context) +{ +} + static inline void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu) { } From c367d3bf721f2bc391d6cfb47f6884e99d563df0 Mon Sep 17 00:00:00 2001 From: Xiaofeng Yuan Date: Thu, 17 Sep 2026 20:20:12 +0800 Subject: [PATCH 09/15] RISC-V: KVM: Fix IPI delivery for out-of-order vcpu_id The SBI IPI handler walks vCPUs with kvm_for_each_vcpu(), which iterates by vcpu_idx (creation order) rather than vcpu_id order. Since vcpu_id can be assigned out of order by userspace, a vCPU whose hart_bit falls outside the XLEN-bit hart_mask range may be reached before vCPUs the mask actually targets. In that case the handler jumps to "done" and stops sending IPIs, leaving valid target vCPUs without an interrupt. Replace the early "goto done" with "continue" so vCPUs outside the hart_mask range are skipped without aborting the loop. Reproduced with a minimal userspace VMM driving KVM inside a QEMU (RISC-V virt) guest: three vCPUs are created with ids 100, 0, 1 (in creation order) and sbi_send_ipi(hart_mask=bit0, hbase=0) is called from vcpu_id 1. Before this change the IPI is dropped and the ecall returns SBI_ERR_INVALID_PARAM; with this change the IPI is delivered and the ecall returns SBI_SUCCESS. Fixes: 0611f78f83c9 ("riscv: KVM: Fix SBI IPI error generation") Cc: stable@vger.kernel.org Suggested-by: Andrew Jones Signed-off-by: Xiaofeng Yuan Reviewed-by: Nutty Liu Reviewed-by: Troy Mitchell Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260917122012.2577-1-yuanxiaofeng@eswincomputing.com Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_sbi_replace.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/riscv/kvm/vcpu_sbi_replace.c b/arch/riscv/kvm/vcpu_sbi_replace.c index 506a510b6bff..c2f1f7f26442 100644 --- a/arch/riscv/kvm/vcpu_sbi_replace.c +++ b/arch/riscv/kvm/vcpu_sbi_replace.c @@ -64,8 +64,17 @@ static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, if (tmp->vcpu_id < hbase) continue; hart_bit = tmp->vcpu_id - hbase; + /* + * kvm_for_each_vcpu() walks kvm->vcpus[] by + * vcpu_idx, i.e. the creation order, which has + * nothing to do with the vcpu_id (hart id) space + * that the SBI IPI operates on. vcpu_ids need not + * increase along the iteration, so harts outside + * the hart_mask window must be skipped instead of + * aborting the loop. + */ if (hart_bit >= __riscv_xlen) - goto done; + continue; if (!(hmask & (1UL << hart_bit))) continue; } @@ -76,7 +85,6 @@ static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, kvm_riscv_vcpu_pmu_incr_fw(tmp, SBI_PMU_FW_IPI_RCVD); } -done: if (hbase != -1UL && (hmask ^ sentmask)) retdata->err_val = SBI_ERR_INVALID_PARAM; From bae99073549aba7c3d79685a4640a46aa5c55340 Mon Sep 17 00:00:00 2001 From: Xiaofeng Yuan Date: Thu, 17 Sep 2026 20:14:11 +0800 Subject: [PATCH 10/15] RISC-V: KVM: Replace imsic switch-case macros with range checks The imsic_eix_read/swap/write/set accessors use a family of macros that expand into a switch with 128 cases covering the EIP and EIE register windows. This mirrors the csr_read_num() idiom required where a CSR number must be encoded as a csrr instruction immediate (e.g. drivers/perf/riscv_pmu.c), but here the register number is merely written to vsiselect as data, so the expansion solves no real constraint. It costs ~90 lines of nested macros and trips ~30 checkpatch errors and warnings. Since the generated cases form two contiguous windows, [IMSIC_EIP0, IMSIC_EIP63] and [IMSIC_EIE0, IMSIC_EIE63], the same behavior is expressed with a simple range check. Introduce imsic_eix_ireg_is_valid() and use it in the four accessors, removing the macros along with the ~30 checkpatch errors and warnings they caused. No functional change intended. Compile tested with riscv64-linux-gnu-gcc and tested on QEMU (RISC-V virt, AIA). Signed-off-by: Xiaofeng Yuan Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260917121411.2445-1-yuanxiaofeng@eswincomputing.com Signed-off-by: Anup Patel --- arch/riscv/kvm/aia_imsic.c | 124 +++++-------------------------------- 1 file changed, 15 insertions(+), 109 deletions(-) diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c index f17dc559a709..984b2212328a 100644 --- a/arch/riscv/kvm/aia_imsic.c +++ b/arch/riscv/kvm/aia_imsic.c @@ -67,36 +67,17 @@ struct imsic { __r; \ }) -#define imsic_read_switchcase(__ireg) \ - case __ireg: \ - return imsic_vs_csr_read(__ireg); -#define imsic_read_switchcase_2(__ireg) \ - imsic_read_switchcase(__ireg + 0) \ - imsic_read_switchcase(__ireg + 1) -#define imsic_read_switchcase_4(__ireg) \ - imsic_read_switchcase_2(__ireg + 0) \ - imsic_read_switchcase_2(__ireg + 2) -#define imsic_read_switchcase_8(__ireg) \ - imsic_read_switchcase_4(__ireg + 0) \ - imsic_read_switchcase_4(__ireg + 4) -#define imsic_read_switchcase_16(__ireg) \ - imsic_read_switchcase_8(__ireg + 0) \ - imsic_read_switchcase_8(__ireg + 8) -#define imsic_read_switchcase_32(__ireg) \ - imsic_read_switchcase_16(__ireg + 0) \ - imsic_read_switchcase_16(__ireg + 16) -#define imsic_read_switchcase_64(__ireg) \ - imsic_read_switchcase_32(__ireg + 0) \ - imsic_read_switchcase_32(__ireg + 32) +static inline bool imsic_eix_ireg_is_valid(int ireg) +{ + return (ireg >= IMSIC_EIP0 && ireg <= IMSIC_EIP63) || + (ireg >= IMSIC_EIE0 && ireg <= IMSIC_EIE63); +} static unsigned long imsic_eix_read(int ireg) { - switch (ireg) { - imsic_read_switchcase_64(IMSIC_EIP0) - imsic_read_switchcase_64(IMSIC_EIE0) - } - - return 0; + if (!imsic_eix_ireg_is_valid(ireg)) + return 0; + return imsic_vs_csr_read(ireg); } #define imsic_vs_csr_swap(__c, __v) \ @@ -107,36 +88,11 @@ static unsigned long imsic_eix_read(int ireg) __r; \ }) -#define imsic_swap_switchcase(__ireg, __v) \ - case __ireg: \ - return imsic_vs_csr_swap(__ireg, __v); -#define imsic_swap_switchcase_2(__ireg, __v) \ - imsic_swap_switchcase(__ireg + 0, __v) \ - imsic_swap_switchcase(__ireg + 1, __v) -#define imsic_swap_switchcase_4(__ireg, __v) \ - imsic_swap_switchcase_2(__ireg + 0, __v) \ - imsic_swap_switchcase_2(__ireg + 2, __v) -#define imsic_swap_switchcase_8(__ireg, __v) \ - imsic_swap_switchcase_4(__ireg + 0, __v) \ - imsic_swap_switchcase_4(__ireg + 4, __v) -#define imsic_swap_switchcase_16(__ireg, __v) \ - imsic_swap_switchcase_8(__ireg + 0, __v) \ - imsic_swap_switchcase_8(__ireg + 8, __v) -#define imsic_swap_switchcase_32(__ireg, __v) \ - imsic_swap_switchcase_16(__ireg + 0, __v) \ - imsic_swap_switchcase_16(__ireg + 16, __v) -#define imsic_swap_switchcase_64(__ireg, __v) \ - imsic_swap_switchcase_32(__ireg + 0, __v) \ - imsic_swap_switchcase_32(__ireg + 32, __v) - static unsigned long imsic_eix_swap(int ireg, unsigned long val) { - switch (ireg) { - imsic_swap_switchcase_64(IMSIC_EIP0, val) - imsic_swap_switchcase_64(IMSIC_EIE0, val) - } - - return 0; + if (!imsic_eix_ireg_is_valid(ireg)) + return 0; + return imsic_vs_csr_swap(ireg, val); } #define imsic_vs_csr_write(__c, __v) \ @@ -145,35 +101,10 @@ do { \ csr_write(CSR_VSIREG, __v); \ } while (0) -#define imsic_write_switchcase(__ireg, __v) \ - case __ireg: \ - imsic_vs_csr_write(__ireg, __v); \ - break; -#define imsic_write_switchcase_2(__ireg, __v) \ - imsic_write_switchcase(__ireg + 0, __v) \ - imsic_write_switchcase(__ireg + 1, __v) -#define imsic_write_switchcase_4(__ireg, __v) \ - imsic_write_switchcase_2(__ireg + 0, __v) \ - imsic_write_switchcase_2(__ireg + 2, __v) -#define imsic_write_switchcase_8(__ireg, __v) \ - imsic_write_switchcase_4(__ireg + 0, __v) \ - imsic_write_switchcase_4(__ireg + 4, __v) -#define imsic_write_switchcase_16(__ireg, __v) \ - imsic_write_switchcase_8(__ireg + 0, __v) \ - imsic_write_switchcase_8(__ireg + 8, __v) -#define imsic_write_switchcase_32(__ireg, __v) \ - imsic_write_switchcase_16(__ireg + 0, __v) \ - imsic_write_switchcase_16(__ireg + 16, __v) -#define imsic_write_switchcase_64(__ireg, __v) \ - imsic_write_switchcase_32(__ireg + 0, __v) \ - imsic_write_switchcase_32(__ireg + 32, __v) - static void imsic_eix_write(int ireg, unsigned long val) { - switch (ireg) { - imsic_write_switchcase_64(IMSIC_EIP0, val) - imsic_write_switchcase_64(IMSIC_EIE0, val) - } + if (imsic_eix_ireg_is_valid(ireg)) + imsic_vs_csr_write(ireg, val); } #define imsic_vs_csr_set(__c, __v) \ @@ -182,35 +113,10 @@ do { \ csr_set(CSR_VSIREG, __v); \ } while (0) -#define imsic_set_switchcase(__ireg, __v) \ - case __ireg: \ - imsic_vs_csr_set(__ireg, __v); \ - break; -#define imsic_set_switchcase_2(__ireg, __v) \ - imsic_set_switchcase(__ireg + 0, __v) \ - imsic_set_switchcase(__ireg + 1, __v) -#define imsic_set_switchcase_4(__ireg, __v) \ - imsic_set_switchcase_2(__ireg + 0, __v) \ - imsic_set_switchcase_2(__ireg + 2, __v) -#define imsic_set_switchcase_8(__ireg, __v) \ - imsic_set_switchcase_4(__ireg + 0, __v) \ - imsic_set_switchcase_4(__ireg + 4, __v) -#define imsic_set_switchcase_16(__ireg, __v) \ - imsic_set_switchcase_8(__ireg + 0, __v) \ - imsic_set_switchcase_8(__ireg + 8, __v) -#define imsic_set_switchcase_32(__ireg, __v) \ - imsic_set_switchcase_16(__ireg + 0, __v) \ - imsic_set_switchcase_16(__ireg + 16, __v) -#define imsic_set_switchcase_64(__ireg, __v) \ - imsic_set_switchcase_32(__ireg + 0, __v) \ - imsic_set_switchcase_32(__ireg + 32, __v) - static void imsic_eix_set(int ireg, unsigned long val) { - switch (ireg) { - imsic_set_switchcase_64(IMSIC_EIP0, val) - imsic_set_switchcase_64(IMSIC_EIE0, val) - } + if (imsic_eix_ireg_is_valid(ireg)) + imsic_vs_csr_set(ireg, val); } static unsigned long imsic_mrif_atomic_rmw(struct imsic_mrif *mrif, From 80f6e72b21aa773e71c748e1e5a6d3aa8d458bd7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 25 Sep 2026 17:51:16 +0200 Subject: [PATCH 11/15] RISC-V: KVM: Use a raw lock for IMSIC wakeup state kvm_riscv_vcpu_aia_imsic_put() can run from the scheduler preemption notifier while the raw runqueue lock is held. Taking vsfile_lock, an rwlock_t, there violates the lockdep wait-context rules. Protect the CPU/HGEI pair with a separate raw spinlock. All updates to that pair retain vsfile_lock and take the new lock, while scheduler-out uses only the new lock around the HGEIE update. This keeps the wakeup setup serialized with VS-file publication and release without bringing wider IMSIC operations into a raw critical section. Fixes: 4cec89db80ba ("RISC-V: KVM: Move HGEI[E|P] CSR access to IMSIC virtualization") Signed-off-by: Andrew Jones Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260925155116.465203-1-andrew.jones@oss.qualcomm.com Signed-off-by: Anup Patel --- arch/riscv/kvm/aia_imsic.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c index 984b2212328a..302938972aa0 100644 --- a/arch/riscv/kvm/aia_imsic.c +++ b/arch/riscv/kvm/aia_imsic.c @@ -48,6 +48,8 @@ struct imsic { /* IMSIC VS-file */ rwlock_t vsfile_lock; + /* Writers hold both locks; scheduler-out only takes vsfile_hgei_lock. */ + raw_spinlock_t vsfile_hgei_lock; int vsfile_cpu; int vsfile_hgei; void __iomem *vsfile_va; @@ -488,6 +490,17 @@ static void imsic_vsfile_local_update(int vsfile_hgei, u32 nr_eix, csr_write(CSR_VSISELECT, old_vsiselect); } +static void imsic_vsfile_set_hgei(struct imsic *imsic, int cpu, int hgei) +{ + unsigned long flags; + + /* Serialize the CPU/HGEI pair with scheduler-out's wakeup setup. */ + raw_spin_lock_irqsave(&imsic->vsfile_hgei_lock, flags); + imsic->vsfile_cpu = cpu; + imsic->vsfile_hgei = hgei; + raw_spin_unlock_irqrestore(&imsic->vsfile_hgei_lock, flags); +} + static void imsic_vsfile_cleanup(struct imsic *imsic) { int old_vsfile_hgei, old_vsfile_cpu; @@ -502,7 +515,7 @@ static void imsic_vsfile_cleanup(struct imsic *imsic) write_lock_irqsave(&imsic->vsfile_lock, flags); old_vsfile_hgei = imsic->vsfile_hgei; old_vsfile_cpu = imsic->vsfile_cpu; - imsic->vsfile_cpu = imsic->vsfile_hgei = -1; + imsic_vsfile_set_hgei(imsic, -1, -1); imsic->vsfile_va = NULL; imsic->vsfile_pa = 0; write_unlock_irqrestore(&imsic->vsfile_lock, flags); @@ -633,10 +646,10 @@ void kvm_riscv_vcpu_aia_imsic_put(struct kvm_vcpu *vcpu) if (!kvm_vcpu_is_blocking(vcpu)) return; - read_lock_irqsave(&imsic->vsfile_lock, flags); + raw_spin_lock_irqsave(&imsic->vsfile_hgei_lock, flags); if (imsic->vsfile_cpu > -1) csr_set(CSR_HGEIE, BIT(imsic->vsfile_hgei)); - read_unlock_irqrestore(&imsic->vsfile_lock, flags); + raw_spin_unlock_irqrestore(&imsic->vsfile_hgei_lock, flags); } void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu) @@ -653,7 +666,7 @@ void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu) write_lock_irqsave(&imsic->vsfile_lock, flags); old_vsfile_hgei = imsic->vsfile_hgei; old_vsfile_cpu = imsic->vsfile_cpu; - imsic->vsfile_cpu = imsic->vsfile_hgei = -1; + imsic_vsfile_set_hgei(imsic, -1, -1); imsic->vsfile_va = NULL; imsic->vsfile_pa = 0; write_unlock_irqrestore(&imsic->vsfile_lock, flags); @@ -767,8 +780,7 @@ int kvm_riscv_vcpu_aia_imsic_update(struct kvm_vcpu *vcpu) /* Update new IMSIC VS-file details in IMSIC context */ write_lock_irqsave(&imsic->vsfile_lock, flags); - imsic->vsfile_hgei = new_vsfile_hgei; - imsic->vsfile_cpu = vcpu->cpu; + imsic_vsfile_set_hgei(imsic, vcpu->cpu, new_vsfile_hgei); imsic->vsfile_va = new_vsfile_va; imsic->vsfile_pa = new_vsfile_pa; write_unlock_irqrestore(&imsic->vsfile_lock, flags); @@ -1025,6 +1037,7 @@ int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu) /* Setup IMSIC context */ imsic->nr_msis = kvm->arch.aia.nr_ids + 1; rwlock_init(&imsic->vsfile_lock); + raw_spin_lock_init(&imsic->vsfile_hgei_lock); imsic->nr_eix = BITS_TO_U64(imsic->nr_msis); imsic->nr_hw_eix = BITS_TO_U64(kvm_riscv_aia_max_ids); imsic->vsfile_hgei = imsic->vsfile_cpu = -1; From d8538f942fd1006cd6f9b687ace6d45a2c3c015c Mon Sep 17 00:00:00 2001 From: Stefan Butz Date: Thu, 1 Oct 2026 09:35:07 +0200 Subject: [PATCH 12/15] RISC-V: KVM: Don't write MMIO load result to x0 An MMIO load with rd=x0 writes the result into guest_context.zero, which is never cleared, so later emulated reads of x0 return garbage. Fixes: 9f7013265112 ("RISC-V: KVM: Handle MMIO exits for VCPU") Signed-off-by: Stefan Butz Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20261001-b4-mmio_load_protect_x0-v1-1-90515d86f201@butz.st Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_insn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index adbbb59a0f36..2a8dc2b88ba8 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -647,7 +647,7 @@ int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu->arch.mmio_decode.return_handled = 1; insn = vcpu->arch.mmio_decode.insn; - if (run->mmio.is_write) + if (run->mmio.is_write || !((insn >> SH_RD) & MASK_RX)) goto done; len = vcpu->arch.mmio_decode.len; From 7e8fa1a887a044ded2971217196cb07e56902ded Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Sat, 26 Sep 2026 13:52:27 +0800 Subject: [PATCH 13/15] MAINTAINERS: name the kvm-riscv/linux riscv_kvm_next branch The T: entry for KERNEL VIRTUAL MACHINE FOR RISC-V (KVM/riscv) names github.com/kvm-riscv/linux without a branch. The repository's HEAD points to branch master, which mainline already contains. linux-next merges the riscv_kvm_next branch of this repository (Next/Trees). Name that branch in the entry. Signed-off-by: Matthias Goergens Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260926055227.3678332-1-matthias.goergens@gmail.com Signed-off-by: Anup Patel --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 72294ddfa5b7..fa481b2dd40f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14358,7 +14358,7 @@ L: kvm@vger.kernel.org L: kvm-riscv@lists.infradead.org L: linux-riscv@lists.infradead.org S: Maintained -T: git https://github.com/kvm-riscv/linux.git +T: git https://github.com/kvm-riscv/linux.git riscv_kvm_next F: arch/riscv/include/asm/kvm* F: arch/riscv/include/uapi/asm/kvm* F: arch/riscv/kvm/ From 65452f8b9c02d79d200731f627db9c6f5d8c387d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 15 Oct 2026 00:42:38 +0200 Subject: [PATCH 14/15] RISC-V: KVM: Allow Zicclsm, Ziccamoa, Ziccif, Za64rs in guest Extend the KVM ISA extension array to allow KVM userspace to detect Zicclsm, Ziccamoa, Ziccif, Za64rs. This is just notifying of hardware provided capabilities. No KVM specific support is needed. Signed-off-by: Heinrich Schuchardt Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20261014224239.963635-2-heinrich.schuchardt@canonical.com Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 4 ++++ arch/riscv/kvm/isa.c | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 20d9959ca44f..39b0f3f1d486 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -206,6 +206,10 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_ZALASR, KVM_RISCV_ISA_EXT_ZICFILP, KVM_RISCV_ISA_EXT_ZICFISS, + KVM_RISCV_ISA_EXT_ZICCLSM, + KVM_RISCV_ISA_EXT_ZICCAMOA, + KVM_RISCV_ISA_EXT_ZICCIF, + KVM_RISCV_ISA_EXT_ZA64RS, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kvm/isa.c b/arch/riscv/kvm/isa.c index 971f44655100..72e3dc15d294 100644 --- a/arch/riscv/kvm/isa.c +++ b/arch/riscv/kvm/isa.c @@ -38,6 +38,7 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(SVNAPOT), KVM_ISA_EXT_ARR(SVPBMT), KVM_ISA_EXT_ARR(SVVPTC), + KVM_ISA_EXT_ARR(ZA64RS), KVM_ISA_EXT_ARR(ZAAMO), KVM_ISA_EXT_ARR(ZABHA), KVM_ISA_EXT_ARR(ZACAS), @@ -64,6 +65,9 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZICBOM), KVM_ISA_EXT_ARR(ZICBOP), KVM_ISA_EXT_ARR(ZICBOZ), + KVM_ISA_EXT_ARR(ZICCAMOA), + KVM_ISA_EXT_ARR(ZICCIF), + KVM_ISA_EXT_ARR(ZICCLSM), KVM_ISA_EXT_ARR(ZICCRSE), KVM_ISA_EXT_ARR(ZICFILP), KVM_ISA_EXT_ARR(ZICFISS), @@ -183,6 +187,7 @@ bool kvm_riscv_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_SVINVAL: case KVM_RISCV_ISA_EXT_SVNAPOT: case KVM_RISCV_ISA_EXT_SVVPTC: + case KVM_RISCV_ISA_EXT_ZA64RS: case KVM_RISCV_ISA_EXT_ZAAMO: case KVM_RISCV_ISA_EXT_ZABHA: case KVM_RISCV_ISA_EXT_ZACAS: @@ -206,6 +211,9 @@ bool kvm_riscv_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_ZFH: case KVM_RISCV_ISA_EXT_ZFHMIN: case KVM_RISCV_ISA_EXT_ZICBOP: + case KVM_RISCV_ISA_EXT_ZICCAMOA: + case KVM_RISCV_ISA_EXT_ZICCIF: + case KVM_RISCV_ISA_EXT_ZICCLSM: case KVM_RISCV_ISA_EXT_ZICCRSE: case KVM_RISCV_ISA_EXT_ZICNTR: case KVM_RISCV_ISA_EXT_ZICOND: From 633b3931a87438282d6454646ff40c669a6896cb Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 15 Oct 2026 00:42:39 +0200 Subject: [PATCH 15/15] KVM: riscv: selftest: add Zicclsm, Ziccamoa, Ziccif, Za64rs KVM supports extensions Zicclsm, Ziccamoa, Ziccif, Za64rs for the guest. Add these extensions to the get-reg-list test. Signed-off-by: Heinrich Schuchardt Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20261014224239.963635-3-heinrich.schuchardt@canonical.com Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/riscv/get-reg-list.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index bf3980e9db12..71e5969142b3 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -63,6 +63,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVNAPOT: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVPBMT: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVVPTC: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZA64RS: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZAAMO: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZABHA: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZACAS: @@ -89,6 +90,9 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOP: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOZ: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICCAMOA: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICCIF: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICCLSM: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICCRSE: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICFILP: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICFISS: @@ -576,6 +580,7 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(SVNAPOT), KVM_ISA_EXT_ARR(SVPBMT), KVM_ISA_EXT_ARR(SVVPTC), + KVM_ISA_EXT_ARR(ZA64RS), KVM_ISA_EXT_ARR(ZAAMO), KVM_ISA_EXT_ARR(ZABHA), KVM_ISA_EXT_ARR(ZACAS), @@ -602,6 +607,9 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(ZICBOM), KVM_ISA_EXT_ARR(ZICBOP), KVM_ISA_EXT_ARR(ZICBOZ), + KVM_ISA_EXT_ARR(ZICCAMOA), + KVM_ISA_EXT_ARR(ZICCIF), + KVM_ISA_EXT_ARR(ZICCLSM), KVM_ISA_EXT_ARR(ZICCRSE), KVM_ISA_EXT_ARR(ZICFILP), KVM_ISA_EXT_ARR(ZICFISS), @@ -1238,6 +1246,7 @@ KVM_ISA_EXT_SIMPLE_CONFIG(svinval, SVINVAL); KVM_ISA_EXT_SIMPLE_CONFIG(svnapot, SVNAPOT); KVM_ISA_EXT_SIMPLE_CONFIG(svpbmt, SVPBMT); KVM_ISA_EXT_SIMPLE_CONFIG(svvptc, SVVPTC); +KVM_ISA_EXT_SIMPLE_CONFIG(za64rs, ZA64RS); KVM_ISA_EXT_SIMPLE_CONFIG(zaamo, ZAAMO); KVM_ISA_EXT_SIMPLE_CONFIG(zabha, ZABHA); KVM_ISA_EXT_SIMPLE_CONFIG(zacas, ZACAS); @@ -1264,6 +1273,9 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zfhmin, ZFHMIN); KVM_ISA_EXT_SUBLIST_CONFIG(zicbom, ZICBOM); KVM_ISA_EXT_SUBLIST_CONFIG(zicbop, ZICBOP); KVM_ISA_EXT_SUBLIST_CONFIG(zicboz, ZICBOZ); +KVM_ISA_EXT_SIMPLE_CONFIG(ziccamoa, ZICCAMOA); +KVM_ISA_EXT_SIMPLE_CONFIG(ziccif, ZICCIF); +KVM_ISA_EXT_SIMPLE_CONFIG(zicclsm, ZICCLSM); KVM_ISA_EXT_SIMPLE_CONFIG(ziccrse, ZICCRSE); KVM_ISA_EXT_SIMPLE_CONFIG(zicfilp, ZICFILP); KVM_ISA_EXT_SUBLIST_CONFIG(zicfiss, ZICFISS); @@ -1372,6 +1384,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_svnapot, &config_svpbmt, &config_svvptc, + &config_za64rs, &config_zaamo, &config_zabha, &config_zacas, @@ -1398,6 +1411,9 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_zicbom, &config_zicbop, &config_zicboz, + &config_ziccamoa, + &config_ziccif, + &config_zicclsm, &config_ziccrse, &config_zicfilp, &config_zicfiss,