Commit | Line | Data |
---|---|---|
a17ae4c3 | 1 | // SPDX-License-Identifier: GPL-2.0 |
bb11e3bd | 2 | /* |
bb11e3bd MS |
3 | * Disassemble s390 instructions. |
4 | * | |
5 | * Copyright IBM Corp. 2007 | |
6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | |
7 | */ | |
8 | ||
9 | #include <linux/sched.h> | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/string.h> | |
12 | #include <linux/errno.h> | |
13 | #include <linux/ptrace.h> | |
14 | #include <linux/timer.h> | |
15 | #include <linux/mm.h> | |
16 | #include <linux/smp.h> | |
bb11e3bd MS |
17 | #include <linux/init.h> |
18 | #include <linux/interrupt.h> | |
19 | #include <linux/delay.h> | |
3994a52b | 20 | #include <linux/export.h> |
bb11e3bd MS |
21 | #include <linux/kallsyms.h> |
22 | #include <linux/reboot.h> | |
23 | #include <linux/kprobes.h> | |
79df3c19 | 24 | #include <linux/kdebug.h> |
7c0f6ba6 | 25 | #include <linux/uaccess.h> |
8bc1e4ec | 26 | #include <linux/atomic.h> |
648ae35c | 27 | #include <asm/dis.h> |
bb11e3bd | 28 | #include <asm/io.h> |
bb11e3bd | 29 | #include <asm/cpcmd.h> |
bb11e3bd MS |
30 | #include <asm/lowcore.h> |
31 | #include <asm/debug.h> | |
d7b250e2 | 32 | #include <asm/irq.h> |
bb11e3bd | 33 | |
8bc1e4ec HC |
34 | /* Type of operand */ |
35 | #define OPERAND_GPR 0x1 /* Operand printed as %rx */ | |
36 | #define OPERAND_FPR 0x2 /* Operand printed as %fx */ | |
37 | #define OPERAND_AR 0x4 /* Operand printed as %ax */ | |
38 | #define OPERAND_CR 0x8 /* Operand printed as %cx */ | |
39 | #define OPERAND_VR 0x10 /* Operand printed as %vx */ | |
40 | #define OPERAND_DISP 0x20 /* Operand printed as displacement */ | |
41 | #define OPERAND_BASE 0x40 /* Operand printed as base register */ | |
42 | #define OPERAND_INDEX 0x80 /* Operand printed as index register */ | |
43 | #define OPERAND_PCREL 0x100 /* Operand printed as pc-relative symbol */ | |
44 | #define OPERAND_SIGNED 0x200 /* Operand printed as signed value */ | |
45 | #define OPERAND_LENGTH 0x400 /* Operand printed as length (+1) */ | |
46 | ||
47 | struct s390_operand { | |
48 | unsigned char bits; /* The number of bits in the operand. */ | |
49 | unsigned char shift; /* The number of bits to shift. */ | |
50 | unsigned short flags; /* One bit syntax flags. */ | |
51 | }; | |
52 | ||
53 | struct s390_insn { | |
54 | union { | |
55 | const char name[5]; | |
56 | struct { | |
57 | unsigned char zero; | |
58 | unsigned int offset; | |
59 | } __packed; | |
60 | }; | |
61 | unsigned char opfrag; | |
62 | unsigned char format; | |
63 | }; | |
64 | ||
65 | struct s390_opcode_offset { | |
66 | unsigned char opcode; | |
67 | unsigned char mask; | |
68 | unsigned char byte; | |
69 | unsigned short offset; | |
70 | unsigned short count; | |
71 | } __packed; | |
72 | ||
bb11e3bd | 73 | enum { |
8bc1e4ec | 74 | UNUSED, |
bb11e3bd MS |
75 | A_8, /* Access reg. starting at position 8 */ |
76 | A_12, /* Access reg. starting at position 12 */ | |
77 | A_24, /* Access reg. starting at position 24 */ | |
78 | A_28, /* Access reg. starting at position 28 */ | |
bb11e3bd MS |
79 | B_16, /* Base register starting at position 16 */ |
80 | B_32, /* Base register starting at position 32 */ | |
8bc1e4ec HC |
81 | C_8, /* Control reg. starting at position 8 */ |
82 | C_12, /* Control reg. starting at position 12 */ | |
83 | D20_20, /* 20 bit displacement starting at 20 */ | |
bb11e3bd MS |
84 | D_20, /* Displacement starting at position 20 */ |
85 | D_36, /* Displacement starting at position 36 */ | |
8bc1e4ec HC |
86 | F_8, /* FPR starting at position 8 */ |
87 | F_12, /* FPR starting at position 12 */ | |
88 | F_16, /* FPR starting at position 16 */ | |
89 | F_24, /* FPR starting at position 24 */ | |
90 | F_28, /* FPR starting at position 28 */ | |
91 | F_32, /* FPR starting at position 32 */ | |
92 | I8_8, /* 8 bit signed value starting at 8 */ | |
93 | I8_32, /* 8 bit signed value starting at 32 */ | |
94 | I16_16, /* 16 bit signed value starting at 16 */ | |
95 | I16_32, /* 16 bit signed value starting at 32 */ | |
96 | I32_16, /* 32 bit signed value starting at 16 */ | |
97 | J12_12, /* 12 bit PC relative offset at 12 */ | |
98 | J16_16, /* 16 bit PC relative offset at 16 */ | |
99 | J16_32, /* 16 bit PC relative offset at 32 */ | |
100 | J24_24, /* 24 bit PC relative offset at 24 */ | |
101 | J32_16, /* 32 bit PC relative offset at 16 */ | |
bb11e3bd MS |
102 | L4_8, /* 4 bit length starting at position 8 */ |
103 | L4_12, /* 4 bit length starting at position 12 */ | |
104 | L8_8, /* 8 bit length starting at position 8 */ | |
8bc1e4ec HC |
105 | R_8, /* GPR starting at position 8 */ |
106 | R_12, /* GPR starting at position 12 */ | |
107 | R_16, /* GPR starting at position 16 */ | |
108 | R_24, /* GPR starting at position 24 */ | |
109 | R_28, /* GPR starting at position 28 */ | |
bb11e3bd MS |
110 | U4_8, /* 4 bit unsigned value starting at 8 */ |
111 | U4_12, /* 4 bit unsigned value starting at 12 */ | |
112 | U4_16, /* 4 bit unsigned value starting at 16 */ | |
113 | U4_20, /* 4 bit unsigned value starting at 20 */ | |
c68dba20 HC |
114 | U4_24, /* 4 bit unsigned value starting at 24 */ |
115 | U4_28, /* 4 bit unsigned value starting at 28 */ | |
618708ff | 116 | U4_32, /* 4 bit unsigned value starting at 32 */ |
c68dba20 | 117 | U4_36, /* 4 bit unsigned value starting at 36 */ |
bb11e3bd MS |
118 | U8_8, /* 8 bit unsigned value starting at 8 */ |
119 | U8_16, /* 8 bit unsigned value starting at 16 */ | |
618708ff | 120 | U8_24, /* 8 bit unsigned value starting at 24 */ |
e0d281d0 | 121 | U8_28, /* 8 bit unsigned value starting at 28 */ |
618708ff | 122 | U8_32, /* 8 bit unsigned value starting at 32 */ |
8bc1e4ec HC |
123 | U12_16, /* 12 bit unsigned value starting at 16 */ |
124 | U16_16, /* 16 bit unsigned value starting at 16 */ | |
125 | U16_32, /* 16 bit unsigned value starting at 32 */ | |
126 | U32_16, /* 32 bit unsigned value starting at 16 */ | |
127 | VX_12, /* Vector index register starting at position 12 */ | |
128 | V_8, /* Vector reg. starting at position 8 */ | |
129 | V_12, /* Vector reg. starting at position 12 */ | |
130 | V_16, /* Vector reg. starting at position 16 */ | |
131 | V_32, /* Vector reg. starting at position 32 */ | |
132 | X_12, /* Index register starting at position 12 */ | |
bb11e3bd MS |
133 | }; |
134 | ||
8bc1e4ec HC |
135 | static const struct s390_operand operands[] = { |
136 | [UNUSED] = { 0, 0, 0 }, | |
bb11e3bd MS |
137 | [A_8] = { 4, 8, OPERAND_AR }, |
138 | [A_12] = { 4, 12, OPERAND_AR }, | |
139 | [A_24] = { 4, 24, OPERAND_AR }, | |
140 | [A_28] = { 4, 28, OPERAND_AR }, | |
bb11e3bd MS |
141 | [B_16] = { 4, 16, OPERAND_BASE | OPERAND_GPR }, |
142 | [B_32] = { 4, 32, OPERAND_BASE | OPERAND_GPR }, | |
8bc1e4ec HC |
143 | [C_8] = { 4, 8, OPERAND_CR }, |
144 | [C_12] = { 4, 12, OPERAND_CR }, | |
145 | [D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED }, | |
bb11e3bd MS |
146 | [D_20] = { 12, 20, OPERAND_DISP }, |
147 | [D_36] = { 12, 36, OPERAND_DISP }, | |
8bc1e4ec HC |
148 | [F_8] = { 4, 8, OPERAND_FPR }, |
149 | [F_12] = { 4, 12, OPERAND_FPR }, | |
150 | [F_16] = { 4, 16, OPERAND_FPR }, | |
151 | [F_24] = { 4, 24, OPERAND_FPR }, | |
152 | [F_28] = { 4, 28, OPERAND_FPR }, | |
153 | [F_32] = { 4, 32, OPERAND_FPR }, | |
154 | [I8_8] = { 8, 8, OPERAND_SIGNED }, | |
155 | [I8_32] = { 8, 32, OPERAND_SIGNED }, | |
156 | [I16_16] = { 16, 16, OPERAND_SIGNED }, | |
157 | [I16_32] = { 16, 32, OPERAND_SIGNED }, | |
158 | [I32_16] = { 32, 16, OPERAND_SIGNED }, | |
159 | [J12_12] = { 12, 12, OPERAND_PCREL }, | |
160 | [J16_16] = { 16, 16, OPERAND_PCREL }, | |
161 | [J16_32] = { 16, 32, OPERAND_PCREL }, | |
162 | [J24_24] = { 24, 24, OPERAND_PCREL }, | |
163 | [J32_16] = { 32, 16, OPERAND_PCREL }, | |
bb11e3bd | 164 | [L4_8] = { 4, 8, OPERAND_LENGTH }, |
8bc1e4ec | 165 | [L4_12] = { 4, 12, OPERAND_LENGTH }, |
bb11e3bd | 166 | [L8_8] = { 8, 8, OPERAND_LENGTH }, |
8bc1e4ec HC |
167 | [R_8] = { 4, 8, OPERAND_GPR }, |
168 | [R_12] = { 4, 12, OPERAND_GPR }, | |
169 | [R_16] = { 4, 16, OPERAND_GPR }, | |
170 | [R_24] = { 4, 24, OPERAND_GPR }, | |
171 | [R_28] = { 4, 28, OPERAND_GPR }, | |
bb11e3bd | 172 | [U4_8] = { 4, 8, 0 }, |
8bc1e4ec HC |
173 | [U4_12] = { 4, 12, 0 }, |
174 | [U4_16] = { 4, 16, 0 }, | |
175 | [U4_20] = { 4, 20, 0 }, | |
176 | [U4_24] = { 4, 24, 0 }, | |
177 | [U4_28] = { 4, 28, 0 }, | |
178 | [U4_32] = { 4, 32, 0 }, | |
179 | [U4_36] = { 4, 36, 0 }, | |
bb11e3bd | 180 | [U8_8] = { 8, 8, 0 }, |
8bc1e4ec HC |
181 | [U8_16] = { 8, 16, 0 }, |
182 | [U8_24] = { 8, 24, 0 }, | |
183 | [U8_28] = { 8, 28, 0 }, | |
184 | [U8_32] = { 8, 32, 0 }, | |
185 | [U12_16] = { 12, 16, 0 }, | |
bb11e3bd | 186 | [U16_16] = { 16, 16, 0 }, |
618708ff | 187 | [U16_32] = { 16, 32, 0 }, |
bb11e3bd | 188 | [U32_16] = { 32, 16, 0 }, |
8bc1e4ec HC |
189 | [VX_12] = { 4, 12, OPERAND_INDEX | OPERAND_VR }, |
190 | [V_8] = { 4, 8, OPERAND_VR }, | |
191 | [V_12] = { 4, 12, OPERAND_VR }, | |
192 | [V_16] = { 4, 16, OPERAND_VR }, | |
193 | [V_32] = { 4, 32, OPERAND_VR }, | |
194 | [X_12] = { 4, 12, OPERAND_INDEX | OPERAND_GPR }, | |
bb11e3bd MS |
195 | }; |
196 | ||
8bc1e4ec HC |
197 | static const unsigned char formats[][6] = { |
198 | [INSTR_E] = { 0, 0, 0, 0, 0, 0 }, | |
199 | [INSTR_IE_UU] = { U4_24, U4_28, 0, 0, 0, 0 }, | |
200 | [INSTR_MII_UPP] = { U4_8, J12_12, J24_24 }, | |
201 | [INSTR_RIE_R0IU] = { R_8, I16_16, U4_32, 0, 0, 0 }, | |
202 | [INSTR_RIE_R0UU] = { R_8, U16_16, U4_32, 0, 0, 0 }, | |
203 | [INSTR_RIE_RRI0] = { R_8, R_12, I16_16, 0, 0, 0 }, | |
204 | [INSTR_RIE_RRP] = { R_8, R_12, J16_16, 0, 0, 0 }, | |
205 | [INSTR_RIE_RRPU] = { R_8, R_12, U4_32, J16_16, 0, 0 }, | |
206 | [INSTR_RIE_RRUUU] = { R_8, R_12, U8_16, U8_24, U8_32, 0 }, | |
207 | [INSTR_RIE_RUI0] = { R_8, I16_16, U4_12, 0, 0, 0 }, | |
208 | [INSTR_RIE_RUPI] = { R_8, I8_32, U4_12, J16_16, 0, 0 }, | |
209 | [INSTR_RIE_RUPU] = { R_8, U8_32, U4_12, J16_16, 0, 0 }, | |
210 | [INSTR_RIL_RI] = { R_8, I32_16, 0, 0, 0, 0 }, | |
211 | [INSTR_RIL_RP] = { R_8, J32_16, 0, 0, 0, 0 }, | |
212 | [INSTR_RIL_RU] = { R_8, U32_16, 0, 0, 0, 0 }, | |
213 | [INSTR_RIL_UP] = { U4_8, J32_16, 0, 0, 0, 0 }, | |
214 | [INSTR_RIS_RURDI] = { R_8, I8_32, U4_12, D_20, B_16, 0 }, | |
215 | [INSTR_RIS_RURDU] = { R_8, U8_32, U4_12, D_20, B_16, 0 }, | |
216 | [INSTR_RI_RI] = { R_8, I16_16, 0, 0, 0, 0 }, | |
217 | [INSTR_RI_RP] = { R_8, J16_16, 0, 0, 0, 0 }, | |
218 | [INSTR_RI_RU] = { R_8, U16_16, 0, 0, 0, 0 }, | |
219 | [INSTR_RI_UP] = { U4_8, J16_16, 0, 0, 0, 0 }, | |
220 | [INSTR_RRE_00] = { 0, 0, 0, 0, 0, 0 }, | |
221 | [INSTR_RRE_AA] = { A_24, A_28, 0, 0, 0, 0 }, | |
222 | [INSTR_RRE_AR] = { A_24, R_28, 0, 0, 0, 0 }, | |
223 | [INSTR_RRE_F0] = { F_24, 0, 0, 0, 0, 0 }, | |
224 | [INSTR_RRE_FF] = { F_24, F_28, 0, 0, 0, 0 }, | |
225 | [INSTR_RRE_FR] = { F_24, R_28, 0, 0, 0, 0 }, | |
226 | [INSTR_RRE_R0] = { R_24, 0, 0, 0, 0, 0 }, | |
227 | [INSTR_RRE_RA] = { R_24, A_28, 0, 0, 0, 0 }, | |
228 | [INSTR_RRE_RF] = { R_24, F_28, 0, 0, 0, 0 }, | |
229 | [INSTR_RRE_RR] = { R_24, R_28, 0, 0, 0, 0 }, | |
230 | [INSTR_RRF_0UFF] = { F_24, F_28, U4_20, 0, 0, 0 }, | |
231 | [INSTR_RRF_0URF] = { R_24, F_28, U4_20, 0, 0, 0 }, | |
232 | [INSTR_RRF_F0FF] = { F_16, F_24, F_28, 0, 0, 0 }, | |
233 | [INSTR_RRF_F0FF2] = { F_24, F_16, F_28, 0, 0, 0 }, | |
234 | [INSTR_RRF_F0FR] = { F_24, F_16, R_28, 0, 0, 0 }, | |
235 | [INSTR_RRF_FFRU] = { F_24, F_16, R_28, U4_20, 0, 0 }, | |
236 | [INSTR_RRF_FUFF] = { F_24, F_16, F_28, U4_20, 0, 0 }, | |
237 | [INSTR_RRF_FUFF2] = { F_24, F_28, F_16, U4_20, 0, 0 }, | |
238 | [INSTR_RRF_R0RR] = { R_24, R_16, R_28, 0, 0, 0 }, | |
239 | [INSTR_RRF_R0RR2] = { R_24, R_28, R_16, 0, 0, 0 }, | |
240 | [INSTR_RRF_RURR] = { R_24, R_28, R_16, U4_20, 0, 0 }, | |
241 | [INSTR_RRF_RURR2] = { R_24, R_16, R_28, U4_20, 0, 0 }, | |
242 | [INSTR_RRF_U0FF] = { F_24, U4_16, F_28, 0, 0, 0 }, | |
243 | [INSTR_RRF_U0RF] = { R_24, U4_16, F_28, 0, 0, 0 }, | |
244 | [INSTR_RRF_U0RR] = { R_24, R_28, U4_16, 0, 0, 0 }, | |
245 | [INSTR_RRF_UUFF] = { F_24, U4_16, F_28, U4_20, 0, 0 }, | |
246 | [INSTR_RRF_UUFR] = { F_24, U4_16, R_28, U4_20, 0, 0 }, | |
247 | [INSTR_RRF_UURF] = { R_24, U4_16, F_28, U4_20, 0, 0 }, | |
248 | [INSTR_RRS_RRRDU] = { R_8, R_12, U4_32, D_20, B_16 }, | |
249 | [INSTR_RR_FF] = { F_8, F_12, 0, 0, 0, 0 }, | |
250 | [INSTR_RR_R0] = { R_8, 0, 0, 0, 0, 0 }, | |
251 | [INSTR_RR_RR] = { R_8, R_12, 0, 0, 0, 0 }, | |
252 | [INSTR_RR_U0] = { U8_8, 0, 0, 0, 0, 0 }, | |
253 | [INSTR_RR_UR] = { U4_8, R_12, 0, 0, 0, 0 }, | |
254 | [INSTR_RSI_RRP] = { R_8, R_12, J16_16, 0, 0, 0 }, | |
255 | [INSTR_RSL_LRDFU] = { F_32, D_20, L8_8, B_16, U4_36, 0 }, | |
256 | [INSTR_RSL_R0RD] = { D_20, L4_8, B_16, 0, 0, 0 }, | |
257 | [INSTR_RSY_AARD] = { A_8, A_12, D20_20, B_16, 0, 0 }, | |
258 | [INSTR_RSY_CCRD] = { C_8, C_12, D20_20, B_16, 0, 0 }, | |
259 | [INSTR_RSY_RDRU] = { R_8, D20_20, B_16, U4_12, 0, 0 }, | |
260 | [INSTR_RSY_RRRD] = { R_8, R_12, D20_20, B_16, 0, 0 }, | |
261 | [INSTR_RSY_RURD] = { R_8, U4_12, D20_20, B_16, 0, 0 }, | |
262 | [INSTR_RSY_RURD2] = { R_8, D20_20, B_16, U4_12, 0, 0 }, | |
263 | [INSTR_RS_AARD] = { A_8, A_12, D_20, B_16, 0, 0 }, | |
264 | [INSTR_RS_CCRD] = { C_8, C_12, D_20, B_16, 0, 0 }, | |
265 | [INSTR_RS_R0RD] = { R_8, D_20, B_16, 0, 0, 0 }, | |
266 | [INSTR_RS_RRRD] = { R_8, R_12, D_20, B_16, 0, 0 }, | |
267 | [INSTR_RS_RURD] = { R_8, U4_12, D_20, B_16, 0, 0 }, | |
268 | [INSTR_RXE_FRRD] = { F_8, D_20, X_12, B_16, 0, 0 }, | |
269 | [INSTR_RXE_RRRDU] = { R_8, D_20, X_12, B_16, U4_32, 0 }, | |
270 | [INSTR_RXF_FRRDF] = { F_32, F_8, D_20, X_12, B_16, 0 }, | |
271 | [INSTR_RXY_FRRD] = { F_8, D20_20, X_12, B_16, 0, 0 }, | |
272 | [INSTR_RXY_RRRD] = { R_8, D20_20, X_12, B_16, 0, 0 }, | |
273 | [INSTR_RXY_URRD] = { U4_8, D20_20, X_12, B_16, 0, 0 }, | |
274 | [INSTR_RX_FRRD] = { F_8, D_20, X_12, B_16, 0, 0 }, | |
275 | [INSTR_RX_RRRD] = { R_8, D_20, X_12, B_16, 0, 0 }, | |
276 | [INSTR_RX_URRD] = { U4_8, D_20, X_12, B_16, 0, 0 }, | |
277 | [INSTR_SIL_RDI] = { D_20, B_16, I16_32, 0, 0, 0 }, | |
278 | [INSTR_SIL_RDU] = { D_20, B_16, U16_32, 0, 0, 0 }, | |
279 | [INSTR_SIY_IRD] = { D20_20, B_16, I8_8, 0, 0, 0 }, | |
280 | [INSTR_SIY_URD] = { D20_20, B_16, U8_8, 0, 0, 0 }, | |
281 | [INSTR_SI_RD] = { D_20, B_16, 0, 0, 0, 0 }, | |
282 | [INSTR_SI_URD] = { D_20, B_16, U8_8, 0, 0, 0 }, | |
283 | [INSTR_SMI_U0RDP] = { U4_8, J16_32, D_20, B_16, 0, 0 }, | |
284 | [INSTR_SSE_RDRD] = { D_20, B_16, D_36, B_32, 0, 0 }, | |
285 | [INSTR_SSF_RRDRD] = { D_20, B_16, D_36, B_32, R_8, 0 }, | |
286 | [INSTR_SSF_RRDRD2] = { R_8, D_20, B_16, D_36, B_32, 0 }, | |
287 | [INSTR_SS_L0RDRD] = { D_20, L8_8, B_16, D_36, B_32, 0 }, | |
288 | [INSTR_SS_L2RDRD] = { D_20, B_16, D_36, L8_8, B_32, 0 }, | |
289 | [INSTR_SS_LIRDRD] = { D_20, L4_8, B_16, D_36, B_32, U4_12 }, | |
290 | [INSTR_SS_LLRDRD] = { D_20, L4_8, B_16, D_36, L4_12, B_32 }, | |
291 | [INSTR_SS_RRRDRD] = { D_20, R_8, B_16, D_36, B_32, R_12 }, | |
292 | [INSTR_SS_RRRDRD2] = { R_8, D_20, B_16, R_12, D_36, B_32 }, | |
293 | [INSTR_SS_RRRDRD3] = { R_8, R_12, D_20, B_16, D_36, B_32 }, | |
294 | [INSTR_S_00] = { 0, 0, 0, 0, 0, 0 }, | |
295 | [INSTR_S_RD] = { D_20, B_16, 0, 0, 0, 0 }, | |
296 | [INSTR_VRI_V0IU] = { V_8, I16_16, U4_32, 0, 0, 0 }, | |
297 | [INSTR_VRI_V0U] = { V_8, U16_16, 0, 0, 0, 0 }, | |
298 | [INSTR_VRI_V0UU2] = { V_8, U16_16, U4_32, 0, 0, 0 }, | |
299 | [INSTR_VRI_V0UUU] = { V_8, U8_16, U8_24, U4_32, 0, 0 }, | |
300 | [INSTR_VRI_VR0UU] = { V_8, R_12, U8_28, U4_24, 0, 0 }, | |
301 | [INSTR_VRI_VVUU] = { V_8, V_12, U16_16, U4_32, 0, 0 }, | |
302 | [INSTR_VRI_VVUUU] = { V_8, V_12, U12_16, U4_32, U4_28, 0 }, | |
303 | [INSTR_VRI_VVUUU2] = { V_8, V_12, U8_28, U8_16, U4_24, 0 }, | |
304 | [INSTR_VRI_VVV0U] = { V_8, V_12, V_16, U8_24, 0, 0 }, | |
305 | [INSTR_VRI_VVV0UU] = { V_8, V_12, V_16, U8_24, U4_32, 0 }, | |
306 | [INSTR_VRI_VVV0UU2] = { V_8, V_12, V_16, U8_28, U4_24, 0 }, | |
307 | [INSTR_VRR_0V] = { V_12, 0, 0, 0, 0, 0 }, | |
308 | [INSTR_VRR_0VV0U] = { V_12, V_16, U4_24, 0, 0, 0 }, | |
309 | [INSTR_VRR_RV0U] = { R_8, V_12, U4_24, 0, 0, 0 }, | |
310 | [INSTR_VRR_VRR] = { V_8, R_12, R_16, 0, 0, 0 }, | |
311 | [INSTR_VRR_VV] = { V_8, V_12, 0, 0, 0, 0 }, | |
312 | [INSTR_VRR_VV0U] = { V_8, V_12, U4_32, 0, 0, 0 }, | |
313 | [INSTR_VRR_VV0U0U] = { V_8, V_12, U4_32, U4_24, 0, 0 }, | |
314 | [INSTR_VRR_VV0UU2] = { V_8, V_12, U4_32, U4_28, 0, 0 }, | |
315 | [INSTR_VRR_VV0UUU] = { V_8, V_12, U4_32, U4_28, U4_24, 0 }, | |
316 | [INSTR_VRR_VVV] = { V_8, V_12, V_16, 0, 0, 0 }, | |
317 | [INSTR_VRR_VVV0U] = { V_8, V_12, V_16, U4_32, 0, 0 }, | |
318 | [INSTR_VRR_VVV0U0U] = { V_8, V_12, V_16, U4_32, U4_24, 0 }, | |
319 | [INSTR_VRR_VVV0UU] = { V_8, V_12, V_16, U4_32, U4_28, 0 }, | |
320 | [INSTR_VRR_VVV0UUU] = { V_8, V_12, V_16, U4_32, U4_28, U4_24 }, | |
321 | [INSTR_VRR_VVV0V] = { V_8, V_12, V_16, V_32, 0, 0 }, | |
322 | [INSTR_VRR_VVVU0UV] = { V_8, V_12, V_16, V_32, U4_28, U4_20 }, | |
323 | [INSTR_VRR_VVVU0V] = { V_8, V_12, V_16, V_32, U4_20, 0 }, | |
324 | [INSTR_VRR_VVVUU0V] = { V_8, V_12, V_16, V_32, U4_20, U4_24 }, | |
325 | [INSTR_VRS_RRDV] = { V_32, R_12, D_20, B_16, 0, 0 }, | |
326 | [INSTR_VRS_RVRDU] = { R_8, V_12, D_20, B_16, U4_32, 0 }, | |
327 | [INSTR_VRS_VRRD] = { V_8, R_12, D_20, B_16, 0, 0 }, | |
328 | [INSTR_VRS_VRRDU] = { V_8, R_12, D_20, B_16, U4_32, 0 }, | |
329 | [INSTR_VRS_VVRD] = { V_8, V_12, D_20, B_16, 0, 0 }, | |
330 | [INSTR_VRS_VVRDU] = { V_8, V_12, D_20, B_16, U4_32, 0 }, | |
331 | [INSTR_VRV_VVXRDU] = { V_8, D_20, VX_12, B_16, U4_32, 0 }, | |
332 | [INSTR_VRX_VRRD] = { V_8, D_20, X_12, B_16, 0, 0 }, | |
333 | [INSTR_VRX_VRRDU] = { V_8, D_20, X_12, B_16, U4_32, 0 }, | |
334 | [INSTR_VRX_VV] = { V_8, V_12, 0, 0, 0, 0 }, | |
335 | [INSTR_VSI_URDV] = { V_32, D_20, B_16, U8_8, 0, 0 }, | |
bb11e3bd MS |
336 | }; |
337 | ||
8bc1e4ec HC |
338 | static char long_insn_name[][7] = LONG_INSN_INITIALIZER; |
339 | static struct s390_insn opcode[] = OPCODE_TABLE_INITIALIZER; | |
340 | static struct s390_opcode_offset opcode_offset[] = OPCODE_OFFSET_INITIALIZER; | |
bb11e3bd MS |
341 | |
342 | /* Extracts an operand value from an instruction. */ | |
343 | static unsigned int extract_operand(unsigned char *code, | |
f616d676 | 344 | const struct s390_operand *operand) |
bb11e3bd | 345 | { |
3585cb02 | 346 | unsigned char *cp; |
bb11e3bd MS |
347 | unsigned int val; |
348 | int bits; | |
349 | ||
350 | /* Extract fragments of the operand byte for byte. */ | |
3585cb02 | 351 | cp = code + operand->shift / 8; |
bb11e3bd MS |
352 | bits = (operand->shift & 7) + operand->bits; |
353 | val = 0; | |
354 | do { | |
355 | val <<= 8; | |
3585cb02 | 356 | val |= (unsigned int) *cp++; |
bb11e3bd MS |
357 | bits -= 8; |
358 | } while (bits > 0); | |
359 | val >>= -bits; | |
360 | val &= ((1U << (operand->bits - 1)) << 1) - 1; | |
361 | ||
362 | /* Check for special long displacement case. */ | |
363 | if (operand->bits == 20 && operand->shift == 20) | |
364 | val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; | |
365 | ||
3585cb02 MS |
366 | /* Check for register extensions bits for vector registers. */ |
367 | if (operand->flags & OPERAND_VR) { | |
368 | if (operand->shift == 8) | |
369 | val |= (code[4] & 8) << 1; | |
370 | else if (operand->shift == 12) | |
371 | val |= (code[4] & 4) << 2; | |
372 | else if (operand->shift == 16) | |
373 | val |= (code[4] & 2) << 3; | |
374 | else if (operand->shift == 32) | |
375 | val |= (code[4] & 1) << 4; | |
376 | } | |
377 | ||
bb11e3bd MS |
378 | /* Sign extend value if the operand is signed or pc relative. */ |
379 | if ((operand->flags & (OPERAND_SIGNED | OPERAND_PCREL)) && | |
380 | (val & (1U << (operand->bits - 1)))) | |
381 | val |= (-1U << (operand->bits - 1)) << 1; | |
382 | ||
383 | /* Double value if the operand is pc relative. */ | |
384 | if (operand->flags & OPERAND_PCREL) | |
385 | val <<= 1; | |
386 | ||
387 | /* Length x in an instructions has real length x + 1. */ | |
388 | if (operand->flags & OPERAND_LENGTH) | |
389 | val++; | |
390 | return val; | |
391 | } | |
392 | ||
1ffa11ab | 393 | struct s390_insn *find_insn(unsigned char *code) |
bb11e3bd | 394 | { |
8bc1e4ec HC |
395 | struct s390_opcode_offset *entry; |
396 | struct s390_insn *insn; | |
397 | unsigned char opfrag; | |
398 | int i; | |
bb11e3bd | 399 | |
de35089c HC |
400 | /* Search the opcode offset table to find an entry which |
401 | * matches the beginning of the opcode. If there is no match | |
402 | * the last entry will be used, which is the default entry for | |
403 | * unknown instructions as well as 1-byte opcode instructions. | |
404 | */ | |
8bc1e4ec HC |
405 | for (i = 0; i < ARRAY_SIZE(opcode_offset); i++) { |
406 | entry = &opcode_offset[i]; | |
de35089c | 407 | if (entry->opcode == code[0]) |
8bc1e4ec | 408 | break; |
bb11e3bd | 409 | } |
8bc1e4ec HC |
410 | |
411 | opfrag = *(code + entry->byte) & entry->mask; | |
412 | ||
413 | insn = &opcode[entry->offset]; | |
414 | for (i = 0; i < entry->count; i++) { | |
415 | if (insn->opfrag == opfrag) | |
416 | return insn; | |
417 | insn++; | |
bb11e3bd MS |
418 | } |
419 | return NULL; | |
420 | } | |
421 | ||
422 | static int print_insn(char *buffer, unsigned char *code, unsigned long addr) | |
423 | { | |
f616d676 | 424 | struct s390_insn *insn; |
bb11e3bd | 425 | const unsigned char *ops; |
f616d676 | 426 | const struct s390_operand *operand; |
bb11e3bd MS |
427 | unsigned int value; |
428 | char separator; | |
429 | char *ptr; | |
74ccbdc2 | 430 | int i; |
bb11e3bd MS |
431 | |
432 | ptr = buffer; | |
433 | insn = find_insn(code); | |
434 | if (insn) { | |
8bc1e4ec HC |
435 | if (insn->zero == 0) |
436 | ptr += sprintf(ptr, "%.7s\t", | |
437 | long_insn_name[insn->offset]); | |
8b8c12b1 MS |
438 | else |
439 | ptr += sprintf(ptr, "%.5s\t", insn->name); | |
bb11e3bd MS |
440 | /* Extract the operands. */ |
441 | separator = 0; | |
8bc1e4ec | 442 | for (ops = formats[insn->format], i = 0; |
74ccbdc2 | 443 | *ops != 0 && i < 6; ops++, i++) { |
bb11e3bd MS |
444 | operand = operands + *ops; |
445 | value = extract_operand(code, operand); | |
446 | if ((operand->flags & OPERAND_INDEX) && value == 0) | |
447 | continue; | |
448 | if ((operand->flags & OPERAND_BASE) && | |
449 | value == 0 && separator == '(') { | |
450 | separator = ','; | |
451 | continue; | |
452 | } | |
453 | if (separator) | |
454 | ptr += sprintf(ptr, "%c", separator); | |
455 | if (operand->flags & OPERAND_GPR) | |
ee8479bb | 456 | ptr += sprintf(ptr, "%%r%i", value); |
bb11e3bd | 457 | else if (operand->flags & OPERAND_FPR) |
ee8479bb | 458 | ptr += sprintf(ptr, "%%f%i", value); |
bb11e3bd | 459 | else if (operand->flags & OPERAND_AR) |
ee8479bb | 460 | ptr += sprintf(ptr, "%%a%i", value); |
bb11e3bd | 461 | else if (operand->flags & OPERAND_CR) |
ee8479bb | 462 | ptr += sprintf(ptr, "%%c%i", value); |
3585cb02 | 463 | else if (operand->flags & OPERAND_VR) |
ee8479bb | 464 | ptr += sprintf(ptr, "%%v%i", value); |
bb11e3bd | 465 | else if (operand->flags & OPERAND_PCREL) |
92d154b6 CB |
466 | ptr += sprintf(ptr, "%lx", (signed int) value |
467 | + addr); | |
bb11e3bd MS |
468 | else if (operand->flags & OPERAND_SIGNED) |
469 | ptr += sprintf(ptr, "%i", value); | |
470 | else | |
471 | ptr += sprintf(ptr, "%u", value); | |
472 | if (operand->flags & OPERAND_DISP) | |
473 | separator = '('; | |
474 | else if (operand->flags & OPERAND_BASE) { | |
475 | ptr += sprintf(ptr, ")"); | |
476 | separator = ','; | |
477 | } else | |
478 | separator = ','; | |
479 | } | |
480 | } else | |
481 | ptr += sprintf(ptr, "unknown"); | |
482 | return (int) (ptr - buffer); | |
483 | } | |
484 | ||
485 | void show_code(struct pt_regs *regs) | |
486 | { | |
7d256175 | 487 | char *mode = user_mode(regs) ? "User" : "Krnl"; |
bb11e3bd | 488 | unsigned char code[64]; |
b192571d | 489 | char buffer[128], *ptr; |
bb11e3bd MS |
490 | mm_segment_t old_fs; |
491 | unsigned long addr; | |
492 | int start, end, opsize, hops, i; | |
493 | ||
494 | /* Get a snapshot of the 64 bytes surrounding the fault address. */ | |
495 | old_fs = get_fs(); | |
7d256175 | 496 | set_fs(user_mode(regs) ? USER_DS : KERNEL_DS); |
bb11e3bd MS |
497 | for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) { |
498 | addr = regs->psw.addr - 34 + start; | |
499 | if (__copy_from_user(code + start - 2, | |
500 | (char __user *) addr, 2)) | |
501 | break; | |
502 | } | |
503 | for (end = 32; end < 64; end += 2) { | |
504 | addr = regs->psw.addr + end - 32; | |
505 | if (__copy_from_user(code + end, | |
506 | (char __user *) addr, 2)) | |
507 | break; | |
508 | } | |
509 | set_fs(old_fs); | |
510 | /* Code snapshot useable ? */ | |
511 | if ((regs->psw.addr & 1) || start >= end) { | |
512 | printk("%s Code: Bad PSW.\n", mode); | |
513 | return; | |
514 | } | |
515 | /* Find a starting point for the disassembly. */ | |
516 | while (start < 32) { | |
bb11e3bd MS |
517 | for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) { |
518 | if (!find_insn(code + start + i)) | |
519 | break; | |
520 | i += insn_length(code[start + i]); | |
521 | } | |
522 | if (start + i == 32) | |
523 | /* Looks good, sequence ends at PSW. */ | |
524 | break; | |
525 | start += 2; | |
526 | } | |
527 | /* Decode the instructions. */ | |
528 | ptr = buffer; | |
529 | ptr += sprintf(ptr, "%s Code:", mode); | |
530 | hops = 0; | |
531 | while (start < end && hops < 8) { | |
2fa1d4fc HC |
532 | opsize = insn_length(code[start]); |
533 | if (start + opsize == 32) | |
534 | *ptr++ = '#'; | |
535 | else if (start == 32) | |
536 | *ptr++ = '>'; | |
537 | else | |
538 | *ptr++ = ' '; | |
bb11e3bd | 539 | addr = regs->psw.addr + start - 32; |
5a79859a | 540 | ptr += sprintf(ptr, "%016lx: ", addr); |
bb11e3bd MS |
541 | if (start + opsize >= end) |
542 | break; | |
543 | for (i = 0; i < opsize; i++) | |
544 | ptr += sprintf(ptr, "%02x", code[start + i]); | |
545 | *ptr++ = '\t'; | |
546 | if (i < 6) | |
547 | *ptr++ = '\t'; | |
548 | ptr += print_insn(ptr, code + start, addr); | |
549 | start += opsize; | |
4d062487 | 550 | pr_cont("%s", buffer); |
bb11e3bd | 551 | ptr = buffer; |
26f4e759 | 552 | ptr += sprintf(ptr, "\n "); |
bb11e3bd MS |
553 | hops++; |
554 | } | |
4d062487 | 555 | pr_cont("\n"); |
bb11e3bd | 556 | } |
c10302ef MS |
557 | |
558 | void print_fn_code(unsigned char *code, unsigned long len) | |
559 | { | |
560 | char buffer[64], *ptr; | |
561 | int opsize, i; | |
562 | ||
563 | while (len) { | |
564 | ptr = buffer; | |
565 | opsize = insn_length(*code); | |
7678dcfb HC |
566 | if (opsize > len) |
567 | break; | |
c10302ef MS |
568 | ptr += sprintf(ptr, "%p: ", code); |
569 | for (i = 0; i < opsize; i++) | |
570 | ptr += sprintf(ptr, "%02x", code[i]); | |
571 | *ptr++ = '\t'; | |
572 | if (i < 4) | |
573 | *ptr++ = '\t'; | |
574 | ptr += print_insn(ptr, code, (unsigned long) code); | |
575 | *ptr++ = '\n'; | |
576 | *ptr++ = 0; | |
561e1030 | 577 | printk("%s", buffer); |
c10302ef MS |
578 | code += opsize; |
579 | len -= opsize; | |
580 | } | |
581 | } |