summaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorChristoffer Dall <christoffer.dall@linaro.org>2015-10-17 11:55:12 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2015-10-20 12:06:34 -0400
commit544c572e03174438b6656ed24a4516b9a9d5f14a (patch)
treeebeb8f44e77a1f0f0b375ca97fcae8902684cd6b /virt
parentcff9211eb1a1f58ce7f5a2d596b617928fd4be0e (diff)
arm/arm64: KVM: Clear map->active on pend/active clear
When a guest reboots or offlines/onlines CPUs, it is not uncommon for it to clear the pending and active states of an interrupt through the emulated VGIC distributor. However, since the architected timers are defined by the architecture to be level triggered and the guest rightfully expects them to be that, but we emulate them as edge-triggered, we have to mimic level-triggered behavior for an edge-triggered virtual implementation. We currently do not signal the VGIC when the map->active field is true, because it indicates that the guest has already been signalled of the interrupt as required. Normally this field is set to false when the guest deactivates the virtual interrupt through the sync path. We also need to catch the case where the guest deactivates the interrupt through the emulated distributor, again allowing guests to boot even if the original virtual timer signal hit before the guest's GIC initialization sequence is run. Reviewed-by: Eric Auger <eric.auger@linaro.org> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/arm/vgic.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index ea21bc273542..58b125676785 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -531,6 +531,34 @@ bool vgic_handle_set_pending_reg(struct kvm *kvm,
531 return false; 531 return false;
532} 532}
533 533
534/*
535 * If a mapped interrupt's state has been modified by the guest such that it
536 * is no longer active or pending, without it have gone through the sync path,
537 * then the map->active field must be cleared so the interrupt can be taken
538 * again.
539 */
540static void vgic_handle_clear_mapped_irq(struct kvm_vcpu *vcpu)
541{
542 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
543 struct list_head *root;
544 struct irq_phys_map_entry *entry;
545 struct irq_phys_map *map;
546
547 rcu_read_lock();
548
549 /* Check for PPIs */
550 root = &vgic_cpu->irq_phys_map_list;
551 list_for_each_entry_rcu(entry, root, entry) {
552 map = &entry->map;
553
554 if (!vgic_dist_irq_is_pending(vcpu, map->virt_irq) &&
555 !vgic_irq_is_active(vcpu, map->virt_irq))
556 map->active = false;
557 }
558
559 rcu_read_unlock();
560}
561
534bool vgic_handle_clear_pending_reg(struct kvm *kvm, 562bool vgic_handle_clear_pending_reg(struct kvm *kvm,
535 struct kvm_exit_mmio *mmio, 563 struct kvm_exit_mmio *mmio,
536 phys_addr_t offset, int vcpu_id) 564 phys_addr_t offset, int vcpu_id)
@@ -561,6 +589,7 @@ bool vgic_handle_clear_pending_reg(struct kvm *kvm,
561 vcpu_id, offset); 589 vcpu_id, offset);
562 vgic_reg_access(mmio, reg, offset, mode); 590 vgic_reg_access(mmio, reg, offset, mode);
563 591
592 vgic_handle_clear_mapped_irq(kvm_get_vcpu(kvm, vcpu_id));
564 vgic_update_state(kvm); 593 vgic_update_state(kvm);
565 return true; 594 return true;
566 } 595 }
@@ -598,6 +627,7 @@ bool vgic_handle_clear_active_reg(struct kvm *kvm,
598 ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT); 627 ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT);
599 628
600 if (mmio->is_write) { 629 if (mmio->is_write) {
630 vgic_handle_clear_mapped_irq(kvm_get_vcpu(kvm, vcpu_id));
601 vgic_update_state(kvm); 631 vgic_update_state(kvm);
602 return true; 632 return true;
603 } 633 }
@@ -1406,7 +1436,7 @@ static int vgic_sync_hwirq(struct kvm_vcpu *vcpu, struct vgic_lr vlr)
1406 return 0; 1436 return 0;
1407 1437
1408 map = vgic_irq_map_search(vcpu, vlr.irq); 1438 map = vgic_irq_map_search(vcpu, vlr.irq);
1409 BUG_ON(!map || !map->active); 1439 BUG_ON(!map);
1410 1440
1411 ret = irq_get_irqchip_state(map->irq, 1441 ret = irq_get_irqchip_state(map->irq,
1412 IRQCHIP_STATE_ACTIVE, 1442 IRQCHIP_STATE_ACTIVE,