xref: /kvmtool/arm/gicv2m.c (revision e3b0ade2de2b1d38630d51600d5e6eb859f5dc89)
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