]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/traps.c
arm: read/write the banked registers
[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
13 #include <asm/control.h>
14 #include <asm/traps.h>
15 #include <asm/sysregs.h>
16 #include <jailhouse/printk.h>
17 #include <jailhouse/control.h>
18
19 static void access_cell_reg(struct trap_context *ctx, u8 reg,
20                                 unsigned long *val, bool is_read)
21 {
22         unsigned long mode = ctx->cpsr & PSR_MODE_MASK;
23
24         switch (reg) {
25         case 0 ... 7:
26                 access_usr_reg(ctx, reg, val, is_read);
27                 break;
28         case 8 ... 12:
29                 if (mode == PSR_FIQ_MODE)
30                         access_fiq_reg(reg, val, is_read);
31                 else
32                         access_usr_reg(ctx, reg, val, is_read);
33                 break;
34         case 13 ... 14:
35                 switch (mode) {
36                 case PSR_USR_MODE:
37                 case PSR_SYS_MODE:
38                         /*
39                          * lr is saved on the stack, as it is not banked in HYP
40                          * mode. sp is banked, so lr is at offset 13 in the USR
41                          * regs.
42                          */
43                         if (reg == 13)
44                                 access_banked_reg(usr, reg, val, is_read);
45                         else
46                                 access_usr_reg(ctx, 13, val, is_read);
47                         break;
48                 case PSR_SVC_MODE:
49                         access_banked_reg(svc, reg, val, is_read);
50                         break;
51                 case PSR_UND_MODE:
52                         access_banked_reg(und, reg, val, is_read);
53                         break;
54                 case PSR_ABT_MODE:
55                         access_banked_reg(abt, reg, val, is_read);
56                         break;
57                 case PSR_IRQ_MODE:
58                         access_banked_reg(irq, reg, val, is_read);
59                         break;
60                 case PSR_FIQ_MODE:
61                         access_banked_reg(fiq, reg, val, is_read);
62                         break;
63                 }
64                 break;
65         case 15:
66                 /*
67                  * A trapped instruction that accesses the PC? Probably a bug,
68                  * but nothing seems to prevent it.
69                  */
70                 printk("WARNING: trapped instruction attempted to explicitly "
71                        "access the PC.\n");
72                 if (is_read)
73                         *val = ctx->pc;
74                 else
75                         ctx->pc = *val;
76                 break;
77         default:
78                 /* Programming error */
79                 printk("ERROR: attempt to write register %d\n", reg);
80                 break;
81         }
82 }
83
84 static int arch_handle_hvc(struct per_cpu *cpu_data, struct trap_context *ctx)
85 {
86         unsigned long *regs = ctx->regs;
87
88         regs[0] = hypercall(regs[0], regs[1], regs[2]);
89
90         return TRAP_HANDLED;
91 }
92
93 static const trap_handler trap_handlers[38] =
94 {
95         [ESR_EC_HVC]            = arch_handle_hvc,
96 };
97
98 void arch_handle_trap(struct per_cpu *cpu_data, struct registers *guest_regs)
99 {
100         struct trap_context ctx;
101         u32 exception_class;
102         int ret = TRAP_UNHANDLED;
103
104         arm_read_banked_reg(ELR_hyp, ctx.pc);
105         arm_read_banked_reg(SPSR_hyp, ctx.cpsr);
106         arm_read_sysreg(ESR_EL2, ctx.esr);
107         exception_class = ESR_EC(ctx.esr);
108         ctx.regs = guest_regs->usr;
109
110         if (trap_handlers[exception_class])
111                 ret = trap_handlers[exception_class](cpu_data, &ctx);
112
113         if (ret != TRAP_HANDLED) {
114                 panic_printk("CPU%d: Unhandled HYP trap, syndrome 0x%x\n",
115                                 cpu_data->cpu_id, ctx.esr);
116                 while(1);
117         }
118
119         arm_write_banked_reg(ELR_hyp, ctx.pc);
120 }