mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
KVM/riscv fixes for 7.2, take #1
- Avoid redundant page-table allocations in ioremap pcache topup - Apply SBI FWFT LOCK flag only on successful set - Bound SBI PMU counter mask scan to BITS_PER_LONG - Skip TLB flush when G-stage PTE becomes valid with Svvptc - Zicbo[m|z|p] block sizes should be always present in ONE_REG - Inject instruction access fault on unmapped guest fetch - Serialize virtual interrupt pending state updates using raw spinlock - Fix Spectre-v1 in vector register access via ONE_REG -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEZdn75s5e6LHDQ+f/rUjsVaLHLAcFAmpbMVwACgkQrUjsVaLH LAdENhAAi5eWE2WACOp50yy+e9/K/n7WFyGsnAg1u157HR0ywBIfOKA9Q3fGnHs/ WUeqXjtjnVLJFB/LfG3aF9O4PLyU+iZ2g7On5O4ZXQMY2wpueHBZ2fyvUFmrWKl6 JwwgluMxeX1IIhJdhSe0hUU8sxcurYtmuxMKO/2lkYcqxfn6UGpBHONkNGVBncsJ RcaU2lQBnv+8hJ0wlCb0hep9R34YkjF1rmti71tru7XqnF3rq2Z5PBITjfBHXmeB 6iYvVnpSvPiEvxF8454dvQ9bbXmh3OS+ncI/qjS1u2fkrQrM00eZs2bKzUpW7LlG 7ZA5Rm+EQPbHoPV1EKHXXip7uSZ7U8nm9CxMCADI7zZi1K3qvKnnRtA4MahLxO2o WSxWEW7ONHskZWz1YZUyqpPCutJQOtKaIu7ITzS0aHep9UB/3Lrs1sA9hRTEINUl 9O1Nusro+wdlG1SsycWXPNoyHvEnN1h2FjWLRpr54X9mEQtCCg0/qNvwo6CPZNwH E9lWgx7rcFnmy24ln01fHOtTD5IKRNis2MUswqNVyc3X7gOft+w8/1QE/MHYC9cl LF7b12xCOFp1PMkicgVYwWRQ+6qrvidFvWOWqVtcRmfMw6TjXIrB5Fr/MYg8gBL/ N6uzyk3+UmSiFehbElXww3YEiqd81KzKgeEsU74/T2yyAEflVYA= =jcT0 -----END PGP SIGNATURE----- Merge tag 'kvm-riscv-fixes-7.2-1' of https://github.com/kvm-riscv/linux into HEAD KVM/riscv fixes for 7.2, take #1 - Avoid redundant page-table allocations in ioremap pcache topup - Apply SBI FWFT LOCK flag only on successful set - Bound SBI PMU counter mask scan to BITS_PER_LONG - Skip TLB flush when G-stage PTE becomes valid with Svvptc - Zicbo[m|z|p] block sizes should be always present in ONE_REG - Inject instruction access fault on unmapped guest fetch - Serialize virtual interrupt pending state updates using raw spinlock - Fix Spectre-v1 in vector register access via ONE_REG
This commit is contained in:
commit
e61e6fd4f1
|
|
@ -209,13 +209,13 @@ struct kvm_vcpu_arch {
|
|||
/*
|
||||
* VCPU interrupts
|
||||
*
|
||||
* We have a lockless approach for tracking pending VCPU interrupts
|
||||
* implemented using atomic bitops. The irqs_pending bitmap represent
|
||||
* pending interrupts whereas irqs_pending_mask represent bits changed
|
||||
* in irqs_pending. Our approach is modeled around multiple producer
|
||||
* and single consumer problem where the consumer is the VCPU itself.
|
||||
* The irqs_pending bitmap represents pending interrupts whereas
|
||||
* irqs_pending_mask represents bits changed in irqs_pending. Updates
|
||||
* to these bitmaps are serialized so vcpu interrupt sync/flush cannot
|
||||
* drop a newly injected interrupt while syncing guest-visible HVIP.
|
||||
*/
|
||||
#define KVM_RISCV_VCPU_NR_IRQS 64
|
||||
raw_spinlock_t irqs_pending_lock;
|
||||
DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
|
||||
DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
|
||||
|
||||
|
|
|
|||
|
|
@ -53,12 +53,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)
|
|||
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
|
||||
unsigned long mask, val;
|
||||
|
||||
lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
|
||||
|
||||
if (!kvm_riscv_aia_available())
|
||||
return;
|
||||
|
||||
if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) {
|
||||
mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0);
|
||||
val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask;
|
||||
mask = vcpu->arch.irqs_pending_mask[1];
|
||||
if (mask) {
|
||||
vcpu->arch.irqs_pending_mask[1] = 0;
|
||||
val = vcpu->arch.irqs_pending[1] & mask;
|
||||
|
||||
csr->hviph &= ~mask;
|
||||
csr->hviph |= val;
|
||||
|
|
@ -69,6 +72,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
|
||||
|
||||
lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
|
||||
|
||||
if (kvm_riscv_aia_available())
|
||||
csr->vsieh = ncsr_read(CSR_VSIEH);
|
||||
}
|
||||
|
|
@ -77,13 +82,22 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
|
|||
bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
|
||||
{
|
||||
unsigned long seip;
|
||||
#ifdef CONFIG_32BIT
|
||||
unsigned long flags;
|
||||
bool pending;
|
||||
#endif
|
||||
|
||||
if (!kvm_riscv_aia_available())
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_32BIT
|
||||
if (READ_ONCE(vcpu->arch.irqs_pending[1]) &
|
||||
(vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask)))
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
pending = vcpu->arch.irqs_pending[1] &
|
||||
(vcpu->arch.aia_context.guest_csr.vsieh &
|
||||
upper_32_bits(mask));
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
if (pending)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
|
|
@ -207,6 +221,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
|
||||
#ifdef CONFIG_32BIT
|
||||
unsigned long flags;
|
||||
#endif
|
||||
|
||||
if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
|
||||
return -ENOENT;
|
||||
|
|
@ -219,8 +236,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
|
|||
((unsigned long *)csr)[reg_num] = val;
|
||||
|
||||
#ifdef CONFIG_32BIT
|
||||
if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph))
|
||||
WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0);
|
||||
if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) {
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
vcpu->arch.irqs_pending_mask[1] = 0;
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock,
|
||||
flags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm/kvm_gstage.h>
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
unsigned long kvm_riscv_gstage_max_pgd_levels __ro_after_init = 3;
|
||||
|
|
@ -171,8 +173,10 @@ int kvm_riscv_gstage_set_pte(struct kvm_gstage *gstage,
|
|||
}
|
||||
|
||||
if (pte_val(*ptep) != pte_val(map->pte)) {
|
||||
bool was_invalid = !pte_val(*ptep);
|
||||
set_pte(ptep, map->pte);
|
||||
if (gstage_pte_leaf(ptep))
|
||||
if (gstage_pte_leaf(ptep) &&
|
||||
!(was_invalid && riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)))
|
||||
gstage_tlb_flush(gstage, current_level, map->addr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ int kvm_riscv_mmu_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa,
|
|||
pgprot_t prot;
|
||||
unsigned long pfn;
|
||||
phys_addr_t addr, end;
|
||||
unsigned long pgd_levels = kvm->arch.pgd_levels;
|
||||
struct kvm_mmu_memory_cache pcache = {
|
||||
.gfp_custom = (in_atomic) ? GFP_ATOMIC | __GFP_ACCOUNT : 0,
|
||||
.gfp_zero = __GFP_ZERO,
|
||||
|
|
@ -63,7 +64,7 @@ int kvm_riscv_mmu_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa,
|
|||
if (!writable)
|
||||
map.pte = pte_wrprotect(map.pte);
|
||||
|
||||
ret = kvm_mmu_topup_memory_cache(&pcache, kvm->arch.pgd_levels);
|
||||
ret = __kvm_mmu_topup_memory_cache(&pcache, pgd_levels, pgd_levels);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ static void kvm_riscv_vcpu_context_reset(struct kvm_vcpu *vcpu,
|
|||
|
||||
static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool loaded;
|
||||
|
||||
/**
|
||||
|
|
@ -104,8 +105,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
|
|||
|
||||
kvm_riscv_vcpu_aia_reset(vcpu);
|
||||
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
|
||||
bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
kvm_riscv_vcpu_pmu_reset(vcpu);
|
||||
|
||||
|
|
@ -151,6 +154,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
|||
|
||||
/* Setup VCPU hfence queue */
|
||||
spin_lock_init(&vcpu->arch.hfence_lock);
|
||||
raw_spin_lock_init(&vcpu->arch.irqs_pending_lock);
|
||||
|
||||
spin_lock_init(&vcpu->arch.reset_state.lock);
|
||||
|
||||
|
|
@ -352,10 +356,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
|
||||
unsigned long mask, val;
|
||||
unsigned long flags;
|
||||
|
||||
if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) {
|
||||
mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0);
|
||||
val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask;
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
mask = vcpu->arch.irqs_pending_mask[0];
|
||||
if (mask) {
|
||||
vcpu->arch.irqs_pending_mask[0] = 0;
|
||||
val = vcpu->arch.irqs_pending[0] & mask;
|
||||
|
||||
csr->hvip &= ~mask;
|
||||
csr->hvip |= val;
|
||||
|
|
@ -363,11 +371,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
|
|||
|
||||
/* Flush AIA high interrupts */
|
||||
kvm_riscv_vcpu_aia_flush_interrupts(vcpu);
|
||||
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long hvip;
|
||||
unsigned long flags;
|
||||
struct kvm_vcpu_arch *v = &vcpu->arch;
|
||||
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
|
||||
|
||||
|
|
@ -376,34 +387,41 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
|
|||
|
||||
/* Sync-up HVIP.VSSIP bit changes does by Guest */
|
||||
hvip = ncsr_read(CSR_HVIP);
|
||||
|
||||
raw_spin_lock_irqsave(&v->irqs_pending_lock, flags);
|
||||
|
||||
if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
|
||||
if (hvip & (1UL << IRQ_VS_SOFT)) {
|
||||
if (!test_and_set_bit(IRQ_VS_SOFT,
|
||||
v->irqs_pending_mask))
|
||||
set_bit(IRQ_VS_SOFT, v->irqs_pending);
|
||||
if (!__test_and_set_bit(IRQ_VS_SOFT,
|
||||
v->irqs_pending_mask))
|
||||
__set_bit(IRQ_VS_SOFT, v->irqs_pending);
|
||||
} else {
|
||||
if (!test_and_set_bit(IRQ_VS_SOFT,
|
||||
v->irqs_pending_mask))
|
||||
clear_bit(IRQ_VS_SOFT, v->irqs_pending);
|
||||
if (!__test_and_set_bit(IRQ_VS_SOFT,
|
||||
v->irqs_pending_mask))
|
||||
__clear_bit(IRQ_VS_SOFT, v->irqs_pending);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */
|
||||
if ((csr->hvip ^ hvip) & (1UL << IRQ_PMU_OVF)) {
|
||||
if (!(hvip & (1UL << IRQ_PMU_OVF)) &&
|
||||
!test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
|
||||
clear_bit(IRQ_PMU_OVF, v->irqs_pending);
|
||||
!__test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
|
||||
__clear_bit(IRQ_PMU_OVF, v->irqs_pending);
|
||||
}
|
||||
|
||||
/* Sync-up AIA high interrupts */
|
||||
kvm_riscv_vcpu_aia_sync_interrupts(vcpu);
|
||||
|
||||
raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags);
|
||||
|
||||
/* Sync-up timer CSRs */
|
||||
kvm_riscv_vcpu_timer_sync(vcpu);
|
||||
}
|
||||
|
||||
int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* We only allow VS-mode software, timer, and external
|
||||
* interrupts when irq is one of the local interrupts
|
||||
|
|
@ -416,9 +434,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
|||
irq != IRQ_PMU_OVF)
|
||||
return -EINVAL;
|
||||
|
||||
set_bit(irq, vcpu->arch.irqs_pending);
|
||||
smp_mb__before_atomic();
|
||||
set_bit(irq, vcpu->arch.irqs_pending_mask);
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
__set_bit(irq, vcpu->arch.irqs_pending);
|
||||
__set_bit(irq, vcpu->arch.irqs_pending_mask);
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
kvm_vcpu_kick(vcpu);
|
||||
|
||||
|
|
@ -427,6 +446,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
|||
|
||||
int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* We only allow VS-mode software, timer, counter overflow and external
|
||||
* interrupts when irq is one of the local interrupts
|
||||
|
|
@ -439,26 +460,33 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
|||
irq != IRQ_PMU_OVF)
|
||||
return -EINVAL;
|
||||
|
||||
clear_bit(irq, vcpu->arch.irqs_pending);
|
||||
smp_mb__before_atomic();
|
||||
set_bit(irq, vcpu->arch.irqs_pending_mask);
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
__clear_bit(irq, vcpu->arch.irqs_pending);
|
||||
__set_bit(irq, vcpu->arch.irqs_pending_mask);
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long ie;
|
||||
bool ret;
|
||||
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
|
||||
<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
|
||||
ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
|
||||
(unsigned long)mask;
|
||||
if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie)
|
||||
return true;
|
||||
ret = vcpu->arch.irqs_pending[0] & ie;
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
/* Check AIA high interrupts */
|
||||
return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
|
||||
if (!ret)
|
||||
ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,25 @@ static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||
return kvm_riscv_vcpu_mmio_store(vcpu, run,
|
||||
fault_addr,
|
||||
trap->htinst);
|
||||
case EXC_INST_GUEST_PAGE_FAULT: {
|
||||
/*
|
||||
* No memslot backs this GPA and an instruction fetch
|
||||
* cannot be emulated as MMIO. On bare metal a fetch
|
||||
* from an unbacked physical address raises an
|
||||
* instruction access fault, so reflect that back to
|
||||
* the guest.
|
||||
*/
|
||||
struct kvm_cpu_trap inst_trap = {
|
||||
.sepc = trap->sepc,
|
||||
.scause = EXC_INST_ACCESS,
|
||||
.stval = trap->stval,
|
||||
.htval = 0,
|
||||
.htinst = 0,
|
||||
};
|
||||
|
||||
kvm_riscv_vcpu_trap_redirect(vcpu, &inst_trap);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -50,19 +50,13 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu,
|
|||
reg_val = vcpu->arch.isa[0] & KVM_RISCV_BASE_ISA_MASK;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOM))
|
||||
return -ENOENT;
|
||||
reg_val = riscv_cbom_block_size;
|
||||
reg_val = (kvm_riscv_isa_check_host(ZICBOM)) ? 0 : riscv_cbom_block_size;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOZ))
|
||||
return -ENOENT;
|
||||
reg_val = riscv_cboz_block_size;
|
||||
reg_val = (kvm_riscv_isa_check_host(ZICBOZ)) ? 0 : riscv_cboz_block_size;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicbop_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOP))
|
||||
return -ENOENT;
|
||||
reg_val = riscv_cbop_block_size;
|
||||
reg_val = (kvm_riscv_isa_check_host(ZICBOP)) ? 0 : riscv_cbop_block_size;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(mvendorid):
|
||||
reg_val = vcpu->arch.mvendorid;
|
||||
|
|
@ -144,21 +138,15 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu,
|
|||
}
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOM))
|
||||
return -ENOENT;
|
||||
if (reg_val != riscv_cbom_block_size)
|
||||
if (reg_val && reg_val != riscv_cbom_block_size)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOZ))
|
||||
return -ENOENT;
|
||||
if (reg_val != riscv_cboz_block_size)
|
||||
if (reg_val && reg_val != riscv_cboz_block_size)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicbop_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOP))
|
||||
return -ENOENT;
|
||||
if (reg_val != riscv_cbop_block_size)
|
||||
if (reg_val && reg_val != riscv_cbop_block_size)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(mvendorid):
|
||||
|
|
@ -298,6 +286,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
|
||||
unsigned long flags;
|
||||
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
|
@ -311,8 +300,11 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
|
|||
|
||||
((unsigned long *)csr)[reg_num] = reg_val;
|
||||
|
||||
if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
|
||||
WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0);
|
||||
if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
vcpu->arch.irqs_pending_mask[0] = 0;
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -614,20 +606,6 @@ static int copy_config_reg_indices(const struct kvm_vcpu *vcpu,
|
|||
u64 size;
|
||||
u64 reg;
|
||||
|
||||
/*
|
||||
* Avoid reporting config reg if the corresponding extension
|
||||
* was not available.
|
||||
*/
|
||||
if (i == KVM_REG_RISCV_CONFIG_REG(zicbom_block_size) &&
|
||||
kvm_riscv_isa_check_host(ZICBOM))
|
||||
continue;
|
||||
else if (i == KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) &&
|
||||
kvm_riscv_isa_check_host(ZICBOZ))
|
||||
continue;
|
||||
else if (i == KVM_REG_RISCV_CONFIG_REG(zicbop_block_size) &&
|
||||
kvm_riscv_isa_check_host(ZICBOP))
|
||||
continue;
|
||||
|
||||
size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
|
||||
reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CONFIG | i;
|
||||
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ int kvm_riscv_vcpu_pmu_ctr_start(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|||
}
|
||||
}
|
||||
/* Start the counters that have been configured and requested by the guest */
|
||||
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
|
||||
for_each_set_bit(i, &ctr_mask, BITS_PER_LONG) {
|
||||
pmc_index = array_index_nospec(i + ctr_base,
|
||||
RISCV_KVM_MAX_COUNTERS);
|
||||
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
|
||||
|
|
@ -658,7 +658,7 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|||
}
|
||||
|
||||
/* Stop the counters that have been configured and requested by the guest */
|
||||
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
|
||||
for_each_set_bit(i, &ctr_mask, BITS_PER_LONG) {
|
||||
pmc_index = array_index_nospec(i + ctr_base,
|
||||
RISCV_KVM_MAX_COUNTERS);
|
||||
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
|
||||
|
|
|
|||
|
|
@ -327,9 +327,11 @@ static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, u32 feature,
|
|||
if (conf->flags & SBI_FWFT_SET_FLAG_LOCK)
|
||||
return SBI_ERR_DENIED_LOCKED;
|
||||
|
||||
conf->flags = flags;
|
||||
ret = conf->feature->set(vcpu, conf, false, value);
|
||||
if (ret == SBI_SUCCESS)
|
||||
conf->flags = flags;
|
||||
|
||||
return conf->feature->set(vcpu, conf, false, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/kvm_isa.h>
|
||||
|
|
@ -129,11 +130,20 @@ static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu,
|
|||
return -ENOENT;
|
||||
}
|
||||
} else if (reg_num <= KVM_REG_RISCV_VECTOR_REG(31)) {
|
||||
unsigned long reg_offset;
|
||||
|
||||
if (reg_size != vlenb)
|
||||
return -EINVAL;
|
||||
WARN_ON(!cntx->vector.datap);
|
||||
*reg_addr = cntx->vector.datap +
|
||||
(reg_num - KVM_REG_RISCV_VECTOR_REG(0)) * vlenb;
|
||||
/*
|
||||
* The reg_num is derived from the userspace-provided ONE_REG
|
||||
* id. Sanitize it with array_index_nospec() to prevent
|
||||
* speculative out-of-bounds access to the vector register
|
||||
* buffer (32 vector registers: v0..v31).
|
||||
*/
|
||||
reg_offset = array_index_nospec(
|
||||
reg_num - KVM_REG_RISCV_VECTOR_REG(0), 32);
|
||||
*reg_addr = cntx->vector.datap + reg_offset * vlenb;
|
||||
} else {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user