]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/traps.c
arm: mmio emulation skeleton
[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 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 void access_cell_reg(struct trap_context *ctx, u8 reg, unsigned long *val,
127                      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 void dump_guest_regs(struct per_cpu *cpu_data, struct trap_context *ctx)
192 {
193         u8 reg;
194         unsigned long reg_val;
195
196         panic_printk("pc=0x%08x cpsr=0x%08x esr=0x%08x\n", ctx->pc, ctx->cpsr,
197                         ctx->esr);
198         for (reg = 0; reg < 15; reg++) {
199                 access_cell_reg(ctx, reg, &reg_val, true);
200                 panic_printk("r%d=0x%08x ", reg, reg_val);
201                 if ((reg + 1) % 4 == 0)
202                         panic_printk("\n");
203         }
204         panic_printk("\n");
205 }
206
207 static int arch_handle_hvc(struct per_cpu *cpu_data, struct trap_context *ctx)
208 {
209         unsigned long *regs = ctx->regs;
210
211         regs[0] = hypercall(regs[0], regs[1], regs[2]);
212
213         return TRAP_HANDLED;
214 }
215
216 static int arch_handle_cp15_64(struct per_cpu *cpu_data, struct trap_context *ctx)
217 {
218         unsigned long rt_val, rt2_val;
219         u32 opc1        = ctx->esr >> 16 & 0x7;
220         u32 rt2         = ctx->esr >> 10 & 0xf;
221         u32 rt          = ctx->esr >> 5 & 0xf;
222         u32 crm         = ctx->esr >> 1 & 0xf;
223         u32 read        = ctx->esr & 1;
224
225         if (!read) {
226                 access_cell_reg(ctx, rt, &rt_val, true);
227                 access_cell_reg(ctx, rt2, &rt2_val, true);
228         }
229
230 #ifdef CONFIG_ARM_GIC_V3
231         /* Trapped ICC_SGI1R write */
232         if (!read && opc1 == 0 && crm == 12) {
233                 arch_skip_instruction(ctx);
234                 return gicv3_handle_sgir_write(cpu_data,
235                                 (u64)rt2_val << 32 | rt_val);
236         }
237 #else
238         /* Avoid `unused' warning... */
239         crm = crm;
240         opc1 = opc1;
241 #endif
242
243         return TRAP_UNHANDLED;
244 }
245
246 static const trap_handler trap_handlers[38] =
247 {
248         [ESR_EC_CP15_64]        = arch_handle_cp15_64,
249         [ESR_EC_HVC]            = arch_handle_hvc,
250         [ESR_EC_DABT]           = arch_handle_dabt,
251 };
252
253 void arch_handle_trap(struct per_cpu *cpu_data, struct registers *guest_regs)
254 {
255         struct trap_context ctx;
256         u32 exception_class;
257         int ret = TRAP_UNHANDLED;
258
259         arm_read_banked_reg(ELR_hyp, ctx.pc);
260         arm_read_banked_reg(SPSR_hyp, ctx.cpsr);
261         arm_read_sysreg(ESR_EL2, ctx.esr);
262         exception_class = ESR_EC(ctx.esr);
263         ctx.regs = guest_regs->usr;
264
265         /*
266          * On some implementations, instructions that fail their condition check
267          * can trap.
268          */
269         if (arch_failed_condition(&ctx)) {
270                 arch_skip_instruction(&ctx);
271                 goto restore_context;
272         }
273
274         if (trap_handlers[exception_class])
275                 ret = trap_handlers[exception_class](cpu_data, &ctx);
276
277         switch (ret) {
278         case TRAP_UNHANDLED:
279         case TRAP_FORBIDDEN:
280                 panic_printk("FATAL: %s on CPU%d\n", (ret == TRAP_UNHANDLED ?
281                                 "unhandled trap" : "forbidden access"),
282                                 cpu_data->cpu_id);
283                 dump_guest_regs(cpu_data, &ctx);
284                 panic_park();
285         }
286
287 restore_context:
288         arm_write_banked_reg(SPSR_hyp, ctx.cpsr);
289         arm_write_banked_reg(ELR_hyp, ctx.pc);
290 }