Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c44f4f0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull KVM bugfixes from Paolo Bonzini:
 "Bug fixes for ARM, mostly 4.3 regressions related to virtual interrupt
  controller changes"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  arm/arm64: KVM: Fix disabled distributor operation
  arm/arm64: KVM: Clear map->active on pend/active clear
  arm/arm64: KVM: Fix arch timer behavior for disabled interrupts
  KVM: arm: use GIC support unconditionally
  KVM: arm/arm64: Fix memory leak if timer initialization fails
  KVM: arm/arm64: Do not inject spurious interrupts
parents 8a990fb4 ad355e38
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ config KVM
	depends on MMU && OF
	depends on MMU && OF
	select PREEMPT_NOTIFIERS
	select PREEMPT_NOTIFIERS
	select ANON_INODES
	select ANON_INODES
	select ARM_GIC
	select HAVE_KVM_CPU_RELAX_INTERCEPT
	select HAVE_KVM_CPU_RELAX_INTERCEPT
	select HAVE_KVM_ARCH_TLB_FLUSH_ALL
	select HAVE_KVM_ARCH_TLB_FLUSH_ALL
	select KVM_MMIO
	select KVM_MMIO
+1 −1
Original line number Original line Diff line number Diff line
@@ -1080,7 +1080,7 @@ static int init_hyp_mode(void)
	 */
	 */
	err = kvm_timer_hyp_init();
	err = kvm_timer_hyp_init();
	if (err)
	if (err)
		goto out_free_mappings;
		goto out_free_context;


#ifndef CONFIG_HOTPLUG_CPU
#ifndef CONFIG_HOTPLUG_CPU
	free_boot_hyp_pgd();
	free_boot_hyp_pgd();
+19 −0
Original line number Original line Diff line number Diff line
@@ -137,6 +137,8 @@ bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
{
{
	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
	bool phys_active;
	int ret;


	/*
	/*
	 * We're about to run this vcpu again, so there is no need to
	 * We're about to run this vcpu again, so there is no need to
@@ -151,6 +153,23 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
	 */
	 */
	if (kvm_timer_should_fire(vcpu))
	if (kvm_timer_should_fire(vcpu))
		kvm_timer_inject_irq(vcpu);
		kvm_timer_inject_irq(vcpu);

	/*
	 * We keep track of whether the edge-triggered interrupt has been
	 * signalled to the vgic/guest, and if so, we mask the interrupt and
	 * the physical distributor to prevent the timer from raising a
	 * physical interrupt whenever we run a guest, preventing forward
	 * VCPU progress.
	 */
	if (kvm_vgic_get_phys_irq_active(timer->map))
		phys_active = true;
	else
		phys_active = false;

	ret = irq_set_irqchip_state(timer->map->irq,
				    IRQCHIP_STATE_ACTIVE,
				    phys_active);
	WARN_ON(ret);
}
}


/**
/**
+55 −40
Original line number Original line Diff line number Diff line
@@ -531,6 +531,34 @@ bool vgic_handle_set_pending_reg(struct kvm *kvm,
	return false;
	return false;
}
}


/*
 * If a mapped interrupt's state has been modified by the guest such that it
 * is no longer active or pending, without it have gone through the sync path,
 * then the map->active field must be cleared so the interrupt can be taken
 * again.
 */
static void vgic_handle_clear_mapped_irq(struct kvm_vcpu *vcpu)
{
	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
	struct list_head *root;
	struct irq_phys_map_entry *entry;
	struct irq_phys_map *map;

	rcu_read_lock();

	/* Check for PPIs */
	root = &vgic_cpu->irq_phys_map_list;
	list_for_each_entry_rcu(entry, root, entry) {
		map = &entry->map;

		if (!vgic_dist_irq_is_pending(vcpu, map->virt_irq) &&
		    !vgic_irq_is_active(vcpu, map->virt_irq))
			map->active = false;
	}

	rcu_read_unlock();
}

bool vgic_handle_clear_pending_reg(struct kvm *kvm,
bool vgic_handle_clear_pending_reg(struct kvm *kvm,
				   struct kvm_exit_mmio *mmio,
				   struct kvm_exit_mmio *mmio,
				   phys_addr_t offset, int vcpu_id)
				   phys_addr_t offset, int vcpu_id)
@@ -561,6 +589,7 @@ bool vgic_handle_clear_pending_reg(struct kvm *kvm,
					  vcpu_id, offset);
					  vcpu_id, offset);
		vgic_reg_access(mmio, reg, offset, mode);
		vgic_reg_access(mmio, reg, offset, mode);


		vgic_handle_clear_mapped_irq(kvm_get_vcpu(kvm, vcpu_id));
		vgic_update_state(kvm);
		vgic_update_state(kvm);
		return true;
		return true;
	}
	}
@@ -598,6 +627,7 @@ bool vgic_handle_clear_active_reg(struct kvm *kvm,
			ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT);
			ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT);


	if (mmio->is_write) {
	if (mmio->is_write) {
		vgic_handle_clear_mapped_irq(kvm_get_vcpu(kvm, vcpu_id));
		vgic_update_state(kvm);
		vgic_update_state(kvm);
		return true;
		return true;
	}
	}
@@ -982,6 +1012,12 @@ static int compute_pending_for_cpu(struct kvm_vcpu *vcpu)
	pend_percpu = vcpu->arch.vgic_cpu.pending_percpu;
	pend_percpu = vcpu->arch.vgic_cpu.pending_percpu;
	pend_shared = vcpu->arch.vgic_cpu.pending_shared;
	pend_shared = vcpu->arch.vgic_cpu.pending_shared;


	if (!dist->enabled) {
		bitmap_zero(pend_percpu, VGIC_NR_PRIVATE_IRQS);
		bitmap_zero(pend_shared, nr_shared);
		return 0;
	}

	pending = vgic_bitmap_get_cpu_map(&dist->irq_pending, vcpu_id);
	pending = vgic_bitmap_get_cpu_map(&dist->irq_pending, vcpu_id);
	enabled = vgic_bitmap_get_cpu_map(&dist->irq_enabled, vcpu_id);
	enabled = vgic_bitmap_get_cpu_map(&dist->irq_enabled, vcpu_id);
	bitmap_and(pend_percpu, pending, enabled, VGIC_NR_PRIVATE_IRQS);
	bitmap_and(pend_percpu, pending, enabled, VGIC_NR_PRIVATE_IRQS);
@@ -1009,11 +1045,6 @@ void vgic_update_state(struct kvm *kvm)
	struct kvm_vcpu *vcpu;
	struct kvm_vcpu *vcpu;
	int c;
	int c;


	if (!dist->enabled) {
		set_bit(0, dist->irq_pending_on_cpu);
		return;
	}

	kvm_for_each_vcpu(c, vcpu, kvm) {
	kvm_for_each_vcpu(c, vcpu, kvm) {
		if (compute_pending_for_cpu(vcpu))
		if (compute_pending_for_cpu(vcpu))
			set_bit(c, dist->irq_pending_on_cpu);
			set_bit(c, dist->irq_pending_on_cpu);
@@ -1092,6 +1123,15 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
	struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
	struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);


	/*
	 * We must transfer the pending state back to the distributor before
	 * retiring the LR, otherwise we may loose edge-triggered interrupts.
	 */
	if (vlr.state & LR_STATE_PENDING) {
		vgic_dist_irq_set_pending(vcpu, irq);
		vlr.hwirq = 0;
	}

	vlr.state = 0;
	vlr.state = 0;
	vgic_set_lr(vcpu, lr_nr, vlr);
	vgic_set_lr(vcpu, lr_nr, vlr);
	clear_bit(lr_nr, vgic_cpu->lr_used);
	clear_bit(lr_nr, vgic_cpu->lr_used);
@@ -1132,7 +1172,8 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
		kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
		kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
		vgic_irq_clear_active(vcpu, irq);
		vgic_irq_clear_active(vcpu, irq);
		vgic_update_state(vcpu->kvm);
		vgic_update_state(vcpu->kvm);
	} else if (vgic_dist_irq_is_pending(vcpu, irq)) {
	} else {
		WARN_ON(!vgic_dist_irq_is_pending(vcpu, irq));
		vlr.state |= LR_STATE_PENDING;
		vlr.state |= LR_STATE_PENDING;
		kvm_debug("Set pending: 0x%x\n", vlr.state);
		kvm_debug("Set pending: 0x%x\n", vlr.state);
	}
	}
@@ -1240,7 +1281,7 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
	unsigned long *pa_percpu, *pa_shared;
	unsigned long *pa_percpu, *pa_shared;
	int i, vcpu_id, lr, ret;
	int i, vcpu_id;
	int overflow = 0;
	int overflow = 0;
	int nr_shared = vgic_nr_shared_irqs(dist);
	int nr_shared = vgic_nr_shared_irqs(dist);


@@ -1295,31 +1336,6 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
		 */
		 */
		clear_bit(vcpu_id, dist->irq_pending_on_cpu);
		clear_bit(vcpu_id, dist->irq_pending_on_cpu);
	}
	}

	for (lr = 0; lr < vgic->nr_lr; lr++) {
		struct vgic_lr vlr;

		if (!test_bit(lr, vgic_cpu->lr_used))
			continue;

		vlr = vgic_get_lr(vcpu, lr);

		/*
		 * If we have a mapping, and the virtual interrupt is
		 * presented to the guest (as pending or active), then we must
		 * set the state to active in the physical world. See
		 * Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt.
		 */
		if (vlr.state & LR_HW) {
			struct irq_phys_map *map;
			map = vgic_irq_map_search(vcpu, vlr.irq);

			ret = irq_set_irqchip_state(map->irq,
						    IRQCHIP_STATE_ACTIVE,
						    true);
			WARN_ON(ret);
		}
	}
}
}


static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
@@ -1421,7 +1437,7 @@ static int vgic_sync_hwirq(struct kvm_vcpu *vcpu, struct vgic_lr vlr)
		return 0;
		return 0;


	map = vgic_irq_map_search(vcpu, vlr.irq);
	map = vgic_irq_map_search(vcpu, vlr.irq);
	BUG_ON(!map || !map->active);
	BUG_ON(!map);


	ret = irq_get_irqchip_state(map->irq,
	ret = irq_get_irqchip_state(map->irq,
				    IRQCHIP_STATE_ACTIVE,
				    IRQCHIP_STATE_ACTIVE,
@@ -1429,13 +1445,8 @@ static int vgic_sync_hwirq(struct kvm_vcpu *vcpu, struct vgic_lr vlr)


	WARN_ON(ret);
	WARN_ON(ret);


	if (map->active) {
	if (map->active)
		ret = irq_set_irqchip_state(map->irq,
					    IRQCHIP_STATE_ACTIVE,
					    false);
		WARN_ON(ret);
		return 0;
		return 0;
	}


	return 1;
	return 1;
}
}
@@ -1607,8 +1618,12 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
	} else {
	} else {
		if (level_triggered) {
		if (level_triggered) {
			vgic_dist_irq_clear_level(vcpu, irq_num);
			vgic_dist_irq_clear_level(vcpu, irq_num);
			if (!vgic_dist_irq_soft_pend(vcpu, irq_num))
			if (!vgic_dist_irq_soft_pend(vcpu, irq_num)) {
				vgic_dist_irq_clear_pending(vcpu, irq_num);
				vgic_dist_irq_clear_pending(vcpu, irq_num);
				vgic_cpu_irq_clear(vcpu, irq_num);
				if (!compute_pending_for_cpu(vcpu))
					clear_bit(cpuid, dist->irq_pending_on_cpu);
			}
		}
		}


		ret = false;
		ret = false;