]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/gic-v2.c
arm: add support for GICv2
[jailhouse.git] / hypervisor / arch / arm / gic-v2.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) ARM Limited, 2014
5  *
6  * Authors:
7  *  Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
13 #include <jailhouse/control.h>
14 #include <jailhouse/mmio.h>
15 #include <asm/gic_common.h>
16 #include <asm/irqchip.h>
17 #include <asm/platform.h>
18 #include <asm/setup.h>
19
20 static unsigned int gic_num_lr;
21
22 extern void *gicd_base;
23 extern unsigned int gicd_size;
24 void *gicc_base;
25 unsigned int gicc_size;
26 void *gicv_base;
27 void *gich_base;
28 unsigned int gich_size;
29
30 static int gic_init(void)
31 {
32         int err;
33
34         /* FIXME: parse device tree */
35         gicc_base = GICC_BASE;
36         gicc_size = GICC_SIZE;
37         gich_base = GICH_BASE;
38         gich_size = GICH_SIZE;
39         gicv_base = GICV_BASE;
40
41         err = arch_map_device(gicc_base, gicc_base, gicc_size);
42         if (err)
43                 return err;
44
45         err = arch_map_device(gich_base, gich_base, gich_size);
46
47         return err;
48 }
49
50 static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
51 {
52         unsigned int i;
53         bool root_shutdown = is_shutdown && (cpu_data->cell == &root_cell);
54         u32 active;
55         u32 gich_vmcr = 0;
56         u32 gicc_ctlr, gicc_pmr;
57
58         /* Clear list registers */
59         for (i = 0; i < gic_num_lr; i++)
60                 gic_write_lr(i, 0);
61
62         /* Deactivate all PPIs */
63         active = mmio_read32(gicd_base + GICD_ISACTIVER);
64         for (i = 16; i < 32; i++) {
65                 if (test_bit(i, (unsigned long *)&active))
66                         mmio_write32(gicc_base + GICC_DIR, i);
67         }
68
69         /* Disable PPIs if necessary */
70         if (!root_shutdown)
71                 mmio_write32(gicd_base + GICD_ICENABLER, 0xffff0000);
72         /* Ensure IPIs are enabled */
73         mmio_write32(gicd_base + GICD_ISENABLER, 0x0000ffff);
74
75         mmio_write32(gich_base + GICH_APR, 0);
76
77         if (is_shutdown)
78                 mmio_write32(gich_base + GICH_HCR, 0);
79
80         if (root_shutdown) {
81                 gich_vmcr = mmio_read32(gich_base + GICH_VMCR);
82                 gicc_ctlr = 0;
83                 gicc_pmr = (gich_vmcr >> GICH_VMCR_PMR_SHIFT) << GICV_PMR_SHIFT;
84
85                 if (gich_vmcr & GICH_VMCR_EN0)
86                         gicc_ctlr |= GICC_CTLR_GRPEN1;
87                 if (gich_vmcr & GICH_VMCR_EOImode)
88                         gicc_ctlr |= GICC_CTLR_EOImode;
89
90                 mmio_write32(gicc_base + GICC_CTLR, gicc_ctlr);
91                 mmio_write32(gicc_base + GICC_PMR, gicc_pmr);
92
93                 gich_vmcr = 0;
94         }
95         mmio_write32(gich_base + GICH_VMCR, gich_vmcr);
96
97         return 0;
98 }
99
100 static int gic_cpu_init(struct per_cpu *cpu_data)
101 {
102         u32 vtr, vmcr;
103         u32 cell_gicc_ctlr, cell_gicc_pmr;
104
105         /* Ensure all IPIs are enabled */
106         mmio_write32(gicd_base + GICD_ISENABLER, 0x0000ffff);
107
108         cell_gicc_ctlr = mmio_read32(gicc_base + GICC_CTLR);
109         cell_gicc_pmr = mmio_read32(gicc_base + GICC_PMR);
110
111         mmio_write32(gicc_base + GICC_CTLR,
112                      GICC_CTLR_GRPEN1 | GICC_CTLR_EOImode);
113         mmio_write32(gicc_base + GICC_PMR, GICC_PMR_DEFAULT);
114
115         vtr = mmio_read32(gich_base + GICH_VTR);
116         gic_num_lr = (vtr & 0x3f) + 1;
117
118         /* VMCR only contains 5 bits of priority */
119         vmcr = (cell_gicc_pmr >> GICV_PMR_SHIFT) << GICH_VMCR_PMR_SHIFT;
120         /*
121          * All virtual interrupts are group 0 in this driver since the GICV
122          * layout seen by the guest corresponds to GICC without security
123          * extensions:
124          * - A read from GICV_IAR doesn't acknowledge group 1 interrupts
125          *   (GICV_AIAR does it, but the guest never attempts to accesses it)
126          * - A write to GICV_CTLR.GRP0EN corresponds to the GICC_CTLR.GRP1EN bit
127          *   Since the guest's driver thinks that it is accessing a GIC with
128          *   security extensions, a write to GPR1EN will enable group 0
129          *   interrups.
130          * - Group 0 interrupts are presented as virtual IRQs (FIQEn = 0)
131          */
132         if (cell_gicc_ctlr & GICC_CTLR_GRPEN1)
133                 vmcr |= GICH_VMCR_EN0;
134         if (cell_gicc_ctlr & GICC_CTLR_EOImode)
135                 vmcr |= GICH_VMCR_EOImode;
136
137         mmio_write32(gich_base + GICH_VMCR, vmcr);
138         mmio_write32(gich_base + GICH_HCR, GICH_HCR_EN);
139
140         return 0;
141 }
142
143 static void gic_eoi_irq(u32 irq_id, bool deactivate)
144 {
145         /*
146          * The GIC doesn't seem to care about the CPUID value written to EOIR,
147          * which is rather convenient...
148          */
149         mmio_write32(gicc_base + GICC_EOIR, irq_id);
150         if (deactivate)
151                 mmio_write32(gicc_base + GICC_DIR, irq_id);
152 }
153
154 static void gic_route_spis(struct cell *config_cell, struct cell *dest_cell)
155 {
156 }
157
158 static void gic_cell_init(struct cell *cell)
159 {
160         struct jailhouse_memory gicv_region;
161
162         /*
163          * target_cpu_map has not been populated by all available CPUs when the
164          * setup code initialises the root cell. It is assumed that the kernel
165          * already has configured all its SPIs anyway, and that it will redirect
166          * them when unplugging a CPU.
167          */
168         if (cell != &root_cell)
169                 gic_route_spis(cell, cell);
170
171         gicv_region.phys_start = (unsigned long)gicv_base;
172         /*
173          * WARN: some SoCs (EXYNOS4) use a modified GIC which doesn't have any
174          * banked CPU interface, so we should map per-CPU physical addresses
175          * here.
176          * As for now, none of them seem to have virtualization extensions.
177          */
178         gicv_region.virt_start = (unsigned long)gicc_base;
179         gicv_region.size = gicc_size;
180         gicv_region.flags = JAILHOUSE_MEM_DMA | JAILHOUSE_MEM_READ
181                           | JAILHOUSE_MEM_WRITE;
182
183         /*
184          * Let the guest access the virtual CPU interface instead of the
185          * physical one
186          */
187         arch_map_memory_region(cell, &gicv_region);
188 }
189
190 static void gic_cell_exit(struct cell *cell)
191 {
192         /* Reset interrupt routing of the cell's spis*/
193         gic_route_spis(cell, &root_cell);
194 }
195
196 static int gic_send_sgi(struct sgi *sgi)
197 {
198         u32 val;
199
200         if (!is_sgi(sgi->id))
201                 return -EINVAL;
202
203         val = (sgi->routing_mode & 0x3) << 24
204                 | (sgi->targets & 0xff) << 16
205                 | (sgi->id & 0xf);
206
207         mmio_write32(gicd_base + GICD_SGIR, val);
208
209         return 0;
210 }
211
212 static int gic_inject_irq(struct per_cpu *cpu_data, struct pending_irq *irq)
213 {
214         int i;
215         int first_free = -1;
216         u32 lr;
217         u64 elsr;
218
219         elsr = mmio_read32(gich_base + GICH_ELSR0);
220         elsr |= (u64)mmio_read32(gich_base + GICH_ELSR1) << 32;
221         for (i = 0; i < gic_num_lr; i++) {
222                 if (test_bit(i, (unsigned long *)&elsr)) {
223                         /* Entry is available */
224                         if (first_free == -1)
225                                 first_free = i;
226                         continue;
227                 }
228
229                 /* Check that there is no overlapping */
230                 lr = gic_read_lr(i);
231                 if ((lr & GICH_LR_VIRT_ID_MASK) == irq->virt_id)
232                         return -EINVAL;
233         }
234
235         if (first_free == -1) {
236                 /* Enable maintenance IRQ */
237                 u32 hcr;
238                 hcr = mmio_read32(gich_base + GICH_HCR);
239                 hcr |= GICH_HCR_UIE;
240                 mmio_write32(gich_base + GICH_HCR, hcr);
241
242                 return -EBUSY;
243         }
244
245         /* Inject group 0 interrupt (seen as IRQ by the guest) */
246         lr = irq->virt_id;
247         lr |= GICH_LR_PENDING_BIT;
248
249         if (irq->hw) {
250                 lr |= GICH_LR_HW_BIT;
251                 lr |= irq->type.irq << GICH_LR_PHYS_ID_SHIFT;
252         } else {
253                 lr |= irq->type.sgi.cpuid << GICH_LR_CPUID_SHIFT;
254                 if (irq->type.sgi.maintenance)
255                         lr |= GICH_LR_SGI_EOI_BIT;
256         }
257
258         gic_write_lr(first_free, lr);
259
260         return 0;
261 }
262
263 static int gic_mmio_access(struct per_cpu *cpu_data,
264                            struct mmio_access *access)
265 {
266         void *address = (void *)access->addr;
267
268         if (address >= gicd_base && address < gicd_base + gicd_size)
269                 return gic_handle_dist_access(cpu_data, access);
270
271         return TRAP_UNHANDLED;
272 }
273
274 struct irqchip_ops gic_irqchip = {
275         .init = gic_init,
276         .cpu_init = gic_cpu_init,
277         .cpu_reset = gic_cpu_reset,
278         .cell_init = gic_cell_init,
279         .cell_exit = gic_cell_exit,
280
281         .send_sgi = gic_send_sgi,
282         .handle_irq = gic_handle_irq,
283         .inject_irq = gic_inject_irq,
284         .eoi_irq = gic_eoi_irq,
285         .mmio_access = gic_mmio_access,
286 };