]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/traps.c
arm: GICv3: filter the guests' SGIs
[jailhouse.git] / hypervisor / arch / arm / traps.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  * Condition check code is copied from Linux's
13  * - arch/arm/kernel/opcodes.c
14  * - arch/arm/kvm/emulate.c
15  */
16
17 #include <asm/control.h>
18 #include <asm/gic_common.h>
19 #include <asm/platform.h>
20 #include <asm/traps.h>
21 #include <asm/sysregs.h>
22 #include <jailhouse/printk.h>
23 #include <jailhouse/control.h>
24
25 /*
26  * condition code lookup table
27  * index into the table is test code: EQ, NE, ... LT, GT, AL, NV
28  *
29  * bit position in short is condition code: NZCV
30  */
31 static const unsigned short cc_map[16] = {
32         0xF0F0,                 /* EQ == Z set            */
33         0x0F0F,                 /* NE                     */
34         0xCCCC,                 /* CS == C set            */
35         0x3333,                 /* CC                     */
36         0xFF00,                 /* MI == N set            */
37         0x00FF,                 /* PL                     */
38         0xAAAA,                 /* VS == V set            */
39         0x5555,                 /* VC                     */
40         0x0C0C,                 /* HI == C set && Z clear */
41         0xF3F3,                 /* LS == C clear || Z set */
42         0xAA55,                 /* GE == (N==V)           */
43         0x55AA,                 /* LT == (N!=V)           */
44         0x0A05,                 /* GT == (!Z && (N==V))   */
45         0xF5FA,                 /* LE == (Z || (N!=V))    */
46         0xFFFF,                 /* AL always              */
47         0                       /* NV                     */
48 };
49
50 /* Check condition field either from ESR or from SPSR in thumb mode */
51 static bool arch_failed_condition(struct trap_context *ctx)
52 {
53         u32 class = ESR_EC(ctx->esr);
54         u32 icc = ESR_ICC(ctx->esr);
55         u32 cpsr = ctx->cpsr;
56         u32 flags = cpsr >> 28;
57         u32 cond;
58         /*
59          * Trapped instruction is unconditional, already passed the condition
60          * check, or is invalid
61          */
62         if (class & 0x30 || class == 0)
63                 return false;
64
65         /* Is condition field valid? */
66         if (icc & ESR_ICC_CV_BIT) {
67                 cond = ESR_ICC_COND(icc);
68         } else {
69                 /* This can happen in Thumb mode: examine IT state. */
70                 unsigned long it = PSR_IT(cpsr);
71
72                 /* it == 0 => unconditional. */
73                 if (it == 0)
74                         return false;
75
76                 /* The cond for this insn works out as the top 4 bits. */
77                 cond = (it >> 4);
78         }
79
80         /* Compare the apsr flags with the condition code */
81         if ((cc_map[cond] >> flags) & 1)
82                 return false;
83
84         return true;
85 }
86
87 /*
88  * When exceptions occur while instructions are executed in Thumb IF-THEN
89  * blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have
90  * to do this little bit of work manually. The fields map like this:
91  *
92  * IT[7:0] -> CPSR[26:25],CPSR[15:10]
93  */
94 static void arch_advance_itstate(struct trap_context *ctx)
95 {
96         unsigned long itbits, cond;
97         unsigned long cpsr = ctx->cpsr;
98
99         if (!(cpsr & PSR_IT_MASK(0xff)))
100                 return;
101
102         itbits = PSR_IT(cpsr);
103         cond = itbits >> 5;
104
105         if ((itbits & 0x7) == 0)
106                 /* One instruction left in the block, next itstate is 0 */
107                 itbits = cond = 0;
108         else
109                 itbits = (itbits << 1) & 0x1f;
110
111         itbits |= (cond << 5);
112         cpsr &= ~PSR_IT_MASK(0xff);
113         cpsr |= PSR_IT_MASK(itbits);
114
115         ctx->cpsr = cpsr;
116 }
117
118 static void arch_skip_instruction(struct trap_context *ctx)
119 {
120         u32 instruction_length = ESR_IL(ctx->esr);
121
122         ctx->pc += (instruction_length ? 4 : 2);
123         arch_advance_itstate(ctx);
124 }
125
126 static void access_cell_reg(struct trap_context *ctx, u8 reg,
127                                 unsigned long *val, bool is_read)
128 {
129         unsigned long mode = ctx->cpsr & PSR_MODE_MASK;
130
131         switch (reg) {
132         case 0 ... 7:
133                 access_usr_reg(ctx, reg, val, is_read);
134                 break;
135         case 8 ... 12:
136                 if (mode == PSR_FIQ_MODE)
137                         access_fiq_reg(reg, val, is_read);
138                 else
139                         access_usr_reg(ctx, reg, val, is_read);
140                 break;
141         case 13 ... 14:
142                 switch (mode) {
143                 case PSR_USR_MODE:
144                 case PSR_SYS_MODE:
145                         /*
146                          * lr is saved on the stack, as it is not banked in HYP
147                          * mode. sp is banked, so lr is at offset 13 in the USR
148                          * regs.
149                          */
150                         if (reg == 13)
151                                 access_banked_reg(usr, reg, val, is_read);
152                         else
153                                 access_usr_reg(ctx, 13, val, is_read);
154                         break;
155                 case PSR_SVC_MODE:
156                         access_banked_reg(svc, reg, val, is_read);
157                         break;
158                 case PSR_UND_MODE:
159                         access_banked_reg(und, reg, val, is_read);
160                         break;
161                 case PSR_ABT_MODE:
162                         access_banked_reg(abt, reg, val, is_read);
163                         break;
164                 case PSR_IRQ_MODE:
165                         access_banked_reg(irq, reg, val, is_read);
166                         break;
167                 case PSR_FIQ_MODE:
168                         access_banked_reg(fiq, reg, val, is_read);
169                         break;
170                 }
171                 break;
172         case 15:
173                 /*
174                  * A trapped instruction that accesses the PC? Probably a bug,
175                  * but nothing seems to prevent it.
176                  */
177                 printk("WARNING: trapped instruction attempted to explicitly "
178                        "access the PC.\n");
179                 if (is_read)
180                         *val = ctx->pc;
181                 else
182                         ctx->pc = *val;
183                 break;
184         default:
185                 /* Programming error */
186                 printk("ERROR: attempt to write register %d\n", reg);
187                 break;
188         }
189 }
190
191 static int arch_handle_hvc(struct per_cpu *cpu_data, struct trap_context *ctx)
192 {
193         unsigned long *regs = ctx->regs;
194
195         regs[0] = hypercall(regs[0], regs[1], regs[2]);
196
197         return TRAP_HANDLED;
198 }
199
200 static int arch_handle_cp15_64(struct per_cpu *cpu_data, struct trap_context *ctx)
201 {
202         unsigned long rt_val, rt2_val;
203         u32 opc1        = ctx->esr >> 16 & 0x7;
204         u32 rt2         = ctx->esr >> 10 & 0xf;
205         u32 rt          = ctx->esr >> 5 & 0xf;
206         u32 crm         = ctx->esr >> 1 & 0xf;
207         u32 read        = ctx->esr & 1;
208
209         if (!read) {
210                 access_cell_reg(ctx, rt, &rt_val, true);
211                 access_cell_reg(ctx, rt2, &rt2_val, true);
212         }
213
214 #ifdef CONFIG_ARM_GIC_V3
215         /* Trapped ICC_SGI1R write */
216         if (!read && opc1 == 0 && crm == 12) {
217                 arch_skip_instruction(ctx);
218                 return gicv3_handle_sgir_write(cpu_data,
219                                 (u64)rt2_val << 32 | rt_val);
220         }
221 #else
222         /* Avoid `unused' warning... */
223         crm = crm;
224         opc1 = opc1;
225 #endif
226
227         return TRAP_UNHANDLED;
228 }
229
230 static const trap_handler trap_handlers[38] =
231 {
232         [ESR_EC_CP15_64]        = arch_handle_cp15_64,
233         [ESR_EC_HVC]            = arch_handle_hvc,
234 };
235
236 void arch_handle_trap(struct per_cpu *cpu_data, struct registers *guest_regs)
237 {
238         struct trap_context ctx;
239         u32 exception_class;
240         int ret = TRAP_UNHANDLED;
241
242         arm_read_banked_reg(ELR_hyp, ctx.pc);
243         arm_read_banked_reg(SPSR_hyp, ctx.cpsr);
244         arm_read_sysreg(ESR_EL2, ctx.esr);
245         exception_class = ESR_EC(ctx.esr);
246         ctx.regs = guest_regs->usr;
247
248         /*
249          * On some implementations, instructions that fail their condition check
250          * can trap.
251          */
252         if (arch_failed_condition(&ctx)) {
253                 arch_skip_instruction(&ctx);
254                 goto restore_context;
255         }
256
257         if (trap_handlers[exception_class])
258                 ret = trap_handlers[exception_class](cpu_data, &ctx);
259
260         if (ret != TRAP_HANDLED) {
261                 panic_printk("CPU%d: Unhandled HYP trap, syndrome 0x%x\n",
262                                 cpu_data->cpu_id, ctx.esr);
263                 while(1);
264         }
265
266 restore_context:
267         arm_write_banked_reg(SPSR_hyp, ctx.cpsr);
268         arm_write_banked_reg(ELR_hyp, ctx.pc);
269 }