diff options
-rw-r--r-- | virt/kvm/arm/vgic.c | 81 |
1 files changed, 73 insertions, 8 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index e59aaa4c64e5..be456ce264d0 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c | |||
@@ -71,6 +71,10 @@ | |||
71 | #define VGIC_ADDR_UNDEF (-1) | 71 | #define VGIC_ADDR_UNDEF (-1) |
72 | #define IS_VGIC_ADDR_UNDEF(_x) ((_x) == VGIC_ADDR_UNDEF) | 72 | #define IS_VGIC_ADDR_UNDEF(_x) ((_x) == VGIC_ADDR_UNDEF) |
73 | 73 | ||
74 | #define PRODUCT_ID_KVM 0x4b /* ASCII code K */ | ||
75 | #define IMPLEMENTER_ARM 0x43b | ||
76 | #define GICC_ARCH_VERSION_V2 0x2 | ||
77 | |||
74 | /* Physical address of vgic virtual cpu interface */ | 78 | /* Physical address of vgic virtual cpu interface */ |
75 | static phys_addr_t vgic_vcpu_base; | 79 | static phys_addr_t vgic_vcpu_base; |
76 | 80 | ||
@@ -312,7 +316,7 @@ static bool handle_mmio_misc(struct kvm_vcpu *vcpu, | |||
312 | u32 word_offset = offset & 3; | 316 | u32 word_offset = offset & 3; |
313 | 317 | ||
314 | switch (offset & ~3) { | 318 | switch (offset & ~3) { |
315 | case 0: /* CTLR */ | 319 | case 0: /* GICD_CTLR */ |
316 | reg = vcpu->kvm->arch.vgic.enabled; | 320 | reg = vcpu->kvm->arch.vgic.enabled; |
317 | vgic_reg_access(mmio, ®, word_offset, | 321 | vgic_reg_access(mmio, ®, word_offset, |
318 | ACCESS_READ_VALUE | ACCESS_WRITE_VALUE); | 322 | ACCESS_READ_VALUE | ACCESS_WRITE_VALUE); |
@@ -323,15 +327,15 @@ static bool handle_mmio_misc(struct kvm_vcpu *vcpu, | |||
323 | } | 327 | } |
324 | break; | 328 | break; |
325 | 329 | ||
326 | case 4: /* TYPER */ | 330 | case 4: /* GICD_TYPER */ |
327 | reg = (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5; | 331 | reg = (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5; |
328 | reg |= (VGIC_NR_IRQS >> 5) - 1; | 332 | reg |= (VGIC_NR_IRQS >> 5) - 1; |
329 | vgic_reg_access(mmio, ®, word_offset, | 333 | vgic_reg_access(mmio, ®, word_offset, |
330 | ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED); | 334 | ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED); |
331 | break; | 335 | break; |
332 | 336 | ||
333 | case 8: /* IIDR */ | 337 | case 8: /* GICD_IIDR */ |
334 | reg = 0x4B00043B; | 338 | reg = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0); |
335 | vgic_reg_access(mmio, ®, word_offset, | 339 | vgic_reg_access(mmio, ®, word_offset, |
336 | ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED); | 340 | ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED); |
337 | break; | 341 | break; |
@@ -1716,9 +1720,70 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) | |||
1716 | static bool handle_cpu_mmio_misc(struct kvm_vcpu *vcpu, | 1720 | static bool handle_cpu_mmio_misc(struct kvm_vcpu *vcpu, |
1717 | struct kvm_exit_mmio *mmio, phys_addr_t offset) | 1721 | struct kvm_exit_mmio *mmio, phys_addr_t offset) |
1718 | { | 1722 | { |
1719 | return true; | 1723 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; |
1724 | u32 reg, mask = 0, shift = 0; | ||
1725 | bool updated = false; | ||
1726 | |||
1727 | switch (offset & ~0x3) { | ||
1728 | case GIC_CPU_CTRL: | ||
1729 | mask = GICH_VMCR_CTRL_MASK; | ||
1730 | shift = GICH_VMCR_CTRL_SHIFT; | ||
1731 | break; | ||
1732 | case GIC_CPU_PRIMASK: | ||
1733 | mask = GICH_VMCR_PRIMASK_MASK; | ||
1734 | shift = GICH_VMCR_PRIMASK_SHIFT; | ||
1735 | break; | ||
1736 | case GIC_CPU_BINPOINT: | ||
1737 | mask = GICH_VMCR_BINPOINT_MASK; | ||
1738 | shift = GICH_VMCR_BINPOINT_SHIFT; | ||
1739 | break; | ||
1740 | case GIC_CPU_ALIAS_BINPOINT: | ||
1741 | mask = GICH_VMCR_ALIAS_BINPOINT_MASK; | ||
1742 | shift = GICH_VMCR_ALIAS_BINPOINT_SHIFT; | ||
1743 | break; | ||
1744 | } | ||
1745 | |||
1746 | if (!mmio->is_write) { | ||
1747 | reg = (vgic_cpu->vgic_vmcr & mask) >> shift; | ||
1748 | mmio_data_write(mmio, ~0, reg); | ||
1749 | } else { | ||
1750 | reg = mmio_data_read(mmio, ~0); | ||
1751 | reg = (reg << shift) & mask; | ||
1752 | if (reg != (vgic_cpu->vgic_vmcr & mask)) | ||
1753 | updated = true; | ||
1754 | vgic_cpu->vgic_vmcr &= ~mask; | ||
1755 | vgic_cpu->vgic_vmcr |= reg; | ||
1756 | } | ||
1757 | return updated; | ||
1758 | } | ||
1759 | |||
1760 | static bool handle_mmio_abpr(struct kvm_vcpu *vcpu, | ||
1761 | struct kvm_exit_mmio *mmio, phys_addr_t offset) | ||
1762 | { | ||
1763 | return handle_cpu_mmio_misc(vcpu, mmio, GIC_CPU_ALIAS_BINPOINT); | ||
1720 | } | 1764 | } |
1721 | 1765 | ||
1766 | static bool handle_cpu_mmio_ident(struct kvm_vcpu *vcpu, | ||
1767 | struct kvm_exit_mmio *mmio, | ||
1768 | phys_addr_t offset) | ||
1769 | { | ||
1770 | u32 reg; | ||
1771 | |||
1772 | if (mmio->is_write) | ||
1773 | return false; | ||
1774 | |||
1775 | /* GICC_IIDR */ | ||
1776 | reg = (PRODUCT_ID_KVM << 20) | | ||
1777 | (GICC_ARCH_VERSION_V2 << 16) | | ||
1778 | (IMPLEMENTER_ARM << 0); | ||
1779 | mmio_data_write(mmio, ~0, reg); | ||
1780 | return false; | ||
1781 | } | ||
1782 | |||
1783 | /* | ||
1784 | * CPU Interface Register accesses - these are not accessed by the VM, but by | ||
1785 | * user space for saving and restoring VGIC state. | ||
1786 | */ | ||
1722 | static const struct mmio_range vgic_cpu_ranges[] = { | 1787 | static const struct mmio_range vgic_cpu_ranges[] = { |
1723 | { | 1788 | { |
1724 | .base = GIC_CPU_CTRL, | 1789 | .base = GIC_CPU_CTRL, |
@@ -1728,17 +1793,17 @@ static const struct mmio_range vgic_cpu_ranges[] = { | |||
1728 | { | 1793 | { |
1729 | .base = GIC_CPU_ALIAS_BINPOINT, | 1794 | .base = GIC_CPU_ALIAS_BINPOINT, |
1730 | .len = 4, | 1795 | .len = 4, |
1731 | .handle_mmio = handle_cpu_mmio_misc, | 1796 | .handle_mmio = handle_mmio_abpr, |
1732 | }, | 1797 | }, |
1733 | { | 1798 | { |
1734 | .base = GIC_CPU_ACTIVEPRIO, | 1799 | .base = GIC_CPU_ACTIVEPRIO, |
1735 | .len = 16, | 1800 | .len = 16, |
1736 | .handle_mmio = handle_cpu_mmio_misc, | 1801 | .handle_mmio = handle_mmio_raz_wi, |
1737 | }, | 1802 | }, |
1738 | { | 1803 | { |
1739 | .base = GIC_CPU_IDENT, | 1804 | .base = GIC_CPU_IDENT, |
1740 | .len = 4, | 1805 | .len = 4, |
1741 | .handle_mmio = handle_cpu_mmio_misc, | 1806 | .handle_mmio = handle_cpu_mmio_ident, |
1742 | }, | 1807 | }, |
1743 | }; | 1808 | }; |
1744 | 1809 | ||