mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Merge tag 'kvm-riscv-7.4-1' of https://github.com/kvm-riscv/linux into HEAD
KVM/riscv changes for 7.4 - Lazy V-extension enablement for KVM selftests - Avoid redundant interrupt check for pending timers - Implement KVM_PRE_FAULT_MEMORY ioctl() and enable corresponding KVM selftests - Show sepc/scause/stval CSRs in KVM selftests vcpu dump - Reject vCPU creation after AIA initialization - Fix build with vector support disabled - Fix IPI delivery for out-of-order vcpu_id - Replace imsic switch-case macros with range checks - Use a raw lock for IMSIC wakeup state - Reject vCPU creation after AIA initialization - Updated next branch name in KVM/riscv MAINTAINERS entry - Allow Zicclsm, Ziccamoa, Ziccif, Za64rs for KVM guest
This commit is contained in:
commit
7e60162b16
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
#define __KVM_VCPU_RISCV_VECTOR_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/vector.h>
|
||||
|
||||
#ifdef CONFIG_RISCV_ISA_V
|
||||
#include <asm/vector.h>
|
||||
#include <asm/kvm_host.h>
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
#include <asm/vdso/processor.h>
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user