aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/arm
diff options
context:
space:
mode:
authorChristoffer Dall <christoffer.dall@linaro.org>2014-06-14 16:30:45 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2014-09-18 21:44:32 -0400
commit9da48b5502622f9f0e49df957521ec43a0c9f4c1 (patch)
tree57d10bf03e4637f2e4d3a8d6abd5a5eeec8f2c2f /virt/kvm/arm
parentfaa1b46c3e9f4d40359aee04ff275eea5f4cae3a (diff)
arm/arm64: KVM: vgic: Fix SGI writes to GICD_I{CS}PENDR0
Writes to GICD_ISPENDR0 and GICD_ICPENDR0 ignore all settings of the pending state for SGIs. Make sure the implementation handles this correctly. Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'virt/kvm/arm')
-rw-r--r--virt/kvm/arm/vgic.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 435d8e7ad137..0039ae266a7b 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -454,7 +454,7 @@ static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu,
454 struct kvm_exit_mmio *mmio, 454 struct kvm_exit_mmio *mmio,
455 phys_addr_t offset) 455 phys_addr_t offset)
456{ 456{
457 u32 *reg; 457 u32 *reg, orig;
458 u32 level_mask; 458 u32 level_mask;
459 struct vgic_dist *dist = &vcpu->kvm->arch.vgic; 459 struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
460 460
@@ -463,6 +463,7 @@ static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu,
463 463
464 /* Mark both level and edge triggered irqs as pending */ 464 /* Mark both level and edge triggered irqs as pending */
465 reg = vgic_bitmap_get_reg(&dist->irq_pending, vcpu->vcpu_id, offset); 465 reg = vgic_bitmap_get_reg(&dist->irq_pending, vcpu->vcpu_id, offset);
466 orig = *reg;
466 vgic_reg_access(mmio, reg, offset, 467 vgic_reg_access(mmio, reg, offset,
467 ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT); 468 ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT);
468 469
@@ -474,6 +475,12 @@ static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu,
474 ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT); 475 ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT);
475 *reg &= level_mask; 476 *reg &= level_mask;
476 477
478 /* Ignore writes to SGIs */
479 if (offset < 2) {
480 *reg &= ~0xffff;
481 *reg |= orig & 0xffff;
482 }
483
477 vgic_update_state(vcpu->kvm); 484 vgic_update_state(vcpu->kvm);
478 return true; 485 return true;
479 } 486 }
@@ -486,10 +493,11 @@ static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu,
486 phys_addr_t offset) 493 phys_addr_t offset)
487{ 494{
488 u32 *level_active; 495 u32 *level_active;
489 u32 *reg; 496 u32 *reg, orig;
490 struct vgic_dist *dist = &vcpu->kvm->arch.vgic; 497 struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
491 498
492 reg = vgic_bitmap_get_reg(&dist->irq_pending, vcpu->vcpu_id, offset); 499 reg = vgic_bitmap_get_reg(&dist->irq_pending, vcpu->vcpu_id, offset);
500 orig = *reg;
493 vgic_reg_access(mmio, reg, offset, 501 vgic_reg_access(mmio, reg, offset,
494 ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT); 502 ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT);
495 if (mmio->is_write) { 503 if (mmio->is_write) {
@@ -500,6 +508,12 @@ static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu,
500 vcpu->vcpu_id, offset); 508 vcpu->vcpu_id, offset);
501 *reg |= *level_active; 509 *reg |= *level_active;
502 510
511 /* Ignore writes to SGIs */
512 if (offset < 2) {
513 *reg &= ~0xffff;
514 *reg |= orig & 0xffff;
515 }
516
503 /* Clear soft-pending flags */ 517 /* Clear soft-pending flags */
504 reg = vgic_bitmap_get_reg(&dist->irq_soft_pend, 518 reg = vgic_bitmap_get_reg(&dist->irq_soft_pend,
505 vcpu->vcpu_id, offset); 519 vcpu->vcpu_id, offset);