diff options
Diffstat (limited to 'virt/kvm/arm')
-rw-r--r-- | virt/kvm/arm/vgic.c | 18 |
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); |