aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/arm/vgic.c70
1 files changed, 66 insertions, 4 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index d08ba28e729a..e59aaa4c64e5 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -663,18 +663,80 @@ static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
663 } 663 }
664} 664}
665 665
666static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu, 666/* Handle reads of GICD_CPENDSGIRn and GICD_SPENDSGIRn */
667 struct kvm_exit_mmio *mmio, 667static bool read_set_clear_sgi_pend_reg(struct kvm_vcpu *vcpu,
668 phys_addr_t offset) 668 struct kvm_exit_mmio *mmio,
669 phys_addr_t offset)
669{ 670{
671 struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
672 int sgi;
673 int min_sgi = (offset & ~0x3) * 4;
674 int max_sgi = min_sgi + 3;
675 int vcpu_id = vcpu->vcpu_id;
676 u32 reg = 0;
677
678 /* Copy source SGIs from distributor side */
679 for (sgi = min_sgi; sgi <= max_sgi; sgi++) {
680 int shift = 8 * (sgi - min_sgi);
681 reg |= (u32)dist->irq_sgi_sources[vcpu_id][sgi] << shift;
682 }
683
684 mmio_data_write(mmio, ~0, reg);
670 return false; 685 return false;
671} 686}
672 687
688static bool write_set_clear_sgi_pend_reg(struct kvm_vcpu *vcpu,
689 struct kvm_exit_mmio *mmio,
690 phys_addr_t offset, bool set)
691{
692 struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
693 int sgi;
694 int min_sgi = (offset & ~0x3) * 4;
695 int max_sgi = min_sgi + 3;
696 int vcpu_id = vcpu->vcpu_id;
697 u32 reg;
698 bool updated = false;
699
700 reg = mmio_data_read(mmio, ~0);
701
702 /* Clear pending SGIs on the distributor */
703 for (sgi = min_sgi; sgi <= max_sgi; sgi++) {
704 u8 mask = reg >> (8 * (sgi - min_sgi));
705 if (set) {
706 if ((dist->irq_sgi_sources[vcpu_id][sgi] & mask) != mask)
707 updated = true;
708 dist->irq_sgi_sources[vcpu_id][sgi] |= mask;
709 } else {
710 if (dist->irq_sgi_sources[vcpu_id][sgi] & mask)
711 updated = true;
712 dist->irq_sgi_sources[vcpu_id][sgi] &= ~mask;
713 }
714 }
715
716 if (updated)
717 vgic_update_state(vcpu->kvm);
718
719 return updated;
720}
721
673static bool handle_mmio_sgi_set(struct kvm_vcpu *vcpu, 722static bool handle_mmio_sgi_set(struct kvm_vcpu *vcpu,
674 struct kvm_exit_mmio *mmio, 723 struct kvm_exit_mmio *mmio,
675 phys_addr_t offset) 724 phys_addr_t offset)
676{ 725{
677 return false; 726 if (!mmio->is_write)
727 return read_set_clear_sgi_pend_reg(vcpu, mmio, offset);
728 else
729 return write_set_clear_sgi_pend_reg(vcpu, mmio, offset, true);
730}
731
732static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu,
733 struct kvm_exit_mmio *mmio,
734 phys_addr_t offset)
735{
736 if (!mmio->is_write)
737 return read_set_clear_sgi_pend_reg(vcpu, mmio, offset);
738 else
739 return write_set_clear_sgi_pend_reg(vcpu, mmio, offset, false);
678} 740}
679 741
680/* 742/*