| 1 | |
| 2 | |
| 3 | * Disassemble s390 instructions.
|
| 4 | *
|
| 5 | * Copyright IBM Corp. 2007
|
| 6 | * Author(s): Martin Schwidefsky ([email protected]),
|
| 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>
|
| 17 | #include <linux/init.h>
|
| 18 | #include <linux/interrupt.h>
|
| 19 | #include <linux/delay.h>
|
| 20 | #include <linux/kallsyms.h>
|
| 21 | #include <linux/reboot.h>
|
| 22 | #include <linux/kprobes.h>
|
| 23 | #include <linux/kdebug.h>
|
| 24 | #include <linux/uaccess.h>
|
| 25 | #include <linux/atomic.h>
|
| 26 | #include <linux/io.h>
|
| 27 | #include <asm/dis.h>
|
| 28 | #include <asm/cpcmd.h>
|
| 29 | #include <asm/lowcore.h>
|
| 30 | #include <asm/debug.h>
|
| 31 | #include <asm/irq.h>
|
| 32 |
|
| 33 |
|
| 34 | #define OPERAND_GPR 0x1
|
| 35 | #define OPERAND_FPR 0x2
|
| 36 | #define OPERAND_AR 0x4
|
| 37 | #define OPERAND_CR 0x8
|
| 38 | #define OPERAND_VR 0x10
|
| 39 | #define OPERAND_DISP 0x20
|
| 40 | #define OPERAND_BASE 0x40
|
| 41 | #define OPERAND_INDEX 0x80
|
| 42 | #define OPERAND_PCREL 0x100
|
| 43 | #define OPERAND_SIGNED 0x200
|
| 44 | #define OPERAND_LENGTH 0x400
|
| 45 |
|
| 46 | struct s390_operand {
|
| 47 | unsigned char bits;
|
| 48 | unsigned char shift;
|
| 49 | unsigned short flags;
|
| 50 | };
|
| 51 |
|
| 52 | struct s390_insn {
|
| 53 | union {
|
| 54 | const char name[5] __nonstring;
|
| 55 | struct {
|
| 56 | unsigned char zero;
|
| 57 | unsigned int offset;
|
| 58 | } __packed;
|
| 59 | };
|
| 60 | unsigned char opfrag;
|
| 61 | unsigned char format;
|
| 62 | };
|
| 63 |
|
| 64 | struct s390_opcode_offset {
|
| 65 | unsigned char opcode;
|
| 66 | unsigned char mask;
|
| 67 | unsigned char byte;
|
| 68 | unsigned short offset;
|
| 69 | unsigned short count;
|
| 70 | } __packed;
|
| 71 |
|
| 72 | enum {
|
| 73 | UNUSED,
|
| 74 | A_8,
|
| 75 | A_12,
|
| 76 | A_24,
|
| 77 | A_28,
|
| 78 | B_16,
|
| 79 | B_32,
|
| 80 | C_8,
|
| 81 | C_12,
|
| 82 | D20_20,
|
| 83 | D_20,
|
| 84 | D_36,
|
| 85 | F_8,
|
| 86 | F_12,
|
| 87 | F_16,
|
| 88 | F_24,
|
| 89 | F_28,
|
| 90 | F_32,
|
| 91 | I8_8,
|
| 92 | I8_32,
|
| 93 | I16_16,
|
| 94 | I16_32,
|
| 95 | I32_16,
|
| 96 | J12_12,
|
| 97 | J16_16,
|
| 98 | J16_32,
|
| 99 | J24_24,
|
| 100 | J32_16,
|
| 101 | L4_8,
|
| 102 | L4_12,
|
| 103 | L8_8,
|
| 104 | R_8,
|
| 105 | R_12,
|
| 106 | R_16,
|
| 107 | R_24,
|
| 108 | R_28,
|
| 109 | U4_8,
|
| 110 | U4_12,
|
| 111 | U4_16,
|
| 112 | U4_20,
|
| 113 | U4_24,
|
| 114 | U4_28,
|
| 115 | U4_32,
|
| 116 | U4_36,
|
| 117 | U8_8,
|
| 118 | U8_16,
|
| 119 | U8_24,
|
| 120 | U8_28,
|
| 121 | U8_32,
|
| 122 | U12_16,
|
| 123 | U16_16,
|
| 124 | U16_20,
|
| 125 | U16_32,
|
| 126 | U32_16,
|
| 127 | VX_12,
|
| 128 | V_8,
|
| 129 | V_12,
|
| 130 | V_16,
|
| 131 | V_32,
|
| 132 | X_12,
|
| 133 | };
|
| 134 |
|
| 135 | static const struct s390_operand operands[] = {
|
| 136 | [UNUSED] = { 0, 0, 0 },
|
| 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 },
|
| 141 | [B_16] = { 4, 16, OPERAND_BASE | OPERAND_GPR },
|
| 142 | [B_32] = { 4, 32, OPERAND_BASE | OPERAND_GPR },
|
| 143 | [C_8] = { 4, 8, OPERAND_CR },
|
| 144 | [C_12] = { 4, 12, OPERAND_CR },
|
| 145 | [D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED },
|
| 146 | [D_20] = { 12, 20, OPERAND_DISP },
|
| 147 | [D_36] = { 12, 36, OPERAND_DISP },
|
| 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 },
|
| 164 | [L4_8] = { 4, 8, OPERAND_LENGTH },
|
| 165 | [L4_12] = { 4, 12, OPERAND_LENGTH },
|
| 166 | [L8_8] = { 8, 8, OPERAND_LENGTH },
|
| 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 },
|
| 172 | [U4_8] = { 4, 8, 0 },
|
| 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 },
|
| 180 | [U8_8] = { 8, 8, 0 },
|
| 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 },
|
| 186 | [U16_16] = { 16, 16, 0 },
|
| 187 | [U16_20] = { 16, 20, 0 },
|
| 188 | [U16_32] = { 16, 32, 0 },
|
| 189 | [U32_16] = { 32, 16, 0 },
|
| 190 | [VX_12] = { 4, 12, OPERAND_INDEX | OPERAND_VR },
|
| 191 | [V_8] = { 4, 8, OPERAND_VR },
|
| 192 | [V_12] = { 4, 12, OPERAND_VR },
|
| 193 | [V_16] = { 4, 16, OPERAND_VR },
|
| 194 | [V_32] = { 4, 32, OPERAND_VR },
|
| 195 | [X_12] = { 4, 12, OPERAND_INDEX | OPERAND_GPR },
|
| 196 | };
|
| 197 |
|
| 198 | static const unsigned char formats[][6] = {
|
| 199 | [INSTR_E] = { 0, 0, 0, 0, 0, 0 },
|
| 200 | [INSTR_IE_UU] = { U4_24, U4_28, 0, 0, 0, 0 },
|
| 201 | [INSTR_MII_UPP] = { U4_8, J12_12, J24_24 },
|
| 202 | [INSTR_RIE_R0IU] = { R_8, I16_16, U4_32, 0, 0, 0 },
|
| 203 | [INSTR_RIE_R0UU] = { R_8, U16_16, U4_32, 0, 0, 0 },
|
| 204 | [INSTR_RIE_RRI0] = { R_8, R_12, I16_16, 0, 0, 0 },
|
| 205 | [INSTR_RIE_RRP] = { R_8, R_12, J16_16, 0, 0, 0 },
|
| 206 | [INSTR_RIE_RRPU] = { R_8, R_12, U4_32, J16_16, 0, 0 },
|
| 207 | [INSTR_RIE_RRUUU] = { R_8, R_12, U8_16, U8_24, U8_32, 0 },
|
| 208 | [INSTR_RIE_RUI0] = { R_8, I16_16, U4_12, 0, 0, 0 },
|
| 209 | [INSTR_RIE_RUPI] = { R_8, I8_32, U4_12, J16_16, 0, 0 },
|
| 210 | [INSTR_RIE_RUPU] = { R_8, U8_32, U4_12, J16_16, 0, 0 },
|
| 211 | [INSTR_RIL_RI] = { R_8, I32_16, 0, 0, 0, 0 },
|
| 212 | [INSTR_RIL_RP] = { R_8, J32_16, 0, 0, 0, 0 },
|
| 213 | [INSTR_RIL_RU] = { R_8, U32_16, 0, 0, 0, 0 },
|
| 214 | [INSTR_RIL_UP] = { U4_8, J32_16, 0, 0, 0, 0 },
|
| 215 | [INSTR_RIS_RURDI] = { R_8, I8_32, U4_12, D_20, B_16, 0 },
|
| 216 | [INSTR_RIS_RURDU] = { R_8, U8_32, U4_12, D_20, B_16, 0 },
|
| 217 | [INSTR_RI_RI] = { R_8, I16_16, 0, 0, 0, 0 },
|
| 218 | [INSTR_RI_RP] = { R_8, J16_16, 0, 0, 0, 0 },
|
| 219 | [INSTR_RI_RU] = { R_8, U16_16, 0, 0, 0, 0 },
|
| 220 | [INSTR_RI_UP] = { U4_8, J16_16, 0, 0, 0, 0 },
|
| 221 | [INSTR_RRE_00] = { 0, 0, 0, 0, 0, 0 },
|
| 222 | [INSTR_RRE_AA] = { A_24, A_28, 0, 0, 0, 0 },
|
| 223 | [INSTR_RRE_AR] = { A_24, R_28, 0, 0, 0, 0 },
|
| 224 | [INSTR_RRE_F0] = { F_24, 0, 0, 0, 0, 0 },
|
| 225 | [INSTR_RRE_FF] = { F_24, F_28, 0, 0, 0, 0 },
|
| 226 | [INSTR_RRE_FR] = { F_24, R_28, 0, 0, 0, 0 },
|
| 227 | [INSTR_RRE_R0] = { R_24, 0, 0, 0, 0, 0 },
|
| 228 | [INSTR_RRE_RA] = { R_24, A_28, 0, 0, 0, 0 },
|
| 229 | [INSTR_RRE_RF] = { R_24, F_28, 0, 0, 0, 0 },
|
| 230 | [INSTR_RRE_RR] = { R_24, R_28, 0, 0, 0, 0 },
|
| 231 | [INSTR_RRF_0UFF] = { F_24, F_28, U4_20, 0, 0, 0 },
|
| 232 | [INSTR_RRF_0URF] = { R_24, F_28, U4_20, 0, 0, 0 },
|
| 233 | [INSTR_RRF_F0FF] = { F_16, F_24, F_28, 0, 0, 0 },
|
| 234 | [INSTR_RRF_F0FF2] = { F_24, F_16, F_28, 0, 0, 0 },
|
| 235 | [INSTR_RRF_F0FR] = { F_24, F_16, R_28, 0, 0, 0 },
|
| 236 | [INSTR_RRF_FFRU] = { F_24, F_16, R_28, U4_20, 0, 0 },
|
| 237 | [INSTR_RRF_FUFF] = { F_24, F_16, F_28, U4_20, 0, 0 },
|
| 238 | [INSTR_RRF_FUFF2] = { F_24, F_28, F_16, U4_20, 0, 0 },
|
| 239 | [INSTR_RRF_R0RR] = { R_24, R_16, R_28, 0, 0, 0 },
|
| 240 | [INSTR_RRF_R0RR2] = { R_24, R_28, R_16, 0, 0, 0 },
|
| 241 | [INSTR_RRF_RURR] = { R_24, R_28, R_16, U4_20, 0, 0 },
|
| 242 | [INSTR_RRF_RURR2] = { R_24, R_16, R_28, U4_20, 0, 0 },
|
| 243 | [INSTR_RRF_U0FF] = { F_24, U4_16, F_28, 0, 0, 0 },
|
| 244 | [INSTR_RRF_U0RF] = { R_24, U4_16, F_28, 0, 0, 0 },
|
| 245 | [INSTR_RRF_U0RR] = { R_24, R_28, U4_16, 0, 0, 0 },
|
| 246 | [INSTR_RRF_URR] = { R_24, R_28, U8_16, 0, 0, 0 },
|
| 247 | [INSTR_RRF_UUFF] = { F_24, U4_16, F_28, U4_20, 0, 0 },
|
| 248 | [INSTR_RRF_UUFR] = { F_24, U4_16, R_28, U4_20, 0, 0 },
|
| 249 | [INSTR_RRF_UURF] = { R_24, U4_16, F_28, U4_20, 0, 0 },
|
| 250 | [INSTR_RRS_RRRDU] = { R_8, R_12, U4_32, D_20, B_16 },
|
| 251 | [INSTR_RR_FF] = { F_8, F_12, 0, 0, 0, 0 },
|
| 252 | [INSTR_RR_R0] = { R_8, 0, 0, 0, 0, 0 },
|
| 253 | [INSTR_RR_RR] = { R_8, R_12, 0, 0, 0, 0 },
|
| 254 | [INSTR_RR_U0] = { U8_8, 0, 0, 0, 0, 0 },
|
| 255 | [INSTR_RR_UR] = { U4_8, R_12, 0, 0, 0, 0 },
|
| 256 | [INSTR_RSI_RRP] = { R_8, R_12, J16_16, 0, 0, 0 },
|
| 257 | [INSTR_RSL_LRDFU] = { F_32, D_20, L8_8, B_16, U4_36, 0 },
|
| 258 | [INSTR_RSL_R0RD] = { D_20, L4_8, B_16, 0, 0, 0 },
|
| 259 | [INSTR_RSY_AARD] = { A_8, A_12, D20_20, B_16, 0, 0 },
|
| 260 | [INSTR_RSY_CCRD] = { C_8, C_12, D20_20, B_16, 0, 0 },
|
| 261 | [INSTR_RSY_RRRD] = { R_8, R_12, D20_20, B_16, 0, 0 },
|
| 262 | [INSTR_RSY_RURD] = { R_8, U4_12, D20_20, B_16, 0, 0 },
|
| 263 | [INSTR_RSY_RURD2] = { R_8, D20_20, B_16, U4_12, 0, 0 },
|
| 264 | [INSTR_RS_AARD] = { A_8, A_12, D_20, B_16, 0, 0 },
|
| 265 | [INSTR_RS_CCRD] = { C_8, C_12, D_20, B_16, 0, 0 },
|
| 266 | [INSTR_RS_R0RD] = { R_8, D_20, B_16, 0, 0, 0 },
|
| 267 | [INSTR_RS_RRRD] = { R_8, R_12, D_20, B_16, 0, 0 },
|
| 268 | [INSTR_RS_RURD] = { R_8, U4_12, D_20, B_16, 0, 0 },
|
| 269 | [INSTR_RXE_FRRD] = { F_8, D_20, X_12, B_16, 0, 0 },
|
| 270 | [INSTR_RXE_RRRDU] = { R_8, D_20, X_12, B_16, U4_32, 0 },
|
| 271 | [INSTR_RXF_FRRDF] = { F_32, F_8, D_20, X_12, B_16, 0 },
|
| 272 | [INSTR_RXY_FRRD] = { F_8, D20_20, X_12, B_16, 0, 0 },
|
| 273 | [INSTR_RXY_RRRD] = { R_8, D20_20, X_12, B_16, 0, 0 },
|
| 274 | [INSTR_RXY_URRD] = { U4_8, D20_20, X_12, B_16, 0, 0 },
|
| 275 | [INSTR_RX_FRRD] = { F_8, D_20, X_12, B_16, 0, 0 },
|
| 276 | [INSTR_RX_RRRD] = { R_8, D_20, X_12, B_16, 0, 0 },
|
| 277 | [INSTR_RX_URRD] = { U4_8, D_20, X_12, B_16, 0, 0 },
|
| 278 | [INSTR_SIL_RDI] = { D_20, B_16, I16_32, 0, 0, 0 },
|
| 279 | [INSTR_SIL_RDU] = { D_20, B_16, U16_32, 0, 0, 0 },
|
| 280 | [INSTR_SIY_IRD] = { D20_20, B_16, I8_8, 0, 0, 0 },
|
| 281 | [INSTR_SIY_RD] = { D20_20, B_16, 0, 0, 0, 0 },
|
| 282 | [INSTR_SIY_URD] = { D20_20, B_16, U8_8, 0, 0, 0 },
|
| 283 | [INSTR_SI_RD] = { D_20, B_16, 0, 0, 0, 0 },
|
| 284 | [INSTR_SI_URD] = { D_20, B_16, U8_8, 0, 0, 0 },
|
| 285 | [INSTR_SMI_U0RDP] = { U4_8, J16_32, D_20, B_16, 0, 0 },
|
| 286 | [INSTR_SSE_RDRD] = { D_20, B_16, D_36, B_32, 0, 0 },
|
| 287 | [INSTR_SSF_RRDRD] = { D_20, B_16, D_36, B_32, R_8, 0 },
|
| 288 | [INSTR_SSF_RRDRD2] = { R_8, D_20, B_16, D_36, B_32, 0 },
|
| 289 | [INSTR_SS_L0RDRD] = { D_20, L8_8, B_16, D_36, B_32, 0 },
|
| 290 | [INSTR_SS_L2RDRD] = { D_20, B_16, D_36, L8_8, B_32, 0 },
|
| 291 | [INSTR_SS_LIRDRD] = { D_20, L4_8, B_16, D_36, B_32, U4_12 },
|
| 292 | [INSTR_SS_LLRDRD] = { D_20, L4_8, B_16, D_36, L4_12, B_32 },
|
| 293 | [INSTR_SS_RRRDRD] = { D_20, R_8, B_16, D_36, B_32, R_12 },
|
| 294 | [INSTR_SS_RRRDRD2] = { R_8, D_20, B_16, R_12, D_36, B_32 },
|
| 295 | [INSTR_SS_RRRDRD3] = { R_8, R_12, D_20, B_16, D_36, B_32 },
|
| 296 | [INSTR_S_00] = { 0, 0, 0, 0, 0, 0 },
|
| 297 | [INSTR_S_RD] = { D_20, B_16, 0, 0, 0, 0 },
|
| 298 | [INSTR_VRI_V0IU] = { V_8, I16_16, U4_32, 0, 0, 0 },
|
| 299 | [INSTR_VRI_V0U] = { V_8, U16_16, 0, 0, 0, 0 },
|
| 300 | [INSTR_VRI_V0UU2] = { V_8, U16_16, U4_32, 0, 0, 0 },
|
| 301 | [INSTR_VRI_V0UUU] = { V_8, U8_16, U8_24, U4_32, 0, 0 },
|
| 302 | [INSTR_VRI_VR0UU] = { V_8, R_12, U8_28, U4_24, 0, 0 },
|
| 303 | [INSTR_VRI_VV0UU] = { V_8, V_12, U8_28, U4_24, 0, 0 },
|
| 304 | [INSTR_VRI_VVUU] = { V_8, V_12, U16_16, U4_32, 0, 0 },
|
| 305 | [INSTR_VRI_VVUUU] = { V_8, V_12, U12_16, U4_32, U4_28, 0 },
|
| 306 | [INSTR_VRI_VVUUU2] = { V_8, V_12, U8_28, U8_16, U4_24, 0 },
|
| 307 | [INSTR_VRI_VVV0U] = { V_8, V_12, V_16, U8_24, 0, 0 },
|
| 308 | [INSTR_VRI_VVV0UU] = { V_8, V_12, V_16, U8_24, U4_32, 0 },
|
| 309 | [INSTR_VRI_VVV0UU2] = { V_8, V_12, V_16, U8_28, U4_24, 0 },
|
| 310 | [INSTR_VRI_VVV0UV] = { V_8, V_12, V_16, V_32, U8_24, 0 },
|
| 311 | [INSTR_VRR_0V0U] = { V_12, U16_20, 0, 0, 0, 0 },
|
| 312 | [INSTR_VRR_0VV0U] = { V_12, V_16, U4_24, 0, 0, 0 },
|
| 313 | [INSTR_VRR_0VVU] = { V_12, V_16, U16_20, 0, 0, 0 },
|
| 314 | [INSTR_VRR_RV0UU] = { R_8, V_12, U4_24, U4_28, 0, 0 },
|
| 315 | [INSTR_VRR_VRR] = { V_8, R_12, R_16, 0, 0, 0 },
|
| 316 | [INSTR_VRR_VV] = { V_8, V_12, 0, 0, 0, 0 },
|
| 317 | [INSTR_VRR_VV0U] = { V_8, V_12, U4_32, 0, 0, 0 },
|
| 318 | [INSTR_VRR_VV0U0U] = { V_8, V_12, U4_32, U4_24, 0, 0 },
|
| 319 | [INSTR_VRR_VV0U2] = { V_8, V_12, U4_24, 0, 0, 0 },
|
| 320 | [INSTR_VRR_VV0UU2] = { V_8, V_12, U4_32, U4_28, 0, 0 },
|
| 321 | [INSTR_VRR_VV0UUU] = { V_8, V_12, U4_32, U4_28, U4_24, 0 },
|
| 322 | [INSTR_VRR_VVV] = { V_8, V_12, V_16, 0, 0, 0 },
|
| 323 | [INSTR_VRR_VVV0U] = { V_8, V_12, V_16, U4_32, 0, 0 },
|
| 324 | [INSTR_VRR_VVV0U0] = { V_8, V_12, V_16, U4_24, 0, 0 },
|
| 325 | [INSTR_VRR_VVV0U0U] = { V_8, V_12, V_16, U4_32, U4_24, 0 },
|
| 326 | [INSTR_VRR_VVV0UU] = { V_8, V_12, V_16, U4_32, U4_28, 0 },
|
| 327 | [INSTR_VRR_VVV0UUU] = { V_8, V_12, V_16, U4_32, U4_28, U4_24 },
|
| 328 | [INSTR_VRR_VVV0V] = { V_8, V_12, V_16, V_32, 0, 0 },
|
| 329 | [INSTR_VRR_VVVU0UV] = { V_8, V_12, V_16, V_32, U4_28, U4_20 },
|
| 330 | [INSTR_VRR_VVVU0V] = { V_8, V_12, V_16, V_32, U4_20, 0 },
|
| 331 | [INSTR_VRR_VVVUU0V] = { V_8, V_12, V_16, V_32, U4_20, U4_24 },
|
| 332 | [INSTR_VRS_RRDV] = { V_32, R_12, D_20, B_16, 0, 0 },
|
| 333 | [INSTR_VRS_RVRDU] = { R_8, V_12, D_20, B_16, U4_32, 0 },
|
| 334 | [INSTR_VRS_VRRD] = { V_8, R_12, D_20, B_16, 0, 0 },
|
| 335 | [INSTR_VRS_VRRDU] = { V_8, R_12, D_20, B_16, U4_32, 0 },
|
| 336 | [INSTR_VRS_VVRDU] = { V_8, V_12, D_20, B_16, U4_32, 0 },
|
| 337 | [INSTR_VRV_VVXRDU] = { V_8, D_20, VX_12, B_16, U4_32, 0 },
|
| 338 | [INSTR_VRX_VRRDU] = { V_8, D_20, X_12, B_16, U4_32, 0 },
|
| 339 | [INSTR_VRX_VV] = { V_8, V_12, 0, 0, 0, 0 },
|
| 340 | [INSTR_VSI_URDV] = { V_32, D_20, B_16, U8_8, 0, 0 },
|
| 341 | };
|
| 342 |
|
| 343 | static char long_insn_name[][7] __nonstring_array = LONG_INSN_INITIALIZER;
|
| 344 | static struct s390_insn opcode[] = OPCODE_TABLE_INITIALIZER;
|
| 345 | static struct s390_opcode_offset opcode_offset[] = OPCODE_OFFSET_INITIALIZER;
|
| 346 |
|
| 347 |
|
| 348 | static unsigned int extract_operand(unsigned char *code,
|
| 349 | const struct s390_operand *operand)
|
| 350 | {
|
| 351 | unsigned char *cp;
|
| 352 | unsigned int val;
|
| 353 | int bits;
|
| 354 |
|
| 355 |
|
| 356 | cp = code + operand->shift / 8;
|
| 357 | bits = (operand->shift & 7) + operand->bits;
|
| 358 | val = 0;
|
| 359 | do {
|
| 360 | val <<= 8;
|
| 361 | val |= (unsigned int) *cp++;
|
| 362 | bits -= 8;
|
| 363 | } while (bits > 0);
|
| 364 | val >>= -bits;
|
| 365 | val &= ((1U << (operand->bits - 1)) << 1) - 1;
|
| 366 |
|
| 367 |
|
| 368 | if (operand->bits == 20 && operand->shift == 20)
|
| 369 | val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
|
| 370 |
|
| 371 |
|
| 372 | if (operand->flags & OPERAND_VR) {
|
| 373 | if (operand->shift == 8)
|
| 374 | val |= (code[4] & 8) << 1;
|
| 375 | else if (operand->shift == 12)
|
| 376 | val |= (code[4] & 4) << 2;
|
| 377 | else if (operand->shift == 16)
|
| 378 | val |= (code[4] & 2) << 3;
|
| 379 | else if (operand->shift == 32)
|
| 380 | val |= (code[4] & 1) << 4;
|
| 381 | }
|
| 382 |
|
| 383 |
|
| 384 | if ((operand->flags & (OPERAND_SIGNED | OPERAND_PCREL)) &&
|
| 385 | (val & (1U << (operand->bits - 1))))
|
| 386 | val |= (-1U << (operand->bits - 1)) << 1;
|
| 387 |
|
| 388 |
|
| 389 | if (operand->flags & OPERAND_PCREL)
|
| 390 | val <<= 1;
|
| 391 |
|
| 392 |
|
| 393 | if (operand->flags & OPERAND_LENGTH)
|
| 394 | val++;
|
| 395 | return val;
|
| 396 | }
|
| 397 |
|
| 398 | struct s390_insn *find_insn(unsigned char *code)
|
| 399 | {
|
| 400 | struct s390_opcode_offset *entry;
|
| 401 | struct s390_insn *insn;
|
| 402 | unsigned char opfrag;
|
| 403 | int i;
|
| 404 |
|
| 405 | |
| 406 | * matches the beginning of the opcode. If there is no match
|
| 407 | * the last entry will be used, which is the default entry for
|
| 408 | * unknown instructions as well as 1-byte opcode instructions.
|
| 409 |
|
| 410 | for (i = 0; i < ARRAY_SIZE(opcode_offset); i++) {
|
| 411 | entry = &opcode_offset[i];
|
| 412 | if (entry->opcode == code[0])
|
| 413 | break;
|
| 414 | }
|
| 415 |
|
| 416 | opfrag = *(code + entry->byte) & entry->mask;
|
| 417 |
|
| 418 | insn = &opcode[entry->offset];
|
| 419 | for (i = 0; i < entry->count; i++) {
|
| 420 | if (insn->opfrag == opfrag)
|
| 421 | return insn;
|
| 422 | insn++;
|
| 423 | }
|
| 424 | return NULL;
|
| 425 | }
|
| 426 |
|
| 427 | static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
|
| 428 | {
|
| 429 | struct s390_insn *insn;
|
| 430 | const unsigned char *ops;
|
| 431 | const struct s390_operand *operand;
|
| 432 | unsigned int value;
|
| 433 | char separator;
|
| 434 | char *ptr;
|
| 435 | int i;
|
| 436 |
|
| 437 | ptr = buffer;
|
| 438 | insn = find_insn(code);
|
| 439 | if (insn) {
|
| 440 | if (insn->zero == 0)
|
| 441 | ptr += sprintf(ptr, "%.7s\t",
|
| 442 | long_insn_name[insn->offset]);
|
| 443 | else
|
| 444 | ptr += sprintf(ptr, "%.5s\t", insn->name);
|
| 445 |
|
| 446 | separator = 0;
|
| 447 | for (ops = formats[insn->format], i = 0;
|
| 448 | *ops != 0 && i < 6; ops++, i++) {
|
| 449 | operand = operands + *ops;
|
| 450 | value = extract_operand(code, operand);
|
| 451 | if ((operand->flags & OPERAND_INDEX) && value == 0)
|
| 452 | continue;
|
| 453 | if ((operand->flags & OPERAND_BASE) &&
|
| 454 | value == 0 && separator == '(') {
|
| 455 | separator = ',';
|
| 456 | continue;
|
| 457 | }
|
| 458 | if (separator)
|
| 459 | ptr += sprintf(ptr, "%c", separator);
|
| 460 | if (operand->flags & OPERAND_GPR)
|
| 461 | ptr += sprintf(ptr, "%%r%u", value);
|
| 462 | else if (operand->flags & OPERAND_FPR)
|
| 463 | ptr += sprintf(ptr, "%%f%u", value);
|
| 464 | else if (operand->flags & OPERAND_AR)
|
| 465 | ptr += sprintf(ptr, "%%a%u", value);
|
| 466 | else if (operand->flags & OPERAND_CR)
|
| 467 | ptr += sprintf(ptr, "%%c%u", value);
|
| 468 | else if (operand->flags & OPERAND_VR)
|
| 469 | ptr += sprintf(ptr, "%%v%u", value);
|
| 470 | else if (operand->flags & OPERAND_PCREL) {
|
| 471 | void *pcrel = (void *)((int)value + addr);
|
| 472 |
|
| 473 | ptr += sprintf(ptr, "%px", pcrel);
|
| 474 | } else if (operand->flags & OPERAND_SIGNED)
|
| 475 | ptr += sprintf(ptr, "%i", (int)value);
|
| 476 | else
|
| 477 | ptr += sprintf(ptr, "%u", value);
|
| 478 | if (operand->flags & OPERAND_DISP)
|
| 479 | separator = '(';
|
| 480 | else if (operand->flags & OPERAND_BASE) {
|
| 481 | ptr += sprintf(ptr, ")");
|
| 482 | separator = ',';
|
| 483 | } else
|
| 484 | separator = ',';
|
| 485 | }
|
| 486 | } else
|
| 487 | ptr += sprintf(ptr, "unknown");
|
| 488 | return (int) (ptr - buffer);
|
| 489 | }
|
| 490 |
|
| 491 | static int copy_from_regs(struct pt_regs *regs, void *dst, void *src, int len)
|
| 492 | {
|
| 493 | if (user_mode(regs)) {
|
| 494 | if (copy_from_user(dst, (char __user *)src, len))
|
| 495 | return -EFAULT;
|
| 496 | } else {
|
| 497 | if (copy_from_kernel_nofault(dst, src, len))
|
| 498 | return -EFAULT;
|
| 499 | }
|
| 500 | return 0;
|
| 501 | }
|
| 502 |
|
| 503 | void show_code(struct pt_regs *regs)
|
| 504 | {
|
| 505 | char *mode = user_mode(regs) ? "User" : "Krnl";
|
| 506 | unsigned long addr, pswaddr, trapaddr;
|
| 507 | bool pgm_check;
|
| 508 | unsigned char code[64];
|
| 509 | char buffer[128], *ptr;
|
| 510 | int start, end, opsize, hops, i;
|
| 511 |
|
| 512 | pswaddr = regs->psw.addr;
|
| 513 | if (test_pt_regs_flag(regs, PIF_PSW_ADDR_ADJUSTED))
|
| 514 | pswaddr = __forward_psw(regs->psw, regs->int_code >> 16);
|
| 515 | pgm_check = test_pt_regs_flag(regs, PIF_PGM_CHECK);
|
| 516 | if (pgm_check)
|
| 517 | trapaddr = get_trap_ip(regs);
|
| 518 |
|
| 519 | for (start = 32; start && pswaddr >= 34 - start; start -= 2) {
|
| 520 | addr = pswaddr - 34 + start;
|
| 521 | if (copy_from_regs(regs, code + start - 2, (void *)addr, 2))
|
| 522 | break;
|
| 523 | }
|
| 524 | for (end = 32; end < 64; end += 2) {
|
| 525 | addr = pswaddr + end - 32;
|
| 526 | if (copy_from_regs(regs, code + end, (void *)addr, 2))
|
| 527 | break;
|
| 528 | }
|
| 529 |
|
| 530 | if ((pswaddr & 1) || start >= end) {
|
| 531 | printk("%s Code: Bad PSW.\n", mode);
|
| 532 | return;
|
| 533 | }
|
| 534 |
|
| 535 | while (start < 32) {
|
| 536 | for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
|
| 537 | if (!find_insn(code + start + i))
|
| 538 | break;
|
| 539 | i += insn_length(code[start + i]);
|
| 540 | }
|
| 541 | if (start + i == 32)
|
| 542 |
|
| 543 | break;
|
| 544 | start += 2;
|
| 545 | }
|
| 546 |
|
| 547 | printk("%s Code:\n", mode);
|
| 548 | hops = 0;
|
| 549 | while (start < end && hops < 8) {
|
| 550 | ptr = buffer;
|
| 551 | opsize = insn_length(code[start]);
|
| 552 | addr = pswaddr + start - 32;
|
| 553 | if (start == 32 && test_pt_regs_flag(regs, PIF_WARN_TRAP_SKIPPED))
|
| 554 | ptr += sprintf(ptr, " WARN RET >");
|
| 555 | else if (pgm_check && addr == trapaddr && start == 32)
|
| 556 | ptr += sprintf(ptr, " PGM+PSW >");
|
| 557 | else if (pgm_check && addr == trapaddr)
|
| 558 | ptr += sprintf(ptr, " PGM >");
|
| 559 | else if (start == 32)
|
| 560 | ptr += sprintf(ptr, " PSW >");
|
| 561 | else
|
| 562 | ptr += sprintf(ptr, " ");
|
| 563 | ptr += sprintf(ptr, "%px: ", (void *)addr);
|
| 564 | if (start + opsize >= end)
|
| 565 | break;
|
| 566 | for (i = 0; i < opsize; i++)
|
| 567 | ptr += sprintf(ptr, "%02x", code[start + i]);
|
| 568 | ptr += sprintf(ptr, "%*s", 13 - 2 * opsize, " ");
|
| 569 | ptr += print_insn(ptr, code + start, addr);
|
| 570 | start += opsize;
|
| 571 | printk("%s\n", buffer);
|
| 572 | hops++;
|
| 573 | }
|
| 574 | }
|
| 575 |
|
| 576 | void print_fn_code(unsigned char *code, unsigned long len)
|
| 577 | {
|
| 578 | char buffer[128], *ptr;
|
| 579 | int opsize, i;
|
| 580 |
|
| 581 | while (len) {
|
| 582 | ptr = buffer;
|
| 583 | opsize = insn_length(*code);
|
| 584 | if (opsize > len)
|
| 585 | break;
|
| 586 | ptr += sprintf(ptr, "%px: ", code);
|
| 587 | for (i = 0; i < opsize; i++)
|
| 588 | ptr += sprintf(ptr, "%02x", code[i]);
|
| 589 | *ptr++ = '\t';
|
| 590 | if (i < 4)
|
| 591 | *ptr++ = '\t';
|
| 592 | ptr += print_insn(ptr, code, (unsigned long) code);
|
| 593 | *ptr++ = '\n';
|
| 594 | *ptr++ = 0;
|
| 595 | printk("%s", buffer);
|
| 596 | code += opsize;
|
| 597 | len -= opsize;
|
| 598 | }
|
| 599 | }
|