Commit 329f4152 authored by Linus Torvalds's avatar Linus Torvalds

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
parents a1e21033 89a1d43e
...@@ -1009,9 +1009,13 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -1009,9 +1009,13 @@ long kvm_arch_vm_ioctl(struct file *filp,
switch (ioctl) { switch (ioctl) {
case KVM_CREATE_IRQCHIP: { case KVM_CREATE_IRQCHIP: {
int ret;
if (!vgic_present) if (!vgic_present)
return -ENXIO; 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: { case KVM_ARM_SET_DEVICE_ADDR: {
struct kvm_arm_device_addr dev_addr; struct kvm_arm_device_addr dev_addr;
......
...@@ -1642,8 +1642,14 @@ enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst, ...@@ -1642,8 +1642,14 @@ enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst,
preempt_disable(); preempt_disable();
if (KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG0) { if (KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG0) {
if (kvm_mips_host_tlb_lookup(vcpu, va) < 0) if (kvm_mips_host_tlb_lookup(vcpu, va) < 0 &&
kvm_mips_handle_kseg0_tlb_fault(va, vcpu); 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) || } else if ((KVM_GUEST_KSEGX(va) < KVM_GUEST_KSEG0) ||
KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG23) { KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG23) {
int index; int index;
...@@ -1680,12 +1686,18 @@ enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst, ...@@ -1680,12 +1686,18 @@ enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst,
run, vcpu); run, vcpu);
preempt_enable(); preempt_enable();
goto dont_update_pc; goto dont_update_pc;
} else { }
/* /*
* We fault an entry from the guest tlb to the * We fault an entry from the guest tlb to the
* shadow host TLB * 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;
preempt_enable();
goto done;
} }
} }
} else { } else {
...@@ -2659,7 +2671,12 @@ enum emulation_result kvm_mips_handle_tlbmiss(u32 cause, ...@@ -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 * OK we have a Guest TLB entry, now inject it into the
* shadow host TLB * 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, ...@@ -99,7 +99,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
} }
gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT); 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__, kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__,
gfn, badvaddr); gfn, badvaddr);
kvm_mips_dump_host_tlbs(); kvm_mips_dump_host_tlbs();
...@@ -138,35 +138,49 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu, ...@@ -138,35 +138,49 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0; unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
struct kvm *kvm = vcpu->kvm; struct kvm *kvm = vcpu->kvm;
kvm_pfn_t pfn0, pfn1; kvm_pfn_t pfn0, pfn1;
gfn_t gfn0, gfn1;
long tlb_lo[2];
int ret; int ret;
if ((tlb->tlb_hi & VPN2_MASK) == 0) { tlb_lo[0] = tlb->tlb_lo[0];
pfn0 = 0; tlb_lo[1] = tlb->tlb_lo[1];
pfn1 = 0;
} else { /*
if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[0]) * The commpage address must not be mapped to anything else if the guest
>> PAGE_SHIFT) < 0) * TLB contains entries nearby, or commpage accesses will break.
return -1; */
if (!((tlb->tlb_hi ^ KVM_GUEST_COMMPAGE_ADDR) &
if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[1]) VPN2_MASK & (PAGE_MASK << 1)))
>> PAGE_SHIFT) < 0) tlb_lo[(KVM_GUEST_COMMPAGE_ADDR >> PAGE_SHIFT) & 1] = 0;
return -1;
gfn0 = mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT;
pfn0 = kvm->arch.guest_pmap[ gfn1 = mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT;
mips3_tlbpfn_to_paddr(tlb->tlb_lo[0]) >> PAGE_SHIFT]; if (gfn0 >= kvm->arch.guest_pmap_npages ||
pfn1 = kvm->arch.guest_pmap[ gfn1 >= kvm->arch.guest_pmap_npages) {
mips3_tlbpfn_to_paddr(tlb->tlb_lo[1]) >> PAGE_SHIFT]; 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 */ /* Get attributes from the Guest TLB */
entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) |
((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) | ((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
(tlb->tlb_lo[0] & ENTRYLO_D) | (tlb_lo[0] & ENTRYLO_D) |
(tlb->tlb_lo[0] & ENTRYLO_V); (tlb_lo[0] & ENTRYLO_V);
entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) | entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) |
((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) | ((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
(tlb->tlb_lo[1] & ENTRYLO_D) | (tlb_lo[1] & ENTRYLO_D) |
(tlb->tlb_lo[1] & ENTRYLO_V); (tlb_lo[1] & ENTRYLO_V);
kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc, kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc,
tlb->tlb_lo[0], tlb->tlb_lo[1]); tlb->tlb_lo[0], tlb->tlb_lo[1]);
...@@ -354,9 +368,15 @@ u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu) ...@@ -354,9 +368,15 @@ u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu)
local_irq_restore(flags); local_irq_restore(flags);
return KVM_INVALID_INST; return KVM_INVALID_INST;
} }
kvm_mips_handle_mapped_seg_tlb_fault(vcpu, if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
&vcpu->arch. &vcpu->arch.guest_tlb[index])) {
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); inst = *(opc);
} }
local_irq_restore(flags); local_irq_restore(flags);
......
...@@ -1329,20 +1329,16 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type) ...@@ -1329,20 +1329,16 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type)
xics->kvm = kvm; xics->kvm = kvm;
/* Already there ? */ /* Already there ? */
mutex_lock(&kvm->lock);
if (kvm->arch.xics) if (kvm->arch.xics)
ret = -EEXIST; ret = -EEXIST;
else else
kvm->arch.xics = xics; kvm->arch.xics = xics;
mutex_unlock(&kvm->lock);
if (ret) { if (ret) {
kfree(xics); kfree(xics);
return ret; return ret;
} }
xics_debugfs_init(xics);
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
if (cpu_has_feature(CPU_FTR_ARCH_206)) { if (cpu_has_feature(CPU_FTR_ARCH_206)) {
/* Enable real mode support */ /* Enable real mode support */
...@@ -1354,9 +1350,17 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type) ...@@ -1354,9 +1350,17 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type)
return 0; 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 = { struct kvm_device_ops kvm_xics_ops = {
.name = "kvm-xics", .name = "kvm-xics",
.create = kvmppc_xics_create, .create = kvmppc_xics_create,
.init = kvmppc_xics_init,
.destroy = kvmppc_xics_free, .destroy = kvmppc_xics_free,
.set_attr = xics_set_attr, .set_attr = xics_set_attr,
.get_attr = xics_get_attr, .get_attr = xics_get_attr,
......
...@@ -1672,6 +1672,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) ...@@ -1672,6 +1672,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
KVM_SYNC_CRS | KVM_SYNC_CRS |
KVM_SYNC_ARCH0 | KVM_SYNC_ARCH0 |
KVM_SYNC_PFAULT; KVM_SYNC_PFAULT;
kvm_s390_set_prefix(vcpu, 0);
if (test_kvm_facility(vcpu->kvm, 64)) if (test_kvm_facility(vcpu->kvm, 64))
vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB; vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
/* fprs can be synchronized via vrs, even if the guest has no vx. With /* fprs can be synchronized via vrs, even if the guest has no vx. With
...@@ -2361,8 +2362,10 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) ...@@ -2361,8 +2362,10 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
rc = gmap_mprotect_notify(vcpu->arch.gmap, rc = gmap_mprotect_notify(vcpu->arch.gmap,
kvm_s390_get_prefix(vcpu), kvm_s390_get_prefix(vcpu),
PAGE_SIZE * 2, PROT_WRITE); PAGE_SIZE * 2, PROT_WRITE);
if (rc) if (rc) {
kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
return rc; return rc;
}
goto retry; goto retry;
} }
......
...@@ -1113,8 +1113,20 @@ struct kvm_device { ...@@ -1113,8 +1113,20 @@ struct kvm_device {
/* create, destroy, and name are mandatory */ /* create, destroy, and name are mandatory */
struct kvm_device_ops { struct kvm_device_ops {
const char *name; 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); 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. * Destroy is responsible for freeing dev.
* *
......
...@@ -73,12 +73,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) ...@@ -73,12 +73,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
int i, vcpu_lock_idx = -1, ret; int i, vcpu_lock_idx = -1, ret;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
mutex_lock(&kvm->lock); if (irqchip_in_kernel(kvm))
return -EEXIST;
if (irqchip_in_kernel(kvm)) {
ret = -EEXIST;
goto out;
}
/* /*
* This function is also called by the KVM_CREATE_IRQCHIP handler, * This function is also called by the KVM_CREATE_IRQCHIP handler,
...@@ -87,10 +83,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) ...@@ -87,10 +83,8 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
* the proper checks already. * the proper checks already.
*/ */
if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
!kvm_vgic_global_state.can_emulate_gicv2) { !kvm_vgic_global_state.can_emulate_gicv2)
ret = -ENODEV; return -ENODEV;
goto out;
}
/* /*
* Any time a vcpu is run, vcpu_load is called which tries to grab the * Any time a vcpu is run, vcpu_load is called which tries to grab the
...@@ -138,9 +132,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) ...@@ -138,9 +132,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx); vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
mutex_unlock(&vcpu->mutex); mutex_unlock(&vcpu->mutex);
} }
out:
mutex_unlock(&kvm->lock);
return ret; return ret;
} }
......
...@@ -696,6 +696,11 @@ static void kvm_destroy_devices(struct kvm *kvm) ...@@ -696,6 +696,11 @@ static void kvm_destroy_devices(struct kvm *kvm)
{ {
struct kvm_device *dev, *tmp; 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_for_each_entry_safe(dev, tmp, &kvm->devices, vm_node) {
list_del(&dev->vm_node); list_del(&dev->vm_node);
dev->ops->destroy(dev); dev->ops->destroy(dev);
...@@ -2832,19 +2837,28 @@ static int kvm_ioctl_create_device(struct kvm *kvm, ...@@ -2832,19 +2837,28 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
dev->ops = ops; dev->ops = ops;
dev->kvm = kvm; dev->kvm = kvm;
mutex_lock(&kvm->lock);
ret = ops->create(dev, cd->type); ret = ops->create(dev, cd->type);
if (ret < 0) { if (ret < 0) {
mutex_unlock(&kvm->lock);
kfree(dev); kfree(dev);
return ret; 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); ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);
if (ret < 0) { if (ret < 0) {
ops->destroy(dev); ops->destroy(dev);
mutex_lock(&kvm->lock);
list_del(&dev->vm_node);
mutex_unlock(&kvm->lock);
return ret; return ret;
} }
list_add(&dev->vm_node, &kvm->devices);
kvm_get_kvm(kvm); kvm_get_kvm(kvm);
cd->fd = ret; cd->fd = ret;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment