Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull KVM fixes from Radim Krčmář:
"KVM:
- lock kvm_device list to prevent corruption on device creation.
PPC:
- split debugfs initialization from creation of the xics device to
unlock the newly taken kvm lock earlier.
s390:
- prevent userspace from triggering two WARN_ON_ONCE.
MIPS:
- fix several issues in the management of TLB faults (Cc: stable)"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
MIPS: KVM: Propagate kseg0/mapped tlb fault errors
MIPS: KVM: Fix gfn range check in kseg0 tlb faults
MIPS: KVM: Add missing gfn range check
MIPS: KVM: Fix mapped fault broken commpage handling
KVM: Protect device ops->create and list_add with kvm->lock
KVM: PPC: Move xics_debugfs_init out of create
KVM: s390: reset KVM_REQ_MMU_RELOAD if mapping the prefix failed
KVM: s390: set the prefix initially properly
This commit is contained in:
@@ -1009,9 +1009,13 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
||||
|
||||
switch (ioctl) {
|
||||
case KVM_CREATE_IRQCHIP: {
|
||||
int ret;
|
||||
if (!vgic_present)
|
||||
return -ENXIO;
|
||||
return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
|
||||
mutex_lock(&kvm->lock);
|
||||
ret = kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
|
||||
mutex_unlock(&kvm->lock);
|
||||
return ret;
|
||||
}
|
||||
case KVM_ARM_SET_DEVICE_ADDR: {
|
||||
struct kvm_arm_device_addr dev_addr;
|
||||
|
||||
@@ -1642,8 +1642,14 @@ enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst,
|
||||
|
||||
preempt_disable();
|
||||
if (KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG0) {
|
||||
if (kvm_mips_host_tlb_lookup(vcpu, va) < 0)
|
||||
kvm_mips_handle_kseg0_tlb_fault(va, vcpu);
|
||||
if (kvm_mips_host_tlb_lookup(vcpu, va) < 0 &&
|
||||
kvm_mips_handle_kseg0_tlb_fault(va, vcpu)) {
|
||||
kvm_err("%s: handling mapped kseg0 tlb fault for %lx, vcpu: %p, ASID: %#lx\n",
|
||||
__func__, va, vcpu, read_c0_entryhi());
|
||||
er = EMULATE_FAIL;
|
||||
preempt_enable();
|
||||
goto done;
|
||||
}
|
||||
} else if ((KVM_GUEST_KSEGX(va) < KVM_GUEST_KSEG0) ||
|
||||
KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG23) {
|
||||
int index;
|
||||
@@ -1680,12 +1686,18 @@ enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst,
|
||||
run, vcpu);
|
||||
preempt_enable();
|
||||
goto dont_update_pc;
|
||||
} else {
|
||||
/*
|
||||
* We fault an entry from the guest tlb to the
|
||||
* shadow host TLB
|
||||
*/
|
||||
kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb);
|
||||
}
|
||||
/*
|
||||
* We fault an entry from the guest tlb to the
|
||||
* shadow host TLB
|
||||
*/
|
||||
if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb)) {
|
||||
kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n",
|
||||
__func__, va, index, vcpu,
|
||||
read_c0_entryhi());
|
||||
er = EMULATE_FAIL;
|
||||
preempt_enable();
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2659,7 +2671,12 @@ enum emulation_result kvm_mips_handle_tlbmiss(u32 cause,
|
||||
* OK we have a Guest TLB entry, now inject it into the
|
||||
* shadow host TLB
|
||||
*/
|
||||
kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb);
|
||||
if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb)) {
|
||||
kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n",
|
||||
__func__, va, index, vcpu,
|
||||
read_c0_entryhi());
|
||||
er = EMULATE_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
|
||||
}
|
||||
|
||||
gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT);
|
||||
if (gfn >= kvm->arch.guest_pmap_npages) {
|
||||
if ((gfn | 1) >= kvm->arch.guest_pmap_npages) {
|
||||
kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__,
|
||||
gfn, badvaddr);
|
||||
kvm_mips_dump_host_tlbs();
|
||||
@@ -138,35 +138,49 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
|
||||
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
kvm_pfn_t pfn0, pfn1;
|
||||
gfn_t gfn0, gfn1;
|
||||
long tlb_lo[2];
|
||||
int ret;
|
||||
|
||||
if ((tlb->tlb_hi & VPN2_MASK) == 0) {
|
||||
pfn0 = 0;
|
||||
pfn1 = 0;
|
||||
} else {
|
||||
if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[0])
|
||||
>> PAGE_SHIFT) < 0)
|
||||
return -1;
|
||||
tlb_lo[0] = tlb->tlb_lo[0];
|
||||
tlb_lo[1] = tlb->tlb_lo[1];
|
||||
|
||||
if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[1])
|
||||
>> PAGE_SHIFT) < 0)
|
||||
return -1;
|
||||
/*
|
||||
* The commpage address must not be mapped to anything else if the guest
|
||||
* TLB contains entries nearby, or commpage accesses will break.
|
||||
*/
|
||||
if (!((tlb->tlb_hi ^ KVM_GUEST_COMMPAGE_ADDR) &
|
||||
VPN2_MASK & (PAGE_MASK << 1)))
|
||||
tlb_lo[(KVM_GUEST_COMMPAGE_ADDR >> PAGE_SHIFT) & 1] = 0;
|
||||
|
||||
pfn0 = kvm->arch.guest_pmap[
|
||||
mips3_tlbpfn_to_paddr(tlb->tlb_lo[0]) >> PAGE_SHIFT];
|
||||
pfn1 = kvm->arch.guest_pmap[
|
||||
mips3_tlbpfn_to_paddr(tlb->tlb_lo[1]) >> PAGE_SHIFT];
|
||||
gfn0 = mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT;
|
||||
gfn1 = mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT;
|
||||
if (gfn0 >= kvm->arch.guest_pmap_npages ||
|
||||
gfn1 >= kvm->arch.guest_pmap_npages) {
|
||||
kvm_err("%s: Invalid gfn: [%#llx, %#llx], EHi: %#lx\n",
|
||||
__func__, gfn0, gfn1, tlb->tlb_hi);
|
||||
kvm_mips_dump_guest_tlbs(vcpu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (kvm_mips_map_page(kvm, gfn0) < 0)
|
||||
return -1;
|
||||
|
||||
if (kvm_mips_map_page(kvm, gfn1) < 0)
|
||||
return -1;
|
||||
|
||||
pfn0 = kvm->arch.guest_pmap[gfn0];
|
||||
pfn1 = kvm->arch.guest_pmap[gfn1];
|
||||
|
||||
/* Get attributes from the Guest TLB */
|
||||
entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) |
|
||||
((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
|
||||
(tlb->tlb_lo[0] & ENTRYLO_D) |
|
||||
(tlb->tlb_lo[0] & ENTRYLO_V);
|
||||
(tlb_lo[0] & ENTRYLO_D) |
|
||||
(tlb_lo[0] & ENTRYLO_V);
|
||||
entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) |
|
||||
((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
|
||||
(tlb->tlb_lo[1] & ENTRYLO_D) |
|
||||
(tlb->tlb_lo[1] & ENTRYLO_V);
|
||||
(tlb_lo[1] & ENTRYLO_D) |
|
||||
(tlb_lo[1] & ENTRYLO_V);
|
||||
|
||||
kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc,
|
||||
tlb->tlb_lo[0], tlb->tlb_lo[1]);
|
||||
@@ -354,9 +368,15 @@ u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu)
|
||||
local_irq_restore(flags);
|
||||
return KVM_INVALID_INST;
|
||||
}
|
||||
kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
|
||||
&vcpu->arch.
|
||||
guest_tlb[index]);
|
||||
if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
|
||||
&vcpu->arch.guest_tlb[index])) {
|
||||
kvm_err("%s: handling mapped seg tlb fault failed for %p, index: %u, vcpu: %p, ASID: %#lx\n",
|
||||
__func__, opc, index, vcpu,
|
||||
read_c0_entryhi());
|
||||
kvm_mips_dump_guest_tlbs(vcpu);
|
||||
local_irq_restore(flags);
|
||||
return KVM_INVALID_INST;
|
||||
}
|
||||
inst = *(opc);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
@@ -1329,20 +1329,16 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type)
|
||||
xics->kvm = kvm;
|
||||
|
||||
/* Already there ? */
|
||||
mutex_lock(&kvm->lock);
|
||||
if (kvm->arch.xics)
|
||||
ret = -EEXIST;
|
||||
else
|
||||
kvm->arch.xics = xics;
|
||||
mutex_unlock(&kvm->lock);
|
||||
|
||||
if (ret) {
|
||||
kfree(xics);
|
||||
return ret;
|
||||
}
|
||||
|
||||
xics_debugfs_init(xics);
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_206)) {
|
||||
/* Enable real mode support */
|
||||
@@ -1354,9 +1350,17 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvmppc_xics_init(struct kvm_device *dev)
|
||||
{
|
||||
struct kvmppc_xics *xics = (struct kvmppc_xics *)dev->private;
|
||||
|
||||
xics_debugfs_init(xics);
|
||||
}
|
||||
|
||||
struct kvm_device_ops kvm_xics_ops = {
|
||||
.name = "kvm-xics",
|
||||
.create = kvmppc_xics_create,
|
||||
.init = kvmppc_xics_init,
|
||||
.destroy = kvmppc_xics_free,
|
||||
.set_attr = xics_set_attr,
|
||||
.get_attr = xics_get_attr,
|
||||
|
||||
@@ -1672,6 +1672,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
KVM_SYNC_CRS |
|
||||
KVM_SYNC_ARCH0 |
|
||||
KVM_SYNC_PFAULT;
|
||||
kvm_s390_set_prefix(vcpu, 0);
|
||||
if (test_kvm_facility(vcpu->kvm, 64))
|
||||
vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
|
||||
/* fprs can be synchronized via vrs, even if the guest has no vx. With
|
||||
@@ -2361,8 +2362,10 @@ retry:
|
||||
rc = gmap_mprotect_notify(vcpu->arch.gmap,
|
||||
kvm_s390_get_prefix(vcpu),
|
||||
PAGE_SIZE * 2, PROT_WRITE);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
|
||||
return rc;
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
||||
@@ -1113,8 +1113,20 @@ struct kvm_device {
|
||||
/* create, destroy, and name are mandatory */
|
||||
struct kvm_device_ops {
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* create is called holding kvm->lock and any operations not suitable
|
||||
* to do while holding the lock should be deferred to init (see
|
||||
* below).
|
||||
*/
|
||||
int (*create)(struct kvm_device *dev, u32 type);
|
||||
|
||||
/*
|
||||
* init is called after create if create is successful and is called
|
||||
* outside of holding kvm->lock.
|
||||
*/
|
||||
void (*init)(struct kvm_device *dev);
|
||||
|
||||
/*
|
||||
* Destroy is responsible for freeing dev.
|
||||
*
|
||||
|
||||
@@ -73,12 +73,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
|
||||
int i, vcpu_lock_idx = -1, ret;
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
|
||||
if (irqchip_in_kernel(kvm)) {
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
if (irqchip_in_kernel(kvm))
|
||||
return -EEXIST;
|
||||
|
||||
/*
|
||||
* This function is also called by the KVM_CREATE_IRQCHIP handler,
|
||||
@@ -87,10 +83,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
|
||||
* the proper checks already.
|
||||
*/
|
||||
if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
|
||||
!kvm_vgic_global_state.can_emulate_gicv2) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
!kvm_vgic_global_state.can_emulate_gicv2)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Any time a vcpu is run, vcpu_load is called which tries to grab the
|
||||
@@ -138,9 +132,6 @@ out_unlock:
|
||||
vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
|
||||
mutex_unlock(&vcpu->mutex);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&kvm->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -696,6 +696,11 @@ static void kvm_destroy_devices(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_device *dev, *tmp;
|
||||
|
||||
/*
|
||||
* We do not need to take the kvm->lock here, because nobody else
|
||||
* has a reference to the struct kvm at this point and therefore
|
||||
* cannot access the devices list anyhow.
|
||||
*/
|
||||
list_for_each_entry_safe(dev, tmp, &kvm->devices, vm_node) {
|
||||
list_del(&dev->vm_node);
|
||||
dev->ops->destroy(dev);
|
||||
@@ -2832,19 +2837,28 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
|
||||
dev->ops = ops;
|
||||
dev->kvm = kvm;
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
ret = ops->create(dev, cd->type);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&kvm->lock);
|
||||
kfree(dev);
|
||||
return ret;
|
||||
}
|
||||
list_add(&dev->vm_node, &kvm->devices);
|
||||
mutex_unlock(&kvm->lock);
|
||||
|
||||
if (ops->init)
|
||||
ops->init(dev);
|
||||
|
||||
ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);
|
||||
if (ret < 0) {
|
||||
ops->destroy(dev);
|
||||
mutex_lock(&kvm->lock);
|
||||
list_del(&dev->vm_node);
|
||||
mutex_unlock(&kvm->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_add(&dev->vm_node, &kvm->devices);
|
||||
kvm_get_kvm(kvm);
|
||||
cd->fd = ret;
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user