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) {
|
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
* 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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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])
|
|
||||||
>> PAGE_SHIFT) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[1])
|
/*
|
||||||
>> PAGE_SHIFT) < 0)
|
* The commpage address must not be mapped to anything else if the guest
|
||||||
return -1;
|
* 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[
|
gfn0 = mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT;
|
||||||
mips3_tlbpfn_to_paddr(tlb->tlb_lo[0]) >> PAGE_SHIFT];
|
gfn1 = mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT;
|
||||||
pfn1 = kvm->arch.guest_pmap[
|
if (gfn0 >= kvm->arch.guest_pmap_npages ||
|
||||||
mips3_tlbpfn_to_paddr(tlb->tlb_lo[1]) >> PAGE_SHIFT];
|
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 */
|
/* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@ retry:
|
|||||||
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 {
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
* 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 @@ out_unlock:
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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;
|
||||||
|
|||||||
Reference in New Issue
Block a user