Commit 544c572e03174438b6656ed24a4516b9a9d5f14a

Authored by Christoffer Dall
1 parent cff9211eb1

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>

Showing 1 changed file with 31 additions and 1 deletions Side-by-side Diff

... ... @@ -531,6 +531,34 @@
531 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 + */
  540 +static 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 +
534 562 bool vgic_handle_clear_pending_reg(struct kvm *kvm,
535 563 struct kvm_exit_mmio *mmio,
536 564 phys_addr_t offset, int vcpu_id)
... ... @@ -561,6 +589,7 @@
561 589 vcpu_id, offset);
562 590 vgic_reg_access(mmio, reg, offset, mode);
563 591  
  592 + vgic_handle_clear_mapped_irq(kvm_get_vcpu(kvm, vcpu_id));
564 593 vgic_update_state(kvm);
565 594 return true;
566 595 }
... ... @@ -598,6 +627,7 @@
598 627 ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT);
599 628  
600 629 if (mmio->is_write) {
  630 + vgic_handle_clear_mapped_irq(kvm_get_vcpu(kvm, vcpu_id));
601 631 vgic_update_state(kvm);
602 632 return true;
603 633 }
... ... @@ -1406,7 +1436,7 @@
1406 1436 return 0;
1407 1437  
1408 1438 map = vgic_irq_map_search(vcpu, vlr.irq);
1409   - BUG_ON(!map || !map->active);
  1439 + BUG_ON(!map);
1410 1440  
1411 1441 ret = irq_get_irqchip_state(map->irq,
1412 1442 IRQCHIP_STATE_ACTIVE,