diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2026-06-15 15:38:02 +0200 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2026-06-15 15:38:02 +0200 |
| commit | 677d68682ebb30e9366f3b387fc16b19844bb19e (patch) | |
| tree | ac8ad9c4be2268d21b4d08bc93a7a8ac3f698569 | |
| parent | 4dffb0a5d1c29163cd4ab8f1a259a7278c94716a (diff) | |
| parent | aeded601d6aceb57cdda4b2701d2ee00c43a8b69 (diff) | |
Merge tag 'loongarch-kvm-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson into HEAD
LoongArch KVM changes for v7.2
1. Enable FPU with max VM supported FPU type.
2. Some enhancements about interrupt injection.
3. Some bug fixes and other small changes.
| -rw-r--r-- | arch/loongarch/include/asm/kvm_host.h | 14 | ||||
| -rw-r--r-- | arch/loongarch/include/asm/kvm_vcpu.h | 43 | ||||
| -rw-r--r-- | arch/loongarch/kvm/exit.c | 22 | ||||
| -rw-r--r-- | arch/loongarch/kvm/intc/eiointc.c | 6 | ||||
| -rw-r--r-- | arch/loongarch/kvm/intc/ipi.c | 2 | ||||
| -rw-r--r-- | arch/loongarch/kvm/intc/pch_pic.c | 2 | ||||
| -rw-r--r-- | arch/loongarch/kvm/interrupt.c | 98 | ||||
| -rw-r--r-- | arch/loongarch/kvm/irqfd.c | 3 | ||||
| -rw-r--r-- | arch/loongarch/kvm/timer.c | 3 | ||||
| -rw-r--r-- | arch/loongarch/kvm/vcpu.c | 118 |
10 files changed, 131 insertions, 180 deletions
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h index 776bc487a705..23cfbecebbd7 100644 --- a/arch/loongarch/include/asm/kvm_host.h +++ b/arch/loongarch/include/asm/kvm_host.h @@ -38,7 +38,8 @@ #define KVM_REQ_TLB_FLUSH_GPA KVM_ARCH_REQ(0) #define KVM_REQ_STEAL_UPDATE KVM_ARCH_REQ(1) #define KVM_REQ_PMU KVM_ARCH_REQ(2) -#define KVM_REQ_AUX_LOAD KVM_ARCH_REQ(3) +#define KVM_REQ_FPU_LOAD KVM_ARCH_REQ(3) +#define KVM_REQ_LBT_LOAD KVM_ARCH_REQ(4) #define KVM_GUESTDBG_SW_BP_MASK \ (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) @@ -157,12 +158,10 @@ enum emulation_result { }; #define KVM_LARCH_FPU (0x1 << 0) -#define KVM_LARCH_LSX (0x1 << 1) -#define KVM_LARCH_LASX (0x1 << 2) -#define KVM_LARCH_LBT (0x1 << 3) -#define KVM_LARCH_PMU (0x1 << 4) -#define KVM_LARCH_SWCSR_LATEST (0x1 << 5) -#define KVM_LARCH_HWCSR_USABLE (0x1 << 6) +#define KVM_LARCH_LBT (0x1 << 1) +#define KVM_LARCH_PMU (0x1 << 2) +#define KVM_LARCH_SWCSR_LATEST (0x1 << 3) +#define KVM_LARCH_HWCSR_USABLE (0x1 << 4) #define LOONGARCH_PV_FEAT_UPDATED BIT_ULL(63) #define LOONGARCH_PV_FEAT_MASK (BIT(KVM_FEATURE_IPI) | \ @@ -203,7 +202,6 @@ struct kvm_vcpu_arch { /* Which auxiliary state is loaded (KVM_LARCH_*) */ unsigned int aux_inuse; - unsigned int aux_ldtype; /* FPU state */ struct loongarch_fpu fpu FPU_ALIGN; diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h index 3784ab4ccdb5..a70a32103523 100644 --- a/arch/loongarch/include/asm/kvm_vcpu.h +++ b/arch/loongarch/include/asm/kvm_vcpu.h @@ -10,22 +10,37 @@ #include <asm/loongarch.h> /* Controlled by 0x5 guest estat */ -#define CPU_SIP0 (_ULCAST_(1)) -#define CPU_SIP1 (_ULCAST_(1) << 1) -#define CPU_PMU (_ULCAST_(1) << 10) -#define CPU_TIMER (_ULCAST_(1) << 11) -#define CPU_IPI (_ULCAST_(1) << 12) -#define CPU_AVEC (_ULCAST_(1) << 14) +#define CPU_SIP0 BIT(INT_SWI0) +#define CPU_SIP1 BIT(INT_SWI1) +#define CPU_HWI0 BIT(INT_HWI0) +#define CPU_HWI1 BIT(INT_HWI1) +#define CPU_HWI2 BIT(INT_HWI2) +#define CPU_HWI3 BIT(INT_HWI3) +#define CPU_HWI4 BIT(INT_HWI4) +#define CPU_HWI5 BIT(INT_HWI5) +#define CPU_HWI6 BIT(INT_HWI6) +#define CPU_HWI7 BIT(INT_HWI7) +#define CPU_PMU BIT(INT_PCOV) +#define CPU_TIMER BIT(INT_TI) +#define CPU_IPI BIT(INT_IPI) +#define CPU_AVEC BIT(INT_AVEC) +#define KVM_ESTAT_INTI_MASK (CPU_SIP0 | CPU_SIP1 | CPU_PMU | CPU_TIMER \ + | CPU_IPI | CPU_AVEC) +#define KVM_ESTAT_EXTI_MASK (CPU_HWI0 | CPU_HWI1 | CPU_HWI2 | CPU_HWI3 \ + | CPU_HWI4 | CPU_HWI5 | CPU_HWI6 | CPU_HWI7) /* Controlled by 0x52 guest exception VIP aligned to estat bit 5~12 */ -#define CPU_IP0 (_ULCAST_(1)) -#define CPU_IP1 (_ULCAST_(1) << 1) -#define CPU_IP2 (_ULCAST_(1) << 2) -#define CPU_IP3 (_ULCAST_(1) << 3) -#define CPU_IP4 (_ULCAST_(1) << 4) -#define CPU_IP5 (_ULCAST_(1) << 5) -#define CPU_IP6 (_ULCAST_(1) << 6) -#define CPU_IP7 (_ULCAST_(1) << 7) +#define VIP_DELTA (INT_HWI0 - CSR_GINTC_VIP_SHIFT) +#define CPU_IP0 BIT(INT_HWI0 - VIP_DELTA) +#define CPU_IP1 BIT(INT_HWI1 - VIP_DELTA) +#define CPU_IP2 BIT(INT_HWI2 - VIP_DELTA) +#define CPU_IP3 BIT(INT_HWI3 - VIP_DELTA) +#define CPU_IP4 BIT(INT_HWI4 - VIP_DELTA) +#define CPU_IP5 BIT(INT_HWI5 - VIP_DELTA) +#define CPU_IP6 BIT(INT_HWI6 - VIP_DELTA) +#define CPU_IP7 BIT(INT_HWI7 - VIP_DELTA) +#define KVM_GINTC_IRQ_MASK (CPU_IP0 | CPU_IP1 | CPU_IP2 | CPU_IP3 \ + | CPU_IP4 | CPU_IP5 | CPU_IP6 | CPU_IP7) #define MNSEC_PER_SEC (NSEC_PER_SEC >> 20) diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c index 3b95cd0f989b..8572b63478bb 100644 --- a/arch/loongarch/kvm/exit.c +++ b/arch/loongarch/kvm/exit.c @@ -103,7 +103,6 @@ static unsigned long kvm_emu_xchg_csr(struct kvm_vcpu *vcpu, int csrid, old = kvm_read_sw_gcsr(csr, csrid); val = (old & ~csr_mask) | (val & csr_mask); kvm_write_sw_gcsr(csr, csrid, val); - old = old & csr_mask; } else pr_warn_once("Unsupported csrxchg 0x%x with pc %lx\n", csrid, vcpu->arch.pc); @@ -755,8 +754,7 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu, int ecode) return RESUME_HOST; } - vcpu->arch.aux_ldtype = KVM_LARCH_FPU; - kvm_make_request(KVM_REQ_AUX_LOAD, vcpu); + kvm_make_request(KVM_REQ_FPU_LOAD, vcpu); return RESUME_GUEST; } @@ -796,10 +794,8 @@ static int kvm_handle_lsx_disabled(struct kvm_vcpu *vcpu, int ecode) { if (!kvm_guest_has_lsx(&vcpu->arch)) kvm_queue_exception(vcpu, EXCCODE_INE, 0); - else { - vcpu->arch.aux_ldtype = KVM_LARCH_LSX; - kvm_make_request(KVM_REQ_AUX_LOAD, vcpu); - } + else + kvm_make_request(KVM_REQ_FPU_LOAD, vcpu); return RESUME_GUEST; } @@ -816,10 +812,8 @@ static int kvm_handle_lasx_disabled(struct kvm_vcpu *vcpu, int ecode) { if (!kvm_guest_has_lasx(&vcpu->arch)) kvm_queue_exception(vcpu, EXCCODE_INE, 0); - else { - vcpu->arch.aux_ldtype = KVM_LARCH_LASX; - kvm_make_request(KVM_REQ_AUX_LOAD, vcpu); - } + else + kvm_make_request(KVM_REQ_FPU_LOAD, vcpu); return RESUME_GUEST; } @@ -828,10 +822,8 @@ static int kvm_handle_lbt_disabled(struct kvm_vcpu *vcpu, int ecode) { if (!kvm_guest_has_lbt(&vcpu->arch)) kvm_queue_exception(vcpu, EXCCODE_INE, 0); - else { - vcpu->arch.aux_ldtype = KVM_LARCH_LBT; - kvm_make_request(KVM_REQ_AUX_LOAD, vcpu); - } + else + kvm_make_request(KVM_REQ_LBT_LOAD, vcpu); return RESUME_GUEST; } diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c index 2ab7fafa86d5..2b14485d14a7 100644 --- a/arch/loongarch/kvm/intc/eiointc.c +++ b/arch/loongarch/kvm/intc/eiointc.c @@ -645,10 +645,14 @@ static int kvm_eiointc_create(struct kvm_device *dev, u32 type) device = &s->device_vext; kvm_iodevice_init(device, &kvm_eiointc_virt_ops); + mutex_lock(&kvm->slots_lock); ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, device); + mutex_unlock(&kvm->slots_lock); if (ret < 0) { + mutex_lock(&kvm->slots_lock); kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device); + mutex_unlock(&kvm->slots_lock); kfree(s); return ret; } @@ -667,8 +671,10 @@ static void kvm_eiointc_destroy(struct kvm_device *dev) kvm = dev->kvm; eiointc = kvm->arch.eiointc; + mutex_lock(&kvm->slots_lock); kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device); kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext); + mutex_unlock(&kvm->slots_lock); kfree(eiointc); kfree(dev); } diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index 1f6ebbd0af5c..4fa0897d7bdb 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -447,7 +447,9 @@ static void kvm_ipi_destroy(struct kvm_device *dev) kvm = dev->kvm; ipi = kvm->arch.ipi; + mutex_lock(&kvm->slots_lock); kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device); + mutex_unlock(&kvm->slots_lock); kfree(ipi); kfree(dev); } diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index aa0ed59ae8cf..175a630aceb4 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -481,7 +481,9 @@ static void kvm_pch_pic_destroy(struct kvm_device *dev) kvm = dev->kvm; s = kvm->arch.pch_pic; /* unregister pch pic device and free it's memory */ + mutex_lock(&kvm->slots_lock); kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &s->device); + mutex_unlock(&kvm->slots_lock); kfree(s); kfree(dev); } diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c index a18c60dffbba..055ac9235b03 100644 --- a/arch/loongarch/kvm/interrupt.c +++ b/arch/loongarch/kvm/interrupt.c @@ -9,41 +9,16 @@ #include <asm/kvm_vcpu.h> #include <asm/kvm_dmsintc.h> -static unsigned int priority_to_irq[EXCCODE_INT_NUM] = { - [INT_TI] = CPU_TIMER, - [INT_IPI] = CPU_IPI, - [INT_SWI0] = CPU_SIP0, - [INT_SWI1] = CPU_SIP1, - [INT_HWI0] = CPU_IP0, - [INT_HWI1] = CPU_IP1, - [INT_HWI2] = CPU_IP2, - [INT_HWI3] = CPU_IP3, - [INT_HWI4] = CPU_IP4, - [INT_HWI5] = CPU_IP5, - [INT_HWI6] = CPU_IP6, - [INT_HWI7] = CPU_IP7, - [INT_AVEC] = CPU_AVEC, -}; - -static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority) +static void kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned long mask) { - unsigned int irq = 0; + unsigned long irq; unsigned long old, new; - clear_bit(priority, &vcpu->arch.irq_pending); - if (priority < EXCCODE_INT_NUM) - irq = priority_to_irq[priority]; - - switch (priority) { - case INT_AVEC: - if (!kvm_guest_has_msgint(&vcpu->arch)) - break; + if (mask & CPU_AVEC) dmsintc_inject_irq(vcpu); - fallthrough; - case INT_TI: - case INT_IPI: - case INT_SWI0: - case INT_SWI1: + + irq = mask & KVM_ESTAT_INTI_MASK; + if (irq) { old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL); set_gcsr_estat(irq); new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL); @@ -51,37 +26,20 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority) /* Inject TI if TVAL inverted */ if (new > old) set_gcsr_estat(CPU_TIMER); - break; - - case INT_HWI0 ... INT_HWI7: - set_csr_gintc(irq); - break; - - default: - break; } - return 1; + irq = (mask >> VIP_DELTA) & KVM_GINTC_IRQ_MASK; + if (irq) + set_csr_gintc(irq); } -static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority) +static void kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned long mask) { - unsigned int irq = 0; + unsigned long irq; unsigned long old, new; - clear_bit(priority, &vcpu->arch.irq_clear); - if (priority < EXCCODE_INT_NUM) - irq = priority_to_irq[priority]; - - switch (priority) { - case INT_AVEC: - if (!kvm_guest_has_msgint(&vcpu->arch)) - break; - fallthrough; - case INT_TI: - case INT_IPI: - case INT_SWI0: - case INT_SWI1: + irq = mask & KVM_ESTAT_INTI_MASK; + if (irq) { old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL); clear_gcsr_estat(irq); new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL); @@ -89,30 +47,28 @@ static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority) /* Inject TI if TVAL inverted */ if (new > old) set_gcsr_estat(CPU_TIMER); - break; - - case INT_HWI0 ... INT_HWI7: - clear_csr_gintc(irq); - break; - - default: - break; } - return 1; + irq = (mask >> VIP_DELTA) & KVM_GINTC_IRQ_MASK; + if (irq) + clear_csr_gintc(irq); } void kvm_deliver_intr(struct kvm_vcpu *vcpu) { - unsigned int priority; - unsigned long *pending = &vcpu->arch.irq_pending; - unsigned long *pending_clr = &vcpu->arch.irq_clear; + unsigned long mask; - for_each_set_bit(priority, pending_clr, EXCCODE_INT_NUM) - kvm_irq_clear(vcpu, priority); + mask = READ_ONCE(vcpu->arch.irq_clear); + if (mask) { + mask = xchg_relaxed(&vcpu->arch.irq_clear, 0); + kvm_irq_clear(vcpu, mask); + } - for_each_set_bit(priority, pending, EXCCODE_INT_NUM) - kvm_irq_deliver(vcpu, priority); + mask = READ_ONCE(vcpu->arch.irq_pending); + if (mask) { + mask = xchg_relaxed(&vcpu->arch.irq_pending, 0); + kvm_irq_deliver(vcpu, mask); + } } int kvm_pending_timer(struct kvm_vcpu *vcpu) diff --git a/arch/loongarch/kvm/irqfd.c b/arch/loongarch/kvm/irqfd.c index f4f953b22419..40ed1081c4b6 100644 --- a/arch/loongarch/kvm/irqfd.c +++ b/arch/loongarch/kvm/irqfd.c @@ -51,7 +51,8 @@ int kvm_set_routing_entry(struct kvm *kvm, e->irqchip.irqchip = ue->u.irqchip.irqchip; e->irqchip.pin = ue->u.irqchip.pin; - if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) + if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS || + e->irqchip.irqchip >= KVM_NR_IRQCHIPS) return -EINVAL; return 0; diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c index 8356fce0043f..3829f35a4070 100644 --- a/arch/loongarch/kvm/timer.c +++ b/arch/loongarch/kvm/timer.c @@ -30,8 +30,7 @@ enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer) struct kvm_vcpu *vcpu; vcpu = container_of(timer, struct kvm_vcpu, arch.swtimer); - kvm_queue_irq(vcpu, INT_TI); - rcuwait_wake_up(&vcpu->wait); + kvm_vcpu_wake_up(vcpu); return HRTIMER_NORESTART; } diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index e28084c49e68..20c207d80e31 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -239,26 +239,17 @@ static void kvm_late_check_requests(struct kvm_vcpu *vcpu) vcpu->arch.flush_gpa = INVALID_GPA; } - if (kvm_check_request(KVM_REQ_AUX_LOAD, vcpu)) { - switch (vcpu->arch.aux_ldtype) { - case KVM_LARCH_FPU: - kvm_own_fpu(vcpu); - break; - case KVM_LARCH_LSX: - kvm_own_lsx(vcpu); - break; - case KVM_LARCH_LASX: + if (kvm_check_request(KVM_REQ_FPU_LOAD, vcpu)) { + if (kvm_guest_has_lasx(&vcpu->arch)) kvm_own_lasx(vcpu); - break; - case KVM_LARCH_LBT: - kvm_own_lbt(vcpu); - break; - default: - break; - } - - vcpu->arch.aux_ldtype = 0; + else if (kvm_guest_has_lsx(&vcpu->arch)) + kvm_own_lsx(vcpu); + else if (kvm_guest_has_fpu(&vcpu->arch)) + kvm_own_fpu(vcpu); } + + if (kvm_check_request(KVM_REQ_LBT_LOAD, vcpu)) + kvm_own_lbt(vcpu); } /* @@ -308,10 +299,10 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu) * check vmid before vcpu enter guest */ local_irq_disable(); - kvm_deliver_intr(vcpu); kvm_deliver_exception(vcpu); /* Make sure the vcpu mode has been written */ smp_store_mb(vcpu->mode, IN_GUEST_MODE); + kvm_deliver_intr(vcpu); kvm_check_vpid(vcpu); /* @@ -348,7 +339,7 @@ static int kvm_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu) u32 intr = estat & CSR_ESTAT_IS; u32 ecode = (estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT; - vcpu->mode = OUTSIDE_GUEST_MODE; + smp_store_mb(vcpu->mode, OUTSIDE_GUEST_MODE); /* Set a default exit reason */ run->exit_reason = KVM_EXIT_UNKNOWN; @@ -602,7 +593,7 @@ struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid) static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val) { - unsigned long gintc; + unsigned long estat, gintc; struct loongarch_csrs *csr = vcpu->arch.csr; if (get_gcsr_flag(id) & INVALID_GCSR) @@ -621,8 +612,9 @@ static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val) preempt_enable(); /* ESTAT IP0~IP7 get from GINTC */ - gintc = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & 0xff; - *val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT) | (gintc << 2); + gintc = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & KVM_GINTC_IRQ_MASK; + estat = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT) & ~KVM_ESTAT_EXTI_MASK; + *val = estat | (gintc << VIP_DELTA); return 0; } @@ -637,7 +629,8 @@ static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val) static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val) { - int ret = 0, gintc; + int ret = 0; + unsigned long estat, gintc; struct loongarch_csrs *csr = vcpu->arch.csr; if (get_gcsr_flag(id) & INVALID_GCSR) @@ -648,11 +641,16 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val) if (id == LOONGARCH_CSR_ESTAT) { /* ESTAT IP0~IP7 inject through GINTC */ - gintc = (val >> 2) & 0xff; - kvm_set_sw_gcsr(csr, LOONGARCH_CSR_GINTC, gintc); + gintc = (val >> VIP_DELTA) & KVM_GINTC_IRQ_MASK; + gintc |= kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & ~KVM_GINTC_IRQ_MASK; + kvm_write_sw_gcsr(csr, LOONGARCH_CSR_GINTC, gintc); - gintc = val & ~(0xffUL << 2); - kvm_set_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, gintc); + /* Only set valid ESTAT bits */ + estat = val & ~KVM_ESTAT_EXTI_MASK; + estat &= CSR_ESTAT_IS | CSR_ESTAT_EXC | CSR_ESTAT_ESUBCODE; + if (!kvm_guest_has_msgint(&vcpu->arch)) + estat &= ~CPU_AVEC; + kvm_write_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, estat); return ret; } @@ -1108,7 +1106,8 @@ static int kvm_loongarch_cpucfg_get_attr(struct kvm_vcpu *vcpu, return -ENXIO; } - put_user(val, uaddr); + if (put_user(val, uaddr)) + return -EFAULT; return ret; } @@ -1312,7 +1311,7 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) fpu->fcc = vcpu->arch.fpu.fcc; fpu->fcsr = vcpu->arch.fpu.fcsr; for (i = 0; i < NUM_FPU_REGS; i++) - memcpy(&fpu->fpr[i], &vcpu->arch.fpu.fpr[i], FPU_REG_WIDTH / 64); + memcpy(&fpu->fpr[i], &vcpu->arch.fpu.fpr[i], sizeof(union fpureg)); return 0; } @@ -1324,7 +1323,7 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) vcpu->arch.fpu.fcc = fpu->fcc; vcpu->arch.fpu.fcsr = fpu->fcsr; for (i = 0; i < NUM_FPU_REGS; i++) - memcpy(&vcpu->arch.fpu.fpr[i], &fpu->fpr[i], FPU_REG_WIDTH / 64); + memcpy(&vcpu->arch.fpu.fpr[i], &fpu->fpr[i], sizeof(union fpureg)); return 0; } @@ -1398,24 +1397,10 @@ int kvm_own_lsx(struct kvm_vcpu *vcpu) /* Enable LSX for guest */ kvm_check_fcsr(vcpu, vcpu->arch.fpu.fcsr); set_csr_euen(CSR_EUEN_LSXEN | CSR_EUEN_FPEN); - switch (vcpu->arch.aux_inuse & KVM_LARCH_FPU) { - case KVM_LARCH_FPU: - /* - * Guest FPU state already loaded, - * only restore upper LSX state - */ - _restore_lsx_upper(&vcpu->arch.fpu); - break; - default: - /* Neither FP or LSX already active, - * restore full LSX state - */ - kvm_restore_lsx(&vcpu->arch.fpu); - break; - } + kvm_restore_lsx(&vcpu->arch.fpu); + vcpu->arch.aux_inuse |= KVM_LARCH_FPU; trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LSX); - vcpu->arch.aux_inuse |= KVM_LARCH_LSX | KVM_LARCH_FPU; return 0; } @@ -1427,25 +1412,10 @@ int kvm_own_lasx(struct kvm_vcpu *vcpu) { kvm_check_fcsr(vcpu, vcpu->arch.fpu.fcsr); set_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN); - switch (vcpu->arch.aux_inuse & (KVM_LARCH_FPU | KVM_LARCH_LSX)) { - case KVM_LARCH_LSX: - case KVM_LARCH_LSX | KVM_LARCH_FPU: - /* Guest LSX state already loaded, only restore upper LASX state */ - _restore_lasx_upper(&vcpu->arch.fpu); - break; - case KVM_LARCH_FPU: - /* Guest FP state already loaded, only restore upper LSX & LASX state */ - _restore_lsx_upper(&vcpu->arch.fpu); - _restore_lasx_upper(&vcpu->arch.fpu); - break; - default: - /* Neither FP or LSX already active, restore full LASX state */ - kvm_restore_lasx(&vcpu->arch.fpu); - break; - } + kvm_restore_lasx(&vcpu->arch.fpu); + vcpu->arch.aux_inuse |= KVM_LARCH_FPU; trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LASX); - vcpu->arch.aux_inuse |= KVM_LARCH_LASX | KVM_LARCH_LSX | KVM_LARCH_FPU; return 0; } @@ -1456,29 +1426,32 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu) { preempt_disable(); + if (!(vcpu->arch.aux_inuse & KVM_LARCH_FPU)) + goto done; + kvm_check_fcsr_alive(vcpu); - if (vcpu->arch.aux_inuse & KVM_LARCH_LASX) { + if (kvm_guest_has_lasx(&vcpu->arch)) { kvm_save_lasx(&vcpu->arch.fpu); - vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU | KVM_LARCH_LASX); trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LASX); /* Disable LASX & LSX & FPU */ clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN); - } else if (vcpu->arch.aux_inuse & KVM_LARCH_LSX) { + } else if (kvm_guest_has_lsx(&vcpu->arch)) { kvm_save_lsx(&vcpu->arch.fpu); - vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU); trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LSX); /* Disable LSX & FPU */ clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN); } else if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) { kvm_save_fpu(&vcpu->arch.fpu); - vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU; trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU); /* Disable FPU */ clear_csr_euen(CSR_EUEN_FPEN); } + vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU; + +done: kvm_lose_lbt(vcpu); preempt_enable(); @@ -1487,6 +1460,13 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu) int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { int intr = (int)irq->irq; + unsigned int vector = abs(intr); + + if (vector >= EXCCODE_INT_NUM) + return -EINVAL; + + if (!kvm_guest_has_msgint(&vcpu->arch) && (vector == INT_AVEC)) + return -EINVAL; if (intr > 0) kvm_queue_irq(vcpu, intr); |
