1 #include <errno.h>
2 #include <stdlib.h>
3
4 #include "kvm/irq.h"
5 #include "kvm/kvm.h"
6 #include "kvm/util.h"
7
8 #include "arm-common/gic.h"
9
10 #define GICV2M_MSI_TYPER 0x008
11 #define GICV2M_MSI_SETSPI 0x040
12 #define GICV2M_MSI_IIDR 0xfcc
13
14 #define GICV2M_SPI_MASK 0x3ff
15 #define GICV2M_MSI_TYPER_VAL(start, nr) \
16 (((start) & GICV2M_SPI_MASK) << 16 | ((nr) & GICV2M_SPI_MASK))
17
18 struct gicv2m_chip {
19 int first_spi;
20 int num_spis;
21 int *spis;
22 u64 base;
23 u64 size;
24 };
25
26 static struct gicv2m_chip v2m;
27
28 /*
29 * MSI routing is setup lazily, when the guest writes the MSI tables. The guest
30 * writes which SPI is associated to an MSI vector into the message data field.
31 * The IRQ code notifies us of any change to MSI routing via this callback.
32 * Store the MSI->SPI translation for later.
33 *
34 * Data is the GIC interrupt ID, that includes SGIs and PPIs. SGIs at 0-15, PPIs
35 * are 16-31 and SPIs are 32-1019. What we're saving for later is the MSI's GSI
36 * number, a logical ID used by KVM for routing. The GSI of an SPI is implicitly
37 * defined by KVM to be its pin number (SPI index), and the GSI of an MSI is
38 * allocated by kvmtool.
39 */
gicv2m_update_routing(struct kvm * kvm,struct kvm_irq_routing_entry * entry)40 static int gicv2m_update_routing(struct kvm *kvm,
41 struct kvm_irq_routing_entry *entry)
42 {
43 int spi;
44
45 if (entry->type != KVM_IRQ_ROUTING_MSI) {
46 errno = EINVAL;
47 return -errno;
48 }
49
50 if (!entry->u.msi.address_hi && !entry->u.msi.address_lo)
51 return 0;
52
53 spi = entry->u.msi.data & GICV2M_SPI_MASK;
54 if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) {
55 errno = EINVAL;
56 return -errno;
57 }
58
59 v2m.spis[spi - v2m.first_spi] = entry->gsi;
60
61 return 0;
62 }
63
64 /*
65 * Find SPI bound to the given MSI and return the associated GSI.
66 */
gicv2m_translate_gsi(struct kvm * kvm,u32 gsi)67 static int gicv2m_translate_gsi(struct kvm *kvm, u32 gsi)
68 {
69 int i;
70
71 for (i = 0; i < v2m.num_spis; i++) {
72 if (v2m.spis[i] == (int)gsi)
73 return i + v2m.first_spi - KVM_IRQ_OFFSET;
74 }
75
76 /* Not an MSI */
77 return gsi;
78 }
79
gicv2m_can_signal_msi(struct kvm * kvm)80 static bool gicv2m_can_signal_msi(struct kvm *kvm)
81 {
82 return true;
83 }
84
85 /*
86 * Instead of setting up MSI routes, virtual devices can also trigger them
87 * manually (like a direct write to MSI_SETSPI). In this case, trigger the SPI
88 * directly.
89 */
gicv2m_signal_msi(struct kvm * kvm,struct kvm_msi * msi)90 static int gicv2m_signal_msi(struct kvm *kvm, struct kvm_msi *msi)
91 {
92 int spi = msi->data & GICV2M_SPI_MASK;
93
94 if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) {
95 pr_err("invalid SPI number %d", spi);
96 return -EINVAL;
97 }
98
99 kvm__irq_trigger(kvm, spi);
100 return 0;
101 }
102
103 static struct msi_routing_ops gicv2m_routing = {
104 .update_route = gicv2m_update_routing,
105 .translate_gsi = gicv2m_translate_gsi,
106 .can_signal_msi = gicv2m_can_signal_msi,
107 .signal_msi = gicv2m_signal_msi,
108 };
109
gicv2m_mmio_callback(struct kvm_cpu * vcpu,u64 addr,u8 * data,u32 len,u8 is_write,void * ptr)110 static void gicv2m_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
111 u32 len, u8 is_write, void *ptr)
112 {
113 if (is_write)
114 return;
115
116 addr -= v2m.base;
117
118 switch (addr) {
119 case GICV2M_MSI_TYPER:
120 *(u32 *)data = GICV2M_MSI_TYPER_VAL(v2m.first_spi,
121 v2m.num_spis);
122 break;
123 case GICV2M_MSI_IIDR:
124 *(u32 *)data = 0x0;
125 break;
126 }
127 }
128
gic__create_gicv2m_frame(struct kvm * kvm,u64 base)129 int gic__create_gicv2m_frame(struct kvm *kvm, u64 base)
130 {
131 int i;
132 int irq = irq__alloc_line();
133
134 v2m = (struct gicv2m_chip) {
135 .first_spi = irq, /* Includes GIC_SPI_IRQ_BASE */
136 .num_spis = 64, /* arbitrary */
137 .base = base,
138 .size = KVM_VGIC_V2M_SIZE,
139 };
140
141 v2m.spis = calloc(v2m.num_spis, sizeof(int));
142 if (!v2m.spis)
143 return -ENOMEM;
144
145 v2m.spis[0] = -1;
146 for (i = 1; i < v2m.num_spis; i++) {
147 irq__alloc_line();
148 v2m.spis[i] = -1;
149 }
150
151 msi_routing_ops = &gicv2m_routing;
152
153 return kvm__register_mmio(kvm, base, KVM_VGIC_V2M_SIZE, false,
154 gicv2m_mmio_callback, kvm);
155 }
156