diff --git a/MAINTAINERS b/MAINTAINERS index dd9680d9de0b..4d81161dd982 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14361,7 +14361,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/ 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) { } 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/Kconfig b/arch/riscv/kvm/Kconfig index 2e3c4e6c1cd7..f7e4d0f9b156 100644 --- a/arch/riscv/kvm/Kconfig +++ b/arch/riscv/kvm/Kconfig @@ -26,6 +26,7 @@ config KVM select KVM_COMMON select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_GENERIC_HARDWARE_ENABLING + select KVM_GENERIC_PRE_FAULT_MEMORY select VIRT_XFER_TO_GUEST_WORK select SCHED_INFO select GUEST_PERF_EVENTS if PERF_EVENTS diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c index f17dc559a709..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; @@ -67,36 +69,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 +90,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 +103,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 +115,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, @@ -582,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; @@ -596,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); @@ -727,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) @@ -747,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); @@ -861,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); @@ -1119,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; 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/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: diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index 3e955d808743..8b8959099651 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -754,6 +754,53 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot, return ret; } +int kvm_arch_pre_fault_allowed(struct kvm_vcpu *vcpu) +{ + return 0; +} + +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/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; } 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; 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; 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) 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: diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 3cb35a6963d5..17a4256e9081 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -242,6 +242,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 e3acf2ae9881..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 @@ -25,6 +28,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; @@ -127,6 +143,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 c175dcd14114..5478ac038029 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; @@ -43,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[] = { @@ -50,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) @@ -233,6 +240,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)); @@ -268,6 +276,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, @@ -294,13 +306,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); -} - -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); + 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) @@ -346,8 +354,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; } @@ -406,19 +432,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) @@ -430,6 +480,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); @@ -446,6 +526,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); 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,