Commit 05d36a7d authored by Paolo Bonzini's avatar Paolo Bonzini

Merge tag 'kvm-arm-for-v4.9-rc4' of...

Merge tag 'kvm-arm-for-v4.9-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/ARM updates for v4.9-rc4

- Kick the vcpu when a pending interrupt becomes pending again
- Prevent access to invalid interrupt registers
- Invalid TLBs when two vcpus from the same VM share a CPU
parents bc33b0ca d42c7970
...@@ -66,6 +66,7 @@ extern char __kvm_hyp_vector[]; ...@@ -66,6 +66,7 @@ extern char __kvm_hyp_vector[];
extern void __kvm_flush_vm_context(void); extern void __kvm_flush_vm_context(void);
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa); extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
extern void __kvm_tlb_flush_vmid(struct kvm *kvm); extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu); extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
......
...@@ -57,6 +57,9 @@ struct kvm_arch { ...@@ -57,6 +57,9 @@ struct kvm_arch {
/* VTTBR value associated with below pgd and vmid */ /* VTTBR value associated with below pgd and vmid */
u64 vttbr; u64 vttbr;
/* The last vcpu id that ran on each physical CPU */
int __percpu *last_vcpu_ran;
/* Timer */ /* Timer */
struct arch_timer_kvm timer; struct arch_timer_kvm timer;
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
#define ICIALLUIS __ACCESS_CP15(c7, 0, c1, 0) #define ICIALLUIS __ACCESS_CP15(c7, 0, c1, 0)
#define ATS1CPR __ACCESS_CP15(c7, 0, c8, 0) #define ATS1CPR __ACCESS_CP15(c7, 0, c8, 0)
#define TLBIALLIS __ACCESS_CP15(c8, 0, c3, 0) #define TLBIALLIS __ACCESS_CP15(c8, 0, c3, 0)
#define TLBIALL __ACCESS_CP15(c8, 0, c7, 0)
#define TLBIALLNSNHIS __ACCESS_CP15(c8, 4, c3, 4) #define TLBIALLNSNHIS __ACCESS_CP15(c8, 4, c3, 4)
#define PRRR __ACCESS_CP15(c10, 0, c2, 0) #define PRRR __ACCESS_CP15(c10, 0, c2, 0)
#define NMRR __ACCESS_CP15(c10, 0, c2, 1) #define NMRR __ACCESS_CP15(c10, 0, c2, 1)
......
...@@ -114,11 +114,18 @@ void kvm_arch_check_processor_compat(void *rtn) ...@@ -114,11 +114,18 @@ void kvm_arch_check_processor_compat(void *rtn)
*/ */
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
{ {
int ret = 0; int ret, cpu;
if (type) if (type)
return -EINVAL; return -EINVAL;
kvm->arch.last_vcpu_ran = alloc_percpu(typeof(*kvm->arch.last_vcpu_ran));
if (!kvm->arch.last_vcpu_ran)
return -ENOMEM;
for_each_possible_cpu(cpu)
*per_cpu_ptr(kvm->arch.last_vcpu_ran, cpu) = -1;
ret = kvm_alloc_stage2_pgd(kvm); ret = kvm_alloc_stage2_pgd(kvm);
if (ret) if (ret)
goto out_fail_alloc; goto out_fail_alloc;
...@@ -141,6 +148,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) ...@@ -141,6 +148,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
out_free_stage2_pgd: out_free_stage2_pgd:
kvm_free_stage2_pgd(kvm); kvm_free_stage2_pgd(kvm);
out_fail_alloc: out_fail_alloc:
free_percpu(kvm->arch.last_vcpu_ran);
kvm->arch.last_vcpu_ran = NULL;
return ret; return ret;
} }
...@@ -168,6 +177,9 @@ void kvm_arch_destroy_vm(struct kvm *kvm) ...@@ -168,6 +177,9 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
{ {
int i; int i;
free_percpu(kvm->arch.last_vcpu_ran);
kvm->arch.last_vcpu_ran = NULL;
for (i = 0; i < KVM_MAX_VCPUS; ++i) { for (i = 0; i < KVM_MAX_VCPUS; ++i) {
if (kvm->vcpus[i]) { if (kvm->vcpus[i]) {
kvm_arch_vcpu_free(kvm->vcpus[i]); kvm_arch_vcpu_free(kvm->vcpus[i]);
...@@ -312,6 +324,19 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) ...@@ -312,6 +324,19 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{ {
int *last_ran;
last_ran = this_cpu_ptr(vcpu->kvm->arch.last_vcpu_ran);
/*
* We might get preempted before the vCPU actually runs, but
* over-invalidation doesn't affect correctness.
*/
if (*last_ran != vcpu->vcpu_id) {
kvm_call_hyp(__kvm_tlb_flush_local_vmid, vcpu);
*last_ran = vcpu->vcpu_id;
}
vcpu->cpu = cpu; vcpu->cpu = cpu;
vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state); vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
......
...@@ -55,6 +55,21 @@ void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) ...@@ -55,6 +55,21 @@ void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
__kvm_tlb_flush_vmid(kvm); __kvm_tlb_flush_vmid(kvm);
} }
void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
/* Switch to requested VMID */
write_sysreg(kvm->arch.vttbr, VTTBR);
isb();
write_sysreg(0, TLBIALL);
dsb(nsh);
isb();
write_sysreg(0, VTTBR);
}
void __hyp_text __kvm_flush_vm_context(void) void __hyp_text __kvm_flush_vm_context(void)
{ {
write_sysreg(0, TLBIALLNSNHIS); write_sysreg(0, TLBIALLNSNHIS);
......
...@@ -54,6 +54,7 @@ extern char __kvm_hyp_vector[]; ...@@ -54,6 +54,7 @@ extern char __kvm_hyp_vector[];
extern void __kvm_flush_vm_context(void); extern void __kvm_flush_vm_context(void);
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa); extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
extern void __kvm_tlb_flush_vmid(struct kvm *kvm); extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu); extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
......
...@@ -62,6 +62,9 @@ struct kvm_arch { ...@@ -62,6 +62,9 @@ struct kvm_arch {
/* VTTBR value associated with above pgd and vmid */ /* VTTBR value associated with above pgd and vmid */
u64 vttbr; u64 vttbr;
/* The last vcpu id that ran on each physical CPU */
int __percpu *last_vcpu_ran;
/* The maximum number of vCPUs depends on the used GIC model */ /* The maximum number of vCPUs depends on the used GIC model */
int max_vcpus; int max_vcpus;
......
...@@ -128,7 +128,7 @@ static inline unsigned long __kern_hyp_va(unsigned long v) ...@@ -128,7 +128,7 @@ static inline unsigned long __kern_hyp_va(unsigned long v)
return v; return v;
} }
#define kern_hyp_va(v) (typeof(v))(__kern_hyp_va((unsigned long)(v))) #define kern_hyp_va(v) ((typeof(v))(__kern_hyp_va((unsigned long)(v))))
/* /*
* We currently only support a 40bit IPA. * We currently only support a 40bit IPA.
......
...@@ -64,6 +64,21 @@ void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm) ...@@ -64,6 +64,21 @@ void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
write_sysreg(0, vttbr_el2); write_sysreg(0, vttbr_el2);
} }
void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
/* Switch to requested VMID */
write_sysreg(kvm->arch.vttbr, vttbr_el2);
isb();
asm volatile("tlbi vmalle1" : : );
dsb(nsh);
isb();
write_sysreg(0, vttbr_el2);
}
void __hyp_text __kvm_flush_vm_context(void) void __hyp_text __kvm_flush_vm_context(void)
{ {
dsb(ishst); dsb(ishst);
......
...@@ -453,18 +453,34 @@ struct vgic_io_device *kvm_to_vgic_iodev(const struct kvm_io_device *dev) ...@@ -453,18 +453,34 @@ struct vgic_io_device *kvm_to_vgic_iodev(const struct kvm_io_device *dev)
return container_of(dev, struct vgic_io_device, dev); return container_of(dev, struct vgic_io_device, dev);
} }
static bool check_region(const struct vgic_register_region *region, static bool check_region(const struct kvm *kvm,
const struct vgic_register_region *region,
gpa_t addr, int len) gpa_t addr, int len)
{ {
if ((region->access_flags & VGIC_ACCESS_8bit) && len == 1) int flags, nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
return true;
if ((region->access_flags & VGIC_ACCESS_32bit) && switch (len) {
len == sizeof(u32) && !(addr & 3)) case sizeof(u8):
return true; flags = VGIC_ACCESS_8bit;
if ((region->access_flags & VGIC_ACCESS_64bit) && break;
len == sizeof(u64) && !(addr & 7)) case sizeof(u32):
flags = VGIC_ACCESS_32bit;
break;
case sizeof(u64):
flags = VGIC_ACCESS_64bit;
break;
default:
return false;
}
if ((region->access_flags & flags) && IS_ALIGNED(addr, len)) {
if (!region->bits_per_irq)
return true; return true;
/* Do we access a non-allocated IRQ? */
return VGIC_ADDR_TO_INTID(addr, region->bits_per_irq) < nr_irqs;
}
return false; return false;
} }
...@@ -477,7 +493,7 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, ...@@ -477,7 +493,7 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions, region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
addr - iodev->base_addr); addr - iodev->base_addr);
if (!region || !check_region(region, addr, len)) { if (!region || !check_region(vcpu->kvm, region, addr, len)) {
memset(val, 0, len); memset(val, 0, len);
return 0; return 0;
} }
...@@ -510,10 +526,7 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, ...@@ -510,10 +526,7 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions, region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
addr - iodev->base_addr); addr - iodev->base_addr);
if (!region) if (!region || !check_region(vcpu->kvm, region, addr, len))
return 0;
if (!check_region(region, addr, len))
return 0; return 0;
switch (iodev->iodev_type) { switch (iodev->iodev_type) {
......
...@@ -50,15 +50,15 @@ extern struct kvm_io_device_ops kvm_io_gic_ops; ...@@ -50,15 +50,15 @@ extern struct kvm_io_device_ops kvm_io_gic_ops;
#define VGIC_ADDR_IRQ_MASK(bits) (((bits) * 1024 / 8) - 1) #define VGIC_ADDR_IRQ_MASK(bits) (((bits) * 1024 / 8) - 1)
/* /*
* (addr & mask) gives us the byte offset for the INT ID, so we want to * (addr & mask) gives us the _byte_ offset for the INT ID.
* divide this with 'bytes per irq' to get the INT ID, which is given * We multiply this by 8 the get the _bit_ offset, then divide this by
* by '(bits) / 8'. But we do this with fixed-point-arithmetic and * the number of bits to learn the actual INT ID.
* take advantage of the fact that division by a fraction equals * But instead of a division (which requires a "long long div" implementation),
* multiplication with the inverted fraction, and scale up both the * we shift by the binary logarithm of <bits>.
* numerator and denominator with 8 to support at most 64 bits per IRQ: * This assumes that <bits> is a power of two.
*/ */
#define VGIC_ADDR_TO_INTID(addr, bits) (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \ #define VGIC_ADDR_TO_INTID(addr, bits) (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
64 / (bits) / 8) 8 >> ilog2(bits))
/* /*
* Some VGIC registers store per-IRQ information, with a different number * Some VGIC registers store per-IRQ information, with a different number
......
...@@ -273,6 +273,18 @@ bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq) ...@@ -273,6 +273,18 @@ bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq)
* no more work for us to do. * no more work for us to do.
*/ */
spin_unlock(&irq->irq_lock); spin_unlock(&irq->irq_lock);
/*
* We have to kick the VCPU here, because we could be
* queueing an edge-triggered interrupt for which we
* get no EOI maintenance interrupt. In that case,
* while the IRQ is already on the VCPU's AP list, the
* VCPU could have EOI'ed the original interrupt and
* won't see this one until it exits for some other
* reason.
*/
if (vcpu)
kvm_vcpu_kick(vcpu);
return false; return false;
} }
......
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