]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/gic-common.c
arm: GIC: handle distributor accesses
[jailhouse.git] / hypervisor / arch / arm / gic-common.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/cell.h>
16 #include <asm/gic_common.h>
17 #include <asm/irqchip.h>
18 #include <asm/percpu.h>
19 #include <asm/platform.h>
20 #include <asm/spinlock.h>
21 #include <asm/traps.h>
22
23 #define REG_RANGE(base, n, size)                \
24                 (base) ... ((base) + (n - 1) * (size))
25
26 extern void *gicd_base;
27 extern unsigned int gicd_size;
28
29 static DEFINE_SPINLOCK(dist_lock);
30
31 /*
32  * Most of the GIC distributor writes only reconfigure the IRQs corresponding to
33  * the bits of the written value, by using separate `set' and `clear' registers.
34  * Such registers can be handled by setting the `is_poke' boolean, which allows
35  * to simply restrict the access->val with the cell configuration mask.
36  * Others, such as the priority registers, will need to be read and written back
37  * with a restricted value, by using the distributor lock.
38  */
39 static int restrict_bitmask_access(struct per_cpu *cpu_data,
40                                    struct mmio_access *access,
41                                    unsigned int reg_index,
42                                    unsigned int bits_per_irq,
43                                    bool is_poke)
44 {
45         unsigned int spi;
46         unsigned long access_mask = 0;
47         /*
48          * In order to avoid division, the number of bits per irq is limited
49          * to powers of 2 for the moment.
50          */
51         unsigned long irqs_per_reg = 32 >> ffsl(bits_per_irq);
52         unsigned long spi_bits = (1 << bits_per_irq) - 1;
53         /* First, extract the first interrupt affected by this access */
54         unsigned int first_irq = reg_index * irqs_per_reg;
55
56         /* For SGIs or PPIs, let the caller do the mmio access */
57         if (!is_spi(first_irq))
58                 return TRAP_UNHANDLED;
59
60         /* For SPIs, compare against the cell config mask */
61         first_irq -= 32;
62         for (spi = first_irq; spi < first_irq + irqs_per_reg; spi++) {
63                 unsigned int bit_nr = (spi - first_irq) * bits_per_irq;
64                 if (spi_in_cell(cpu_data->cell, spi))
65                         access_mask |= spi_bits << bit_nr;
66         }
67
68         if (!access->is_write) {
69                 /* Restrict the read value */
70                 arch_mmio_access(access);
71                 access->val &= access_mask;
72                 return TRAP_HANDLED;
73         }
74
75         if (!is_poke) {
76                 /*
77                  * Modify the existing value of this register by first reading
78                  * it into access->val
79                  * Relies on a spinlock since we need two mmio accesses.
80                  */
81                 unsigned long access_val = access->val;
82
83                 spin_lock(&dist_lock);
84
85                 access->is_write = false;
86                 arch_mmio_access(access);
87                 access->is_write = true;
88
89                 /* Clear 0 bits */
90                 access->val &= ~(access_mask & ~access_val);
91                 access->val |= access_val;
92                 arch_mmio_access(access);
93
94                 spin_unlock(&dist_lock);
95
96                 return TRAP_HANDLED;
97         } else {
98                 access->val &= access_mask;
99                 /* Do the access */
100                 return TRAP_UNHANDLED;
101         }
102 }
103
104 /*
105  * GICv3 uses a 64bit register IROUTER for each IRQ
106  */
107 static int handle_irq_route(struct per_cpu *cpu_data,
108                             struct mmio_access *access, unsigned int irq)
109 {
110         struct cell *cell = cpu_data->cell;
111         unsigned int cpu;
112
113         /* Ignore aff3 on AArch32 (return 0) */
114         if (access->size == 4 && (access->addr % 8))
115                 return TRAP_HANDLED;
116
117         /* SGIs and PPIs are res0 */
118         if (!is_spi(irq))
119                 return TRAP_HANDLED;
120
121         /*
122          * Ignore accesses to SPIs that do not belong to the cell. This isn't
123          * forbidden, because the guest driver may simply iterate over all
124          * registers at initialisation
125          */
126         if (!spi_in_cell(cell, irq - 32))
127                 return TRAP_HANDLED;
128
129         /* Translate the virtual cpu id into the physical one */
130         if (access->is_write) {
131                 access->val = arm_cpu_virt2phys(cell, access->val);
132                 if (access->val == -1) {
133                         printk("Attempt to route IRQ%d outside of cell\n", irq);
134                         return TRAP_FORBIDDEN;
135                 }
136                 /* And do the access */
137                 return TRAP_UNHANDLED;
138         } else {
139                 cpu = mmio_read32(gicd_base + GICD_IROUTER + 8 * irq);
140                 access->val = arm_cpu_phys2virt(cpu);
141                 return TRAP_HANDLED;
142         }
143 }
144
145 int gic_handle_dist_access(struct per_cpu *cpu_data,
146                            struct mmio_access *access)
147 {
148         int ret;
149         unsigned long reg = access->addr - (unsigned long)gicd_base;
150
151         switch (reg) {
152         case REG_RANGE(GICD_IROUTER, 1024, 8):
153                 ret = handle_irq_route(cpu_data, access,
154                                 (reg - GICD_IROUTER) / 8);
155                 break;
156
157         case REG_RANGE(GICD_ICENABLER, 32, 4):
158         case REG_RANGE(GICD_ISENABLER, 32, 4):
159         case REG_RANGE(GICD_ICPENDR, 32, 4):
160         case REG_RANGE(GICD_ISPENDR, 32, 4):
161         case REG_RANGE(GICD_ICACTIVER, 32, 4):
162         case REG_RANGE(GICD_ISACTIVER, 32, 4):
163                 ret = restrict_bitmask_access(cpu_data, access,
164                                 (reg & 0x7f) / 4, 1, true);
165                 break;
166
167         case REG_RANGE(GICD_IGROUPR, 32, 4):
168                 ret = restrict_bitmask_access(cpu_data, access,
169                                 (reg & 0x7f) / 4, 1, false);
170                 break;
171
172         case REG_RANGE(GICD_ICFGR, 64, 4):
173                 ret = restrict_bitmask_access(cpu_data, access,
174                                 (reg & 0xff) / 4, 2, false);
175                 break;
176
177         case REG_RANGE(GICD_IPRIORITYR, 255, 4):
178                 ret = restrict_bitmask_access(cpu_data, access,
179                                 (reg & 0x3ff) / 4, 8, false);
180                 break;
181
182         case GICD_CTLR:
183         case GICD_TYPER:
184         case GICD_IIDR:
185         case REG_RANGE(GICD_PIDR0, 4, 4):
186         case REG_RANGE(GICD_PIDR4, 4, 4):
187         case REG_RANGE(GICD_CIDR0, 4, 4):
188                 /* Allow read access, ignore write */
189                 ret = (access->is_write ? TRAP_HANDLED : TRAP_UNHANDLED);
190                 break;
191
192         default:
193                 /* Ignore access. */
194                 ret = TRAP_HANDLED;
195         }
196
197         /* The sub-handlers return TRAP_UNHANDLED to allow the access */
198         if (ret == TRAP_UNHANDLED) {
199                 arch_mmio_access(access);
200                 ret = TRAP_HANDLED;
201         }
202
203         return ret;
204 }