1 /*
2  * xen/arch/arm/decode.c
3  *
4  * Instruction decoder
5  *
6  * Julien Grall <julien.grall@linaro.org>
7  * Copyright (C) 2013 Linaro Limited.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  */
19 
20 #include <xen/types.h>
21 #include <xen/sched.h>
22 #include <asm/current.h>
23 #include <asm/guest_access.h>
24 #include <xen/lib.h>
25 
26 #include "decode.h"
27 
update_dabt(struct hsr_dabt * dabt,int reg,uint8_t size,bool sign)28 static void update_dabt(struct hsr_dabt *dabt, int reg,
29                         uint8_t size, bool sign)
30 {
31     dabt->reg = reg;
32     dabt->size = size;
33     dabt->sign = sign;
34 }
35 
decode_thumb2(register_t pc,struct hsr_dabt * dabt,uint16_t hw1)36 static int decode_thumb2(register_t pc, struct hsr_dabt *dabt, uint16_t hw1)
37 {
38     uint16_t hw2;
39     uint16_t rt;
40 
41     if ( raw_copy_from_guest(&hw2, (void *__user)(pc + 2), sizeof (hw2)) )
42         return -EFAULT;
43 
44     rt = (hw2 >> 12) & 0xf;
45 
46     switch ( (hw1 >> 9) & 0xf )
47     {
48     case 12:
49     {
50         bool sign = (hw1 & (1u << 8));
51         bool load = (hw1 & (1u << 4));
52 
53         if ( (hw1 & 0x0110) == 0x0100 )
54             /* NEON instruction */
55             goto bad_thumb2;
56 
57         if ( (hw1 & 0x0070) == 0x0070 )
58             /* Undefined opcodes */
59             goto bad_thumb2;
60 
61         /* Store/Load single data item */
62         if ( rt == 15 )
63             /* XXX: Rt == 15 is only invalid for store instruction */
64             goto bad_thumb2;
65 
66         if ( !load && sign )
67             /* Store instruction doesn't support sign extension */
68             goto bad_thumb2;
69 
70         update_dabt(dabt, rt, (hw1 >> 5) & 3, sign);
71 
72         break;
73     }
74     default:
75         goto bad_thumb2;
76     }
77 
78     return 0;
79 
80 bad_thumb2:
81     gprintk(XENLOG_ERR, "unhandled THUMB2 instruction 0x%x%x\n", hw1, hw2);
82 
83     return 1;
84 }
85 
decode_thumb(register_t pc,struct hsr_dabt * dabt)86 static int decode_thumb(register_t pc, struct hsr_dabt *dabt)
87 {
88     uint16_t instr;
89 
90     if ( raw_copy_from_guest(&instr, (void * __user)pc, sizeof (instr)) )
91         return -EFAULT;
92 
93     switch ( instr >> 12 )
94     {
95     case 5:
96     {
97         /* Load/Store register */
98         uint16_t opB = (instr >> 9) & 0x7;
99         int reg = instr & 7;
100 
101         switch ( opB & 0x3 )
102         {
103         case 0: /* Non-signed word */
104             update_dabt(dabt, reg, 2, false);
105             break;
106         case 1: /* Non-signed halfword */
107             update_dabt(dabt, reg, 1, false);
108             break;
109         case 2: /* Non-signed byte */
110             update_dabt(dabt, reg, 0, false);
111             break;
112         case 3: /* Signed byte */
113             update_dabt(dabt, reg, 0, true);
114             break;
115         }
116 
117         break;
118     }
119     case 6:
120         /* Load/Store word immediate offset */
121         update_dabt(dabt, instr & 7, 2, false);
122         break;
123     case 7:
124         /* Load/Store byte immediate offset */
125         update_dabt(dabt, instr & 7, 0, false);
126         break;
127     case 8:
128         /* Load/Store halfword immediate offset */
129         update_dabt(dabt, instr & 7, 1, false);
130         break;
131     case 9:
132         /* Load/Store word sp offset */
133         update_dabt(dabt, (instr >> 8) & 7, 2, false);
134         break;
135     case 14:
136         if ( instr & (1 << 11) )
137             return decode_thumb2(pc, dabt, instr);
138         goto bad_thumb;
139     case 15:
140         return decode_thumb2(pc, dabt, instr);
141     default:
142         goto bad_thumb;
143     }
144 
145     return 0;
146 
147 bad_thumb:
148     gprintk(XENLOG_ERR, "unhandled THUMB instruction 0x%x\n", instr);
149     return 1;
150 }
151 
decode_instruction(const struct cpu_user_regs * regs,struct hsr_dabt * dabt)152 int decode_instruction(const struct cpu_user_regs *regs, struct hsr_dabt *dabt)
153 {
154     if ( is_32bit_domain(current->domain) && regs->cpsr & PSR_THUMB )
155         return decode_thumb(regs->pc, dabt);
156 
157     /* TODO: Handle ARM instruction */
158     gprintk(XENLOG_ERR, "unhandled ARM instruction\n");
159 
160     return 1;
161 }
162 
163 /*
164  * Local variables:
165  * mode: C
166  * c-file-style: "BSD"
167  * c-basic-offset: 4
168  * tab-width: 4
169  * indent-tabs-mode: nil
170  * End:
171  */
172