1a17ae4c3SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2bb11e3bdSMartin Schwidefsky /*
3bb11e3bdSMartin Schwidefsky * Disassemble s390 instructions.
4bb11e3bdSMartin Schwidefsky *
5bb11e3bdSMartin Schwidefsky * Copyright IBM Corp. 2007
6bb11e3bdSMartin Schwidefsky * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7bb11e3bdSMartin Schwidefsky */
8bb11e3bdSMartin Schwidefsky
9bb11e3bdSMartin Schwidefsky #include <linux/sched.h>
10bb11e3bdSMartin Schwidefsky #include <linux/kernel.h>
11bb11e3bdSMartin Schwidefsky #include <linux/string.h>
12bb11e3bdSMartin Schwidefsky #include <linux/errno.h>
13bb11e3bdSMartin Schwidefsky #include <linux/ptrace.h>
14bb11e3bdSMartin Schwidefsky #include <linux/timer.h>
15bb11e3bdSMartin Schwidefsky #include <linux/mm.h>
16bb11e3bdSMartin Schwidefsky #include <linux/smp.h>
17bb11e3bdSMartin Schwidefsky #include <linux/init.h>
18bb11e3bdSMartin Schwidefsky #include <linux/interrupt.h>
19bb11e3bdSMartin Schwidefsky #include <linux/delay.h>
203994a52bSPaul Gortmaker #include <linux/export.h>
21bb11e3bdSMartin Schwidefsky #include <linux/kallsyms.h>
22bb11e3bdSMartin Schwidefsky #include <linux/reboot.h>
23bb11e3bdSMartin Schwidefsky #include <linux/kprobes.h>
2479df3c19SAdrian Bunk #include <linux/kdebug.h>
257c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
268bc1e4ecSHeiko Carstens #include <linux/atomic.h>
27b378a982SHeiko Carstens #include <linux/io.h>
28648ae35cSSuzuki K. Poulose #include <asm/dis.h>
29bb11e3bdSMartin Schwidefsky #include <asm/cpcmd.h>
30bb11e3bdSMartin Schwidefsky #include <asm/lowcore.h>
31bb11e3bdSMartin Schwidefsky #include <asm/debug.h>
32d7b250e2SHeiko Carstens #include <asm/irq.h>
33bb11e3bdSMartin Schwidefsky
348bc1e4ecSHeiko Carstens /* Type of operand */
358bc1e4ecSHeiko Carstens #define OPERAND_GPR 0x1 /* Operand printed as %rx */
368bc1e4ecSHeiko Carstens #define OPERAND_FPR 0x2 /* Operand printed as %fx */
378bc1e4ecSHeiko Carstens #define OPERAND_AR 0x4 /* Operand printed as %ax */
388bc1e4ecSHeiko Carstens #define OPERAND_CR 0x8 /* Operand printed as %cx */
398bc1e4ecSHeiko Carstens #define OPERAND_VR 0x10 /* Operand printed as %vx */
408bc1e4ecSHeiko Carstens #define OPERAND_DISP 0x20 /* Operand printed as displacement */
418bc1e4ecSHeiko Carstens #define OPERAND_BASE 0x40 /* Operand printed as base register */
428bc1e4ecSHeiko Carstens #define OPERAND_INDEX 0x80 /* Operand printed as index register */
438bc1e4ecSHeiko Carstens #define OPERAND_PCREL 0x100 /* Operand printed as pc-relative symbol */
448bc1e4ecSHeiko Carstens #define OPERAND_SIGNED 0x200 /* Operand printed as signed value */
458bc1e4ecSHeiko Carstens #define OPERAND_LENGTH 0x400 /* Operand printed as length (+1) */
468bc1e4ecSHeiko Carstens
478bc1e4ecSHeiko Carstens struct s390_operand {
488bc1e4ecSHeiko Carstens unsigned char bits; /* The number of bits in the operand. */
498bc1e4ecSHeiko Carstens unsigned char shift; /* The number of bits to shift. */
508bc1e4ecSHeiko Carstens unsigned short flags; /* One bit syntax flags. */
518bc1e4ecSHeiko Carstens };
528bc1e4ecSHeiko Carstens
538bc1e4ecSHeiko Carstens struct s390_insn {
548bc1e4ecSHeiko Carstens union {
558bc1e4ecSHeiko Carstens const char name[5];
568bc1e4ecSHeiko Carstens struct {
578bc1e4ecSHeiko Carstens unsigned char zero;
588bc1e4ecSHeiko Carstens unsigned int offset;
598bc1e4ecSHeiko Carstens } __packed;
608bc1e4ecSHeiko Carstens };
618bc1e4ecSHeiko Carstens unsigned char opfrag;
628bc1e4ecSHeiko Carstens unsigned char format;
638bc1e4ecSHeiko Carstens };
648bc1e4ecSHeiko Carstens
658bc1e4ecSHeiko Carstens struct s390_opcode_offset {
668bc1e4ecSHeiko Carstens unsigned char opcode;
678bc1e4ecSHeiko Carstens unsigned char mask;
688bc1e4ecSHeiko Carstens unsigned char byte;
698bc1e4ecSHeiko Carstens unsigned short offset;
708bc1e4ecSHeiko Carstens unsigned short count;
718bc1e4ecSHeiko Carstens } __packed;
728bc1e4ecSHeiko Carstens
73bb11e3bdSMartin Schwidefsky enum {
748bc1e4ecSHeiko Carstens UNUSED,
75bb11e3bdSMartin Schwidefsky A_8, /* Access reg. starting at position 8 */
76bb11e3bdSMartin Schwidefsky A_12, /* Access reg. starting at position 12 */
77bb11e3bdSMartin Schwidefsky A_24, /* Access reg. starting at position 24 */
78bb11e3bdSMartin Schwidefsky A_28, /* Access reg. starting at position 28 */
79bb11e3bdSMartin Schwidefsky B_16, /* Base register starting at position 16 */
80bb11e3bdSMartin Schwidefsky B_32, /* Base register starting at position 32 */
818bc1e4ecSHeiko Carstens C_8, /* Control reg. starting at position 8 */
828bc1e4ecSHeiko Carstens C_12, /* Control reg. starting at position 12 */
838bc1e4ecSHeiko Carstens D20_20, /* 20 bit displacement starting at 20 */
84bb11e3bdSMartin Schwidefsky D_20, /* Displacement starting at position 20 */
85bb11e3bdSMartin Schwidefsky D_36, /* Displacement starting at position 36 */
868bc1e4ecSHeiko Carstens F_8, /* FPR starting at position 8 */
878bc1e4ecSHeiko Carstens F_12, /* FPR starting at position 12 */
888bc1e4ecSHeiko Carstens F_16, /* FPR starting at position 16 */
898bc1e4ecSHeiko Carstens F_24, /* FPR starting at position 24 */
908bc1e4ecSHeiko Carstens F_28, /* FPR starting at position 28 */
918bc1e4ecSHeiko Carstens F_32, /* FPR starting at position 32 */
928bc1e4ecSHeiko Carstens I8_8, /* 8 bit signed value starting at 8 */
938bc1e4ecSHeiko Carstens I8_32, /* 8 bit signed value starting at 32 */
948bc1e4ecSHeiko Carstens I16_16, /* 16 bit signed value starting at 16 */
958bc1e4ecSHeiko Carstens I16_32, /* 16 bit signed value starting at 32 */
968bc1e4ecSHeiko Carstens I32_16, /* 32 bit signed value starting at 16 */
978bc1e4ecSHeiko Carstens J12_12, /* 12 bit PC relative offset at 12 */
988bc1e4ecSHeiko Carstens J16_16, /* 16 bit PC relative offset at 16 */
998bc1e4ecSHeiko Carstens J16_32, /* 16 bit PC relative offset at 32 */
1008bc1e4ecSHeiko Carstens J24_24, /* 24 bit PC relative offset at 24 */
1018bc1e4ecSHeiko Carstens J32_16, /* 32 bit PC relative offset at 16 */
102bb11e3bdSMartin Schwidefsky L4_8, /* 4 bit length starting at position 8 */
103bb11e3bdSMartin Schwidefsky L4_12, /* 4 bit length starting at position 12 */
104bb11e3bdSMartin Schwidefsky L8_8, /* 8 bit length starting at position 8 */
1058bc1e4ecSHeiko Carstens R_8, /* GPR starting at position 8 */
1068bc1e4ecSHeiko Carstens R_12, /* GPR starting at position 12 */
1078bc1e4ecSHeiko Carstens R_16, /* GPR starting at position 16 */
1088bc1e4ecSHeiko Carstens R_24, /* GPR starting at position 24 */
1098bc1e4ecSHeiko Carstens R_28, /* GPR starting at position 28 */
110bb11e3bdSMartin Schwidefsky U4_8, /* 4 bit unsigned value starting at 8 */
111bb11e3bdSMartin Schwidefsky U4_12, /* 4 bit unsigned value starting at 12 */
112bb11e3bdSMartin Schwidefsky U4_16, /* 4 bit unsigned value starting at 16 */
113bb11e3bdSMartin Schwidefsky U4_20, /* 4 bit unsigned value starting at 20 */
114c68dba20SHeiko Carstens U4_24, /* 4 bit unsigned value starting at 24 */
115c68dba20SHeiko Carstens U4_28, /* 4 bit unsigned value starting at 28 */
116618708ffSMartin Schwidefsky U4_32, /* 4 bit unsigned value starting at 32 */
117c68dba20SHeiko Carstens U4_36, /* 4 bit unsigned value starting at 36 */
118bb11e3bdSMartin Schwidefsky U8_8, /* 8 bit unsigned value starting at 8 */
119bb11e3bdSMartin Schwidefsky U8_16, /* 8 bit unsigned value starting at 16 */
120618708ffSMartin Schwidefsky U8_24, /* 8 bit unsigned value starting at 24 */
121e0d281d0SHeiko Carstens U8_28, /* 8 bit unsigned value starting at 28 */
122618708ffSMartin Schwidefsky U8_32, /* 8 bit unsigned value starting at 32 */
1238bc1e4ecSHeiko Carstens U12_16, /* 12 bit unsigned value starting at 16 */
124bb11e3bdSMartin Schwidefsky U16_16, /* 16 bit unsigned value starting at 16 */
1258bc1e4ecSHeiko Carstens U16_32, /* 16 bit unsigned value starting at 32 */
126bb11e3bdSMartin Schwidefsky U32_16, /* 32 bit unsigned value starting at 16 */
1278bc1e4ecSHeiko Carstens VX_12, /* Vector index register starting at position 12 */
1288bc1e4ecSHeiko Carstens V_8, /* Vector reg. starting at position 8 */
1298bc1e4ecSHeiko Carstens V_12, /* Vector reg. starting at position 12 */
1308bc1e4ecSHeiko Carstens V_16, /* Vector reg. starting at position 16 */
1318bc1e4ecSHeiko Carstens V_32, /* Vector reg. starting at position 32 */
1328bc1e4ecSHeiko Carstens X_12, /* Index register starting at position 12 */
133bb11e3bdSMartin Schwidefsky };
134bb11e3bdSMartin Schwidefsky
1358bc1e4ecSHeiko Carstens static const struct s390_operand operands[] = {
136bb11e3bdSMartin Schwidefsky [UNUSED] = { 0, 0, 0 },
137bb11e3bdSMartin Schwidefsky [A_8] = { 4, 8, OPERAND_AR },
138bb11e3bdSMartin Schwidefsky [A_12] = { 4, 12, OPERAND_AR },
139bb11e3bdSMartin Schwidefsky [A_24] = { 4, 24, OPERAND_AR },
140bb11e3bdSMartin Schwidefsky [A_28] = { 4, 28, OPERAND_AR },
141bb11e3bdSMartin Schwidefsky [B_16] = { 4, 16, OPERAND_BASE | OPERAND_GPR },
142bb11e3bdSMartin Schwidefsky [B_32] = { 4, 32, OPERAND_BASE | OPERAND_GPR },
1438bc1e4ecSHeiko Carstens [C_8] = { 4, 8, OPERAND_CR },
1448bc1e4ecSHeiko Carstens [C_12] = { 4, 12, OPERAND_CR },
1458bc1e4ecSHeiko Carstens [D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED },
146bb11e3bdSMartin Schwidefsky [D_20] = { 12, 20, OPERAND_DISP },
147bb11e3bdSMartin Schwidefsky [D_36] = { 12, 36, OPERAND_DISP },
1488bc1e4ecSHeiko Carstens [F_8] = { 4, 8, OPERAND_FPR },
1498bc1e4ecSHeiko Carstens [F_12] = { 4, 12, OPERAND_FPR },
1508bc1e4ecSHeiko Carstens [F_16] = { 4, 16, OPERAND_FPR },
1518bc1e4ecSHeiko Carstens [F_24] = { 4, 24, OPERAND_FPR },
1528bc1e4ecSHeiko Carstens [F_28] = { 4, 28, OPERAND_FPR },
1538bc1e4ecSHeiko Carstens [F_32] = { 4, 32, OPERAND_FPR },
1548bc1e4ecSHeiko Carstens [I8_8] = { 8, 8, OPERAND_SIGNED },
1558bc1e4ecSHeiko Carstens [I8_32] = { 8, 32, OPERAND_SIGNED },
1568bc1e4ecSHeiko Carstens [I16_16] = { 16, 16, OPERAND_SIGNED },
1578bc1e4ecSHeiko Carstens [I16_32] = { 16, 32, OPERAND_SIGNED },
1588bc1e4ecSHeiko Carstens [I32_16] = { 32, 16, OPERAND_SIGNED },
1598bc1e4ecSHeiko Carstens [J12_12] = { 12, 12, OPERAND_PCREL },
1608bc1e4ecSHeiko Carstens [J16_16] = { 16, 16, OPERAND_PCREL },
1618bc1e4ecSHeiko Carstens [J16_32] = { 16, 32, OPERAND_PCREL },
1628bc1e4ecSHeiko Carstens [J24_24] = { 24, 24, OPERAND_PCREL },
1638bc1e4ecSHeiko Carstens [J32_16] = { 32, 16, OPERAND_PCREL },
164bb11e3bdSMartin Schwidefsky [L4_8] = { 4, 8, OPERAND_LENGTH },
165bb11e3bdSMartin Schwidefsky [L4_12] = { 4, 12, OPERAND_LENGTH },
166bb11e3bdSMartin Schwidefsky [L8_8] = { 8, 8, OPERAND_LENGTH },
1678bc1e4ecSHeiko Carstens [R_8] = { 4, 8, OPERAND_GPR },
1688bc1e4ecSHeiko Carstens [R_12] = { 4, 12, OPERAND_GPR },
1698bc1e4ecSHeiko Carstens [R_16] = { 4, 16, OPERAND_GPR },
1708bc1e4ecSHeiko Carstens [R_24] = { 4, 24, OPERAND_GPR },
1718bc1e4ecSHeiko Carstens [R_28] = { 4, 28, OPERAND_GPR },
172bb11e3bdSMartin Schwidefsky [U4_8] = { 4, 8, 0 },
173bb11e3bdSMartin Schwidefsky [U4_12] = { 4, 12, 0 },
174bb11e3bdSMartin Schwidefsky [U4_16] = { 4, 16, 0 },
175bb11e3bdSMartin Schwidefsky [U4_20] = { 4, 20, 0 },
176c68dba20SHeiko Carstens [U4_24] = { 4, 24, 0 },
177c68dba20SHeiko Carstens [U4_28] = { 4, 28, 0 },
178618708ffSMartin Schwidefsky [U4_32] = { 4, 32, 0 },
179c68dba20SHeiko Carstens [U4_36] = { 4, 36, 0 },
180bb11e3bdSMartin Schwidefsky [U8_8] = { 8, 8, 0 },
181bb11e3bdSMartin Schwidefsky [U8_16] = { 8, 16, 0 },
182618708ffSMartin Schwidefsky [U8_24] = { 8, 24, 0 },
183e0d281d0SHeiko Carstens [U8_28] = { 8, 28, 0 },
184618708ffSMartin Schwidefsky [U8_32] = { 8, 32, 0 },
1858bc1e4ecSHeiko Carstens [U12_16] = { 12, 16, 0 },
186bb11e3bdSMartin Schwidefsky [U16_16] = { 16, 16, 0 },
187618708ffSMartin Schwidefsky [U16_32] = { 16, 32, 0 },
188bb11e3bdSMartin Schwidefsky [U32_16] = { 32, 16, 0 },
1898bc1e4ecSHeiko Carstens [VX_12] = { 4, 12, OPERAND_INDEX | OPERAND_VR },
1908bc1e4ecSHeiko Carstens [V_8] = { 4, 8, OPERAND_VR },
1918bc1e4ecSHeiko Carstens [V_12] = { 4, 12, OPERAND_VR },
1928bc1e4ecSHeiko Carstens [V_16] = { 4, 16, OPERAND_VR },
1938bc1e4ecSHeiko Carstens [V_32] = { 4, 32, OPERAND_VR },
1948bc1e4ecSHeiko Carstens [X_12] = { 4, 12, OPERAND_INDEX | OPERAND_GPR },
195bb11e3bdSMartin Schwidefsky };
196bb11e3bdSMartin Schwidefsky
1978bc1e4ecSHeiko Carstens static const unsigned char formats[][6] = {
1988bc1e4ecSHeiko Carstens [INSTR_E] = { 0, 0, 0, 0, 0, 0 },
1998bc1e4ecSHeiko Carstens [INSTR_IE_UU] = { U4_24, U4_28, 0, 0, 0, 0 },
2008bc1e4ecSHeiko Carstens [INSTR_MII_UPP] = { U4_8, J12_12, J24_24 },
2018bc1e4ecSHeiko Carstens [INSTR_RIE_R0IU] = { R_8, I16_16, U4_32, 0, 0, 0 },
2028bc1e4ecSHeiko Carstens [INSTR_RIE_R0UU] = { R_8, U16_16, U4_32, 0, 0, 0 },
2038bc1e4ecSHeiko Carstens [INSTR_RIE_RRI0] = { R_8, R_12, I16_16, 0, 0, 0 },
2048bc1e4ecSHeiko Carstens [INSTR_RIE_RRP] = { R_8, R_12, J16_16, 0, 0, 0 },
2058bc1e4ecSHeiko Carstens [INSTR_RIE_RRPU] = { R_8, R_12, U4_32, J16_16, 0, 0 },
2068bc1e4ecSHeiko Carstens [INSTR_RIE_RRUUU] = { R_8, R_12, U8_16, U8_24, U8_32, 0 },
2078bc1e4ecSHeiko Carstens [INSTR_RIE_RUI0] = { R_8, I16_16, U4_12, 0, 0, 0 },
2088bc1e4ecSHeiko Carstens [INSTR_RIE_RUPI] = { R_8, I8_32, U4_12, J16_16, 0, 0 },
2098bc1e4ecSHeiko Carstens [INSTR_RIE_RUPU] = { R_8, U8_32, U4_12, J16_16, 0, 0 },
2108bc1e4ecSHeiko Carstens [INSTR_RIL_RI] = { R_8, I32_16, 0, 0, 0, 0 },
2118bc1e4ecSHeiko Carstens [INSTR_RIL_RP] = { R_8, J32_16, 0, 0, 0, 0 },
2128bc1e4ecSHeiko Carstens [INSTR_RIL_RU] = { R_8, U32_16, 0, 0, 0, 0 },
2138bc1e4ecSHeiko Carstens [INSTR_RIL_UP] = { U4_8, J32_16, 0, 0, 0, 0 },
2148bc1e4ecSHeiko Carstens [INSTR_RIS_RURDI] = { R_8, I8_32, U4_12, D_20, B_16, 0 },
2158bc1e4ecSHeiko Carstens [INSTR_RIS_RURDU] = { R_8, U8_32, U4_12, D_20, B_16, 0 },
2168bc1e4ecSHeiko Carstens [INSTR_RI_RI] = { R_8, I16_16, 0, 0, 0, 0 },
2178bc1e4ecSHeiko Carstens [INSTR_RI_RP] = { R_8, J16_16, 0, 0, 0, 0 },
2188bc1e4ecSHeiko Carstens [INSTR_RI_RU] = { R_8, U16_16, 0, 0, 0, 0 },
2198bc1e4ecSHeiko Carstens [INSTR_RI_UP] = { U4_8, J16_16, 0, 0, 0, 0 },
2208bc1e4ecSHeiko Carstens [INSTR_RRE_00] = { 0, 0, 0, 0, 0, 0 },
2218bc1e4ecSHeiko Carstens [INSTR_RRE_AA] = { A_24, A_28, 0, 0, 0, 0 },
2228bc1e4ecSHeiko Carstens [INSTR_RRE_AR] = { A_24, R_28, 0, 0, 0, 0 },
2238bc1e4ecSHeiko Carstens [INSTR_RRE_F0] = { F_24, 0, 0, 0, 0, 0 },
2248bc1e4ecSHeiko Carstens [INSTR_RRE_FF] = { F_24, F_28, 0, 0, 0, 0 },
2258bc1e4ecSHeiko Carstens [INSTR_RRE_FR] = { F_24, R_28, 0, 0, 0, 0 },
2268bc1e4ecSHeiko Carstens [INSTR_RRE_R0] = { R_24, 0, 0, 0, 0, 0 },
2278bc1e4ecSHeiko Carstens [INSTR_RRE_RA] = { R_24, A_28, 0, 0, 0, 0 },
2288bc1e4ecSHeiko Carstens [INSTR_RRE_RF] = { R_24, F_28, 0, 0, 0, 0 },
2298bc1e4ecSHeiko Carstens [INSTR_RRE_RR] = { R_24, R_28, 0, 0, 0, 0 },
2308bc1e4ecSHeiko Carstens [INSTR_RRF_0UFF] = { F_24, F_28, U4_20, 0, 0, 0 },
2318bc1e4ecSHeiko Carstens [INSTR_RRF_0URF] = { R_24, F_28, U4_20, 0, 0, 0 },
2328bc1e4ecSHeiko Carstens [INSTR_RRF_F0FF] = { F_16, F_24, F_28, 0, 0, 0 },
2338bc1e4ecSHeiko Carstens [INSTR_RRF_F0FF2] = { F_24, F_16, F_28, 0, 0, 0 },
2348bc1e4ecSHeiko Carstens [INSTR_RRF_F0FR] = { F_24, F_16, R_28, 0, 0, 0 },
2358bc1e4ecSHeiko Carstens [INSTR_RRF_FFRU] = { F_24, F_16, R_28, U4_20, 0, 0 },
2368bc1e4ecSHeiko Carstens [INSTR_RRF_FUFF] = { F_24, F_16, F_28, U4_20, 0, 0 },
2378bc1e4ecSHeiko Carstens [INSTR_RRF_FUFF2] = { F_24, F_28, F_16, U4_20, 0, 0 },
2388bc1e4ecSHeiko Carstens [INSTR_RRF_R0RR] = { R_24, R_16, R_28, 0, 0, 0 },
2398bc1e4ecSHeiko Carstens [INSTR_RRF_R0RR2] = { R_24, R_28, R_16, 0, 0, 0 },
2408bc1e4ecSHeiko Carstens [INSTR_RRF_RURR] = { R_24, R_28, R_16, U4_20, 0, 0 },
2418bc1e4ecSHeiko Carstens [INSTR_RRF_RURR2] = { R_24, R_16, R_28, U4_20, 0, 0 },
2428bc1e4ecSHeiko Carstens [INSTR_RRF_U0FF] = { F_24, U4_16, F_28, 0, 0, 0 },
2438bc1e4ecSHeiko Carstens [INSTR_RRF_U0RF] = { R_24, U4_16, F_28, 0, 0, 0 },
2448bc1e4ecSHeiko Carstens [INSTR_RRF_U0RR] = { R_24, R_28, U4_16, 0, 0, 0 },
245fc20f0c1SMartin Schwidefsky [INSTR_RRF_URR] = { R_24, R_28, U8_16, 0, 0, 0 },
2468bc1e4ecSHeiko Carstens [INSTR_RRF_UUFF] = { F_24, U4_16, F_28, U4_20, 0, 0 },
2478bc1e4ecSHeiko Carstens [INSTR_RRF_UUFR] = { F_24, U4_16, R_28, U4_20, 0, 0 },
2488bc1e4ecSHeiko Carstens [INSTR_RRF_UURF] = { R_24, U4_16, F_28, U4_20, 0, 0 },
2498bc1e4ecSHeiko Carstens [INSTR_RRS_RRRDU] = { R_8, R_12, U4_32, D_20, B_16 },
2508bc1e4ecSHeiko Carstens [INSTR_RR_FF] = { F_8, F_12, 0, 0, 0, 0 },
2518bc1e4ecSHeiko Carstens [INSTR_RR_R0] = { R_8, 0, 0, 0, 0, 0 },
2528bc1e4ecSHeiko Carstens [INSTR_RR_RR] = { R_8, R_12, 0, 0, 0, 0 },
2538bc1e4ecSHeiko Carstens [INSTR_RR_U0] = { U8_8, 0, 0, 0, 0, 0 },
2548bc1e4ecSHeiko Carstens [INSTR_RR_UR] = { U4_8, R_12, 0, 0, 0, 0 },
2558bc1e4ecSHeiko Carstens [INSTR_RSI_RRP] = { R_8, R_12, J16_16, 0, 0, 0 },
2568bc1e4ecSHeiko Carstens [INSTR_RSL_LRDFU] = { F_32, D_20, L8_8, B_16, U4_36, 0 },
2578bc1e4ecSHeiko Carstens [INSTR_RSL_R0RD] = { D_20, L4_8, B_16, 0, 0, 0 },
2588bc1e4ecSHeiko Carstens [INSTR_RSY_AARD] = { A_8, A_12, D20_20, B_16, 0, 0 },
2598bc1e4ecSHeiko Carstens [INSTR_RSY_CCRD] = { C_8, C_12, D20_20, B_16, 0, 0 },
2608bc1e4ecSHeiko Carstens [INSTR_RSY_RDRU] = { R_8, D20_20, B_16, U4_12, 0, 0 },
2618bc1e4ecSHeiko Carstens [INSTR_RSY_RRRD] = { R_8, R_12, D20_20, B_16, 0, 0 },
2628bc1e4ecSHeiko Carstens [INSTR_RSY_RURD] = { R_8, U4_12, D20_20, B_16, 0, 0 },
2638bc1e4ecSHeiko Carstens [INSTR_RSY_RURD2] = { R_8, D20_20, B_16, U4_12, 0, 0 },
2648bc1e4ecSHeiko Carstens [INSTR_RS_AARD] = { A_8, A_12, D_20, B_16, 0, 0 },
2658bc1e4ecSHeiko Carstens [INSTR_RS_CCRD] = { C_8, C_12, D_20, B_16, 0, 0 },
2668bc1e4ecSHeiko Carstens [INSTR_RS_R0RD] = { R_8, D_20, B_16, 0, 0, 0 },
2678bc1e4ecSHeiko Carstens [INSTR_RS_RRRD] = { R_8, R_12, D_20, B_16, 0, 0 },
2688bc1e4ecSHeiko Carstens [INSTR_RS_RURD] = { R_8, U4_12, D_20, B_16, 0, 0 },
2698bc1e4ecSHeiko Carstens [INSTR_RXE_FRRD] = { F_8, D_20, X_12, B_16, 0, 0 },
2708bc1e4ecSHeiko Carstens [INSTR_RXE_RRRDU] = { R_8, D_20, X_12, B_16, U4_32, 0 },
2718bc1e4ecSHeiko Carstens [INSTR_RXF_FRRDF] = { F_32, F_8, D_20, X_12, B_16, 0 },
2728bc1e4ecSHeiko Carstens [INSTR_RXY_FRRD] = { F_8, D20_20, X_12, B_16, 0, 0 },
2738bc1e4ecSHeiko Carstens [INSTR_RXY_RRRD] = { R_8, D20_20, X_12, B_16, 0, 0 },
2748bc1e4ecSHeiko Carstens [INSTR_RXY_URRD] = { U4_8, D20_20, X_12, B_16, 0, 0 },
2758bc1e4ecSHeiko Carstens [INSTR_RX_FRRD] = { F_8, D_20, X_12, B_16, 0, 0 },
2768bc1e4ecSHeiko Carstens [INSTR_RX_RRRD] = { R_8, D_20, X_12, B_16, 0, 0 },
2778bc1e4ecSHeiko Carstens [INSTR_RX_URRD] = { U4_8, D_20, X_12, B_16, 0, 0 },
2788bc1e4ecSHeiko Carstens [INSTR_SIL_RDI] = { D_20, B_16, I16_32, 0, 0, 0 },
2798bc1e4ecSHeiko Carstens [INSTR_SIL_RDU] = { D_20, B_16, U16_32, 0, 0, 0 },
2808bc1e4ecSHeiko Carstens [INSTR_SIY_IRD] = { D20_20, B_16, I8_8, 0, 0, 0 },
28124842079SHeiko Carstens [INSTR_SIY_RD] = { D20_20, B_16, 0, 0, 0, 0 },
2828bc1e4ecSHeiko Carstens [INSTR_SIY_URD] = { D20_20, B_16, U8_8, 0, 0, 0 },
2838bc1e4ecSHeiko Carstens [INSTR_SI_RD] = { D_20, B_16, 0, 0, 0, 0 },
2848bc1e4ecSHeiko Carstens [INSTR_SI_URD] = { D_20, B_16, U8_8, 0, 0, 0 },
2858bc1e4ecSHeiko Carstens [INSTR_SMI_U0RDP] = { U4_8, J16_32, D_20, B_16, 0, 0 },
2868bc1e4ecSHeiko Carstens [INSTR_SSE_RDRD] = { D_20, B_16, D_36, B_32, 0, 0 },
2878bc1e4ecSHeiko Carstens [INSTR_SSF_RRDRD] = { D_20, B_16, D_36, B_32, R_8, 0 },
2888bc1e4ecSHeiko Carstens [INSTR_SSF_RRDRD2] = { R_8, D_20, B_16, D_36, B_32, 0 },
2898bc1e4ecSHeiko Carstens [INSTR_SS_L0RDRD] = { D_20, L8_8, B_16, D_36, B_32, 0 },
2908bc1e4ecSHeiko Carstens [INSTR_SS_L2RDRD] = { D_20, B_16, D_36, L8_8, B_32, 0 },
2918bc1e4ecSHeiko Carstens [INSTR_SS_LIRDRD] = { D_20, L4_8, B_16, D_36, B_32, U4_12 },
2928bc1e4ecSHeiko Carstens [INSTR_SS_LLRDRD] = { D_20, L4_8, B_16, D_36, L4_12, B_32 },
2938bc1e4ecSHeiko Carstens [INSTR_SS_RRRDRD] = { D_20, R_8, B_16, D_36, B_32, R_12 },
2948bc1e4ecSHeiko Carstens [INSTR_SS_RRRDRD2] = { R_8, D_20, B_16, R_12, D_36, B_32 },
2958bc1e4ecSHeiko Carstens [INSTR_SS_RRRDRD3] = { R_8, R_12, D_20, B_16, D_36, B_32 },
2968bc1e4ecSHeiko Carstens [INSTR_S_00] = { 0, 0, 0, 0, 0, 0 },
2978bc1e4ecSHeiko Carstens [INSTR_S_RD] = { D_20, B_16, 0, 0, 0, 0 },
2988bc1e4ecSHeiko Carstens [INSTR_VRI_V0IU] = { V_8, I16_16, U4_32, 0, 0, 0 },
2998bc1e4ecSHeiko Carstens [INSTR_VRI_V0U] = { V_8, U16_16, 0, 0, 0, 0 },
3008bc1e4ecSHeiko Carstens [INSTR_VRI_V0UU2] = { V_8, U16_16, U4_32, 0, 0, 0 },
3018bc1e4ecSHeiko Carstens [INSTR_VRI_V0UUU] = { V_8, U8_16, U8_24, U4_32, 0, 0 },
3028bc1e4ecSHeiko Carstens [INSTR_VRI_VR0UU] = { V_8, R_12, U8_28, U4_24, 0, 0 },
3038bc1e4ecSHeiko Carstens [INSTR_VRI_VVUU] = { V_8, V_12, U16_16, U4_32, 0, 0 },
3048bc1e4ecSHeiko Carstens [INSTR_VRI_VVUUU] = { V_8, V_12, U12_16, U4_32, U4_28, 0 },
3058bc1e4ecSHeiko Carstens [INSTR_VRI_VVUUU2] = { V_8, V_12, U8_28, U8_16, U4_24, 0 },
3068bc1e4ecSHeiko Carstens [INSTR_VRI_VVV0U] = { V_8, V_12, V_16, U8_24, 0, 0 },
3078bc1e4ecSHeiko Carstens [INSTR_VRI_VVV0UU] = { V_8, V_12, V_16, U8_24, U4_32, 0 },
3088bc1e4ecSHeiko Carstens [INSTR_VRI_VVV0UU2] = { V_8, V_12, V_16, U8_28, U4_24, 0 },
3098bc1e4ecSHeiko Carstens [INSTR_VRR_0V] = { V_12, 0, 0, 0, 0, 0 },
3108bc1e4ecSHeiko Carstens [INSTR_VRR_0VV0U] = { V_12, V_16, U4_24, 0, 0, 0 },
311fc20f0c1SMartin Schwidefsky [INSTR_VRR_RV0UU] = { R_8, V_12, U4_24, U4_28, 0, 0 },
3128bc1e4ecSHeiko Carstens [INSTR_VRR_VRR] = { V_8, R_12, R_16, 0, 0, 0 },
3138bc1e4ecSHeiko Carstens [INSTR_VRR_VV] = { V_8, V_12, 0, 0, 0, 0 },
3148bc1e4ecSHeiko Carstens [INSTR_VRR_VV0U] = { V_8, V_12, U4_32, 0, 0, 0 },
3158bc1e4ecSHeiko Carstens [INSTR_VRR_VV0U0U] = { V_8, V_12, U4_32, U4_24, 0, 0 },
316196e3c6aSHeiko Carstens [INSTR_VRR_VV0U2] = { V_8, V_12, U4_24, 0, 0, 0 },
3178bc1e4ecSHeiko Carstens [INSTR_VRR_VV0UU2] = { V_8, V_12, U4_32, U4_28, 0, 0 },
3188bc1e4ecSHeiko Carstens [INSTR_VRR_VV0UUU] = { V_8, V_12, U4_32, U4_28, U4_24, 0 },
3198bc1e4ecSHeiko Carstens [INSTR_VRR_VVV] = { V_8, V_12, V_16, 0, 0, 0 },
3208bc1e4ecSHeiko Carstens [INSTR_VRR_VVV0U] = { V_8, V_12, V_16, U4_32, 0, 0 },
321196e3c6aSHeiko Carstens [INSTR_VRR_VVV0U0] = { V_8, V_12, V_16, U4_24, 0, 0 },
3228bc1e4ecSHeiko Carstens [INSTR_VRR_VVV0U0U] = { V_8, V_12, V_16, U4_32, U4_24, 0 },
3238bc1e4ecSHeiko Carstens [INSTR_VRR_VVV0UU] = { V_8, V_12, V_16, U4_32, U4_28, 0 },
3248bc1e4ecSHeiko Carstens [INSTR_VRR_VVV0UUU] = { V_8, V_12, V_16, U4_32, U4_28, U4_24 },
3258bc1e4ecSHeiko Carstens [INSTR_VRR_VVV0V] = { V_8, V_12, V_16, V_32, 0, 0 },
3268bc1e4ecSHeiko Carstens [INSTR_VRR_VVVU0UV] = { V_8, V_12, V_16, V_32, U4_28, U4_20 },
3278bc1e4ecSHeiko Carstens [INSTR_VRR_VVVU0V] = { V_8, V_12, V_16, V_32, U4_20, 0 },
3288bc1e4ecSHeiko Carstens [INSTR_VRR_VVVUU0V] = { V_8, V_12, V_16, V_32, U4_20, U4_24 },
3298bc1e4ecSHeiko Carstens [INSTR_VRS_RRDV] = { V_32, R_12, D_20, B_16, 0, 0 },
3308bc1e4ecSHeiko Carstens [INSTR_VRS_RVRDU] = { R_8, V_12, D_20, B_16, U4_32, 0 },
3318bc1e4ecSHeiko Carstens [INSTR_VRS_VRRD] = { V_8, R_12, D_20, B_16, 0, 0 },
3328bc1e4ecSHeiko Carstens [INSTR_VRS_VRRDU] = { V_8, R_12, D_20, B_16, U4_32, 0 },
3338bc1e4ecSHeiko Carstens [INSTR_VRS_VVRDU] = { V_8, V_12, D_20, B_16, U4_32, 0 },
3348bc1e4ecSHeiko Carstens [INSTR_VRV_VVXRDU] = { V_8, D_20, VX_12, B_16, U4_32, 0 },
3358bc1e4ecSHeiko Carstens [INSTR_VRX_VRRDU] = { V_8, D_20, X_12, B_16, U4_32, 0 },
3368bc1e4ecSHeiko Carstens [INSTR_VRX_VV] = { V_8, V_12, 0, 0, 0, 0 },
3378bc1e4ecSHeiko Carstens [INSTR_VSI_URDV] = { V_32, D_20, B_16, U8_8, 0, 0 },
338bb11e3bdSMartin Schwidefsky };
339bb11e3bdSMartin Schwidefsky
3408bc1e4ecSHeiko Carstens static char long_insn_name[][7] = LONG_INSN_INITIALIZER;
3418bc1e4ecSHeiko Carstens static struct s390_insn opcode[] = OPCODE_TABLE_INITIALIZER;
3428bc1e4ecSHeiko Carstens static struct s390_opcode_offset opcode_offset[] = OPCODE_OFFSET_INITIALIZER;
343bb11e3bdSMartin Schwidefsky
344bb11e3bdSMartin Schwidefsky /* Extracts an operand value from an instruction. */
extract_operand(unsigned char * code,const struct s390_operand * operand)345bb11e3bdSMartin Schwidefsky static unsigned int extract_operand(unsigned char *code,
346f616d676SSuzuki K. Poulose const struct s390_operand *operand)
347bb11e3bdSMartin Schwidefsky {
3483585cb02SMartin Schwidefsky unsigned char *cp;
349bb11e3bdSMartin Schwidefsky unsigned int val;
350bb11e3bdSMartin Schwidefsky int bits;
351bb11e3bdSMartin Schwidefsky
352bb11e3bdSMartin Schwidefsky /* Extract fragments of the operand byte for byte. */
3533585cb02SMartin Schwidefsky cp = code + operand->shift / 8;
354bb11e3bdSMartin Schwidefsky bits = (operand->shift & 7) + operand->bits;
355bb11e3bdSMartin Schwidefsky val = 0;
356bb11e3bdSMartin Schwidefsky do {
357bb11e3bdSMartin Schwidefsky val <<= 8;
3583585cb02SMartin Schwidefsky val |= (unsigned int) *cp++;
359bb11e3bdSMartin Schwidefsky bits -= 8;
360bb11e3bdSMartin Schwidefsky } while (bits > 0);
361bb11e3bdSMartin Schwidefsky val >>= -bits;
362bb11e3bdSMartin Schwidefsky val &= ((1U << (operand->bits - 1)) << 1) - 1;
363bb11e3bdSMartin Schwidefsky
364bb11e3bdSMartin Schwidefsky /* Check for special long displacement case. */
365bb11e3bdSMartin Schwidefsky if (operand->bits == 20 && operand->shift == 20)
366bb11e3bdSMartin Schwidefsky val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
367bb11e3bdSMartin Schwidefsky
3683585cb02SMartin Schwidefsky /* Check for register extensions bits for vector registers. */
3693585cb02SMartin Schwidefsky if (operand->flags & OPERAND_VR) {
3703585cb02SMartin Schwidefsky if (operand->shift == 8)
3713585cb02SMartin Schwidefsky val |= (code[4] & 8) << 1;
3723585cb02SMartin Schwidefsky else if (operand->shift == 12)
3733585cb02SMartin Schwidefsky val |= (code[4] & 4) << 2;
3743585cb02SMartin Schwidefsky else if (operand->shift == 16)
3753585cb02SMartin Schwidefsky val |= (code[4] & 2) << 3;
3763585cb02SMartin Schwidefsky else if (operand->shift == 32)
3773585cb02SMartin Schwidefsky val |= (code[4] & 1) << 4;
3783585cb02SMartin Schwidefsky }
3793585cb02SMartin Schwidefsky
380bb11e3bdSMartin Schwidefsky /* Sign extend value if the operand is signed or pc relative. */
381bb11e3bdSMartin Schwidefsky if ((operand->flags & (OPERAND_SIGNED | OPERAND_PCREL)) &&
382bb11e3bdSMartin Schwidefsky (val & (1U << (operand->bits - 1))))
383bb11e3bdSMartin Schwidefsky val |= (-1U << (operand->bits - 1)) << 1;
384bb11e3bdSMartin Schwidefsky
385bb11e3bdSMartin Schwidefsky /* Double value if the operand is pc relative. */
386bb11e3bdSMartin Schwidefsky if (operand->flags & OPERAND_PCREL)
387bb11e3bdSMartin Schwidefsky val <<= 1;
388bb11e3bdSMartin Schwidefsky
389bb11e3bdSMartin Schwidefsky /* Length x in an instructions has real length x + 1. */
390bb11e3bdSMartin Schwidefsky if (operand->flags & OPERAND_LENGTH)
391bb11e3bdSMartin Schwidefsky val++;
392bb11e3bdSMartin Schwidefsky return val;
393bb11e3bdSMartin Schwidefsky }
394bb11e3bdSMartin Schwidefsky
find_insn(unsigned char * code)3951ffa11abSHeiko Carstens struct s390_insn *find_insn(unsigned char *code)
396bb11e3bdSMartin Schwidefsky {
3978bc1e4ecSHeiko Carstens struct s390_opcode_offset *entry;
3988bc1e4ecSHeiko Carstens struct s390_insn *insn;
3998bc1e4ecSHeiko Carstens unsigned char opfrag;
4008bc1e4ecSHeiko Carstens int i;
401bb11e3bdSMartin Schwidefsky
402de35089cSHeiko Carstens /* Search the opcode offset table to find an entry which
403de35089cSHeiko Carstens * matches the beginning of the opcode. If there is no match
404de35089cSHeiko Carstens * the last entry will be used, which is the default entry for
405de35089cSHeiko Carstens * unknown instructions as well as 1-byte opcode instructions.
406de35089cSHeiko Carstens */
4078bc1e4ecSHeiko Carstens for (i = 0; i < ARRAY_SIZE(opcode_offset); i++) {
4088bc1e4ecSHeiko Carstens entry = &opcode_offset[i];
409de35089cSHeiko Carstens if (entry->opcode == code[0])
410bb11e3bdSMartin Schwidefsky break;
411bb11e3bdSMartin Schwidefsky }
4128bc1e4ecSHeiko Carstens
4138bc1e4ecSHeiko Carstens opfrag = *(code + entry->byte) & entry->mask;
4148bc1e4ecSHeiko Carstens
4158bc1e4ecSHeiko Carstens insn = &opcode[entry->offset];
4168bc1e4ecSHeiko Carstens for (i = 0; i < entry->count; i++) {
4178bc1e4ecSHeiko Carstens if (insn->opfrag == opfrag)
4188bc1e4ecSHeiko Carstens return insn;
4198bc1e4ecSHeiko Carstens insn++;
420bb11e3bdSMartin Schwidefsky }
421bb11e3bdSMartin Schwidefsky return NULL;
422bb11e3bdSMartin Schwidefsky }
423bb11e3bdSMartin Schwidefsky
print_insn(char * buffer,unsigned char * code,unsigned long addr)424bb11e3bdSMartin Schwidefsky static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
425bb11e3bdSMartin Schwidefsky {
426f616d676SSuzuki K. Poulose struct s390_insn *insn;
427bb11e3bdSMartin Schwidefsky const unsigned char *ops;
428f616d676SSuzuki K. Poulose const struct s390_operand *operand;
429bb11e3bdSMartin Schwidefsky unsigned int value;
430bb11e3bdSMartin Schwidefsky char separator;
431bb11e3bdSMartin Schwidefsky char *ptr;
43274ccbdc2SMartin Schwidefsky int i;
433bb11e3bdSMartin Schwidefsky
434bb11e3bdSMartin Schwidefsky ptr = buffer;
435bb11e3bdSMartin Schwidefsky insn = find_insn(code);
436bb11e3bdSMartin Schwidefsky if (insn) {
4378bc1e4ecSHeiko Carstens if (insn->zero == 0)
4388bc1e4ecSHeiko Carstens ptr += sprintf(ptr, "%.7s\t",
4398bc1e4ecSHeiko Carstens long_insn_name[insn->offset]);
4408b8c12b1SMartin Schwidefsky else
441bb11e3bdSMartin Schwidefsky ptr += sprintf(ptr, "%.5s\t", insn->name);
442bb11e3bdSMartin Schwidefsky /* Extract the operands. */
443bb11e3bdSMartin Schwidefsky separator = 0;
4448bc1e4ecSHeiko Carstens for (ops = formats[insn->format], i = 0;
44574ccbdc2SMartin Schwidefsky *ops != 0 && i < 6; ops++, i++) {
446bb11e3bdSMartin Schwidefsky operand = operands + *ops;
447bb11e3bdSMartin Schwidefsky value = extract_operand(code, operand);
448bb11e3bdSMartin Schwidefsky if ((operand->flags & OPERAND_INDEX) && value == 0)
449bb11e3bdSMartin Schwidefsky continue;
450bb11e3bdSMartin Schwidefsky if ((operand->flags & OPERAND_BASE) &&
451bb11e3bdSMartin Schwidefsky value == 0 && separator == '(') {
452bb11e3bdSMartin Schwidefsky separator = ',';
453bb11e3bdSMartin Schwidefsky continue;
454bb11e3bdSMartin Schwidefsky }
455bb11e3bdSMartin Schwidefsky if (separator)
456bb11e3bdSMartin Schwidefsky ptr += sprintf(ptr, "%c", separator);
457bb11e3bdSMartin Schwidefsky if (operand->flags & OPERAND_GPR)
458ee8479bbSHeiko Carstens ptr += sprintf(ptr, "%%r%i", value);
459bb11e3bdSMartin Schwidefsky else if (operand->flags & OPERAND_FPR)
460ee8479bbSHeiko Carstens ptr += sprintf(ptr, "%%f%i", value);
461bb11e3bdSMartin Schwidefsky else if (operand->flags & OPERAND_AR)
462ee8479bbSHeiko Carstens ptr += sprintf(ptr, "%%a%i", value);
463bb11e3bdSMartin Schwidefsky else if (operand->flags & OPERAND_CR)
464ee8479bbSHeiko Carstens ptr += sprintf(ptr, "%%c%i", value);
4653585cb02SMartin Schwidefsky else if (operand->flags & OPERAND_VR)
466ee8479bbSHeiko Carstens ptr += sprintf(ptr, "%%v%i", value);
467544f1d62SIlya Leoshkevich else if (operand->flags & OPERAND_PCREL) {
468544f1d62SIlya Leoshkevich void *pcrel = (void *)((int)value + addr);
469544f1d62SIlya Leoshkevich
470544f1d62SIlya Leoshkevich ptr += sprintf(ptr, "%px", pcrel);
471544f1d62SIlya Leoshkevich } else if (operand->flags & OPERAND_SIGNED)
472bb11e3bdSMartin Schwidefsky ptr += sprintf(ptr, "%i", value);
473bb11e3bdSMartin Schwidefsky else
474bb11e3bdSMartin Schwidefsky ptr += sprintf(ptr, "%u", value);
475bb11e3bdSMartin Schwidefsky if (operand->flags & OPERAND_DISP)
476bb11e3bdSMartin Schwidefsky separator = '(';
477bb11e3bdSMartin Schwidefsky else if (operand->flags & OPERAND_BASE) {
478bb11e3bdSMartin Schwidefsky ptr += sprintf(ptr, ")");
479bb11e3bdSMartin Schwidefsky separator = ',';
480bb11e3bdSMartin Schwidefsky } else
481bb11e3bdSMartin Schwidefsky separator = ',';
482bb11e3bdSMartin Schwidefsky }
483bb11e3bdSMartin Schwidefsky } else
484bb11e3bdSMartin Schwidefsky ptr += sprintf(ptr, "unknown");
485bb11e3bdSMartin Schwidefsky return (int) (ptr - buffer);
486bb11e3bdSMartin Schwidefsky }
487bb11e3bdSMartin Schwidefsky
copy_from_regs(struct pt_regs * regs,void * dst,void * src,int len)488fc3f61e1SHeiko Carstens static int copy_from_regs(struct pt_regs *regs, void *dst, void *src, int len)
489fc3f61e1SHeiko Carstens {
490fc3f61e1SHeiko Carstens if (user_mode(regs)) {
491fc3f61e1SHeiko Carstens if (copy_from_user(dst, (char __user *)src, len))
492fc3f61e1SHeiko Carstens return -EFAULT;
493fc3f61e1SHeiko Carstens } else {
494fc3f61e1SHeiko Carstens if (copy_from_kernel_nofault(dst, src, len))
495fc3f61e1SHeiko Carstens return -EFAULT;
496fc3f61e1SHeiko Carstens }
497fc3f61e1SHeiko Carstens return 0;
498fc3f61e1SHeiko Carstens }
499fc3f61e1SHeiko Carstens
show_code(struct pt_regs * regs)500bb11e3bdSMartin Schwidefsky void show_code(struct pt_regs *regs)
501bb11e3bdSMartin Schwidefsky {
5027d256175SHeiko Carstens char *mode = user_mode(regs) ? "User" : "Krnl";
503bb11e3bdSMartin Schwidefsky unsigned char code[64];
504b192571dSVasily Gorbik char buffer[128], *ptr;
505bb11e3bdSMartin Schwidefsky unsigned long addr;
506bb11e3bdSMartin Schwidefsky int start, end, opsize, hops, i;
507bb11e3bdSMartin Schwidefsky
508bb11e3bdSMartin Schwidefsky /* Get a snapshot of the 64 bytes surrounding the fault address. */
509bb11e3bdSMartin Schwidefsky for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) {
510bb11e3bdSMartin Schwidefsky addr = regs->psw.addr - 34 + start;
511fc3f61e1SHeiko Carstens if (copy_from_regs(regs, code + start - 2, (void *)addr, 2))
512bb11e3bdSMartin Schwidefsky break;
513bb11e3bdSMartin Schwidefsky }
514bb11e3bdSMartin Schwidefsky for (end = 32; end < 64; end += 2) {
515bb11e3bdSMartin Schwidefsky addr = regs->psw.addr + end - 32;
516fc3f61e1SHeiko Carstens if (copy_from_regs(regs, code + end, (void *)addr, 2))
517bb11e3bdSMartin Schwidefsky break;
518bb11e3bdSMartin Schwidefsky }
519*cada938aSHeiko Carstens /* Code snapshot usable ? */
520bb11e3bdSMartin Schwidefsky if ((regs->psw.addr & 1) || start >= end) {
521bb11e3bdSMartin Schwidefsky printk("%s Code: Bad PSW.\n", mode);
522bb11e3bdSMartin Schwidefsky return;
523bb11e3bdSMartin Schwidefsky }
524bb11e3bdSMartin Schwidefsky /* Find a starting point for the disassembly. */
525bb11e3bdSMartin Schwidefsky while (start < 32) {
526bb11e3bdSMartin Schwidefsky for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
527bb11e3bdSMartin Schwidefsky if (!find_insn(code + start + i))
528bb11e3bdSMartin Schwidefsky break;
529bb11e3bdSMartin Schwidefsky i += insn_length(code[start + i]);
530bb11e3bdSMartin Schwidefsky }
531bb11e3bdSMartin Schwidefsky if (start + i == 32)
532bb11e3bdSMartin Schwidefsky /* Looks good, sequence ends at PSW. */
533bb11e3bdSMartin Schwidefsky break;
534bb11e3bdSMartin Schwidefsky start += 2;
535bb11e3bdSMartin Schwidefsky }
536bb11e3bdSMartin Schwidefsky /* Decode the instructions. */
537bb11e3bdSMartin Schwidefsky ptr = buffer;
538bb11e3bdSMartin Schwidefsky ptr += sprintf(ptr, "%s Code:", mode);
539bb11e3bdSMartin Schwidefsky hops = 0;
540bb11e3bdSMartin Schwidefsky while (start < end && hops < 8) {
5412fa1d4fcSHeiko Carstens opsize = insn_length(code[start]);
5422fa1d4fcSHeiko Carstens if (start + opsize == 32)
5432fa1d4fcSHeiko Carstens *ptr++ = '#';
5442fa1d4fcSHeiko Carstens else if (start == 32)
5452fa1d4fcSHeiko Carstens *ptr++ = '>';
5462fa1d4fcSHeiko Carstens else
5472fa1d4fcSHeiko Carstens *ptr++ = ' ';
548bb11e3bdSMartin Schwidefsky addr = regs->psw.addr + start - 32;
549544f1d62SIlya Leoshkevich ptr += sprintf(ptr, "%px: ", (void *)addr);
550bb11e3bdSMartin Schwidefsky if (start + opsize >= end)
551bb11e3bdSMartin Schwidefsky break;
552bb11e3bdSMartin Schwidefsky for (i = 0; i < opsize; i++)
553bb11e3bdSMartin Schwidefsky ptr += sprintf(ptr, "%02x", code[start + i]);
554bb11e3bdSMartin Schwidefsky *ptr++ = '\t';
555bb11e3bdSMartin Schwidefsky if (i < 6)
556bb11e3bdSMartin Schwidefsky *ptr++ = '\t';
557bb11e3bdSMartin Schwidefsky ptr += print_insn(ptr, code + start, addr);
558bb11e3bdSMartin Schwidefsky start += opsize;
5594d062487SHeiko Carstens pr_cont("%s", buffer);
560bb11e3bdSMartin Schwidefsky ptr = buffer;
56126f4e759SVasily Gorbik ptr += sprintf(ptr, "\n ");
562bb11e3bdSMartin Schwidefsky hops++;
563bb11e3bdSMartin Schwidefsky }
5644d062487SHeiko Carstens pr_cont("\n");
565bb11e3bdSMartin Schwidefsky }
566c10302efSMartin Schwidefsky
print_fn_code(unsigned char * code,unsigned long len)567c10302efSMartin Schwidefsky void print_fn_code(unsigned char *code, unsigned long len)
568c10302efSMartin Schwidefsky {
5696f3353c2SVasily Gorbik char buffer[128], *ptr;
570c10302efSMartin Schwidefsky int opsize, i;
571c10302efSMartin Schwidefsky
572c10302efSMartin Schwidefsky while (len) {
573c10302efSMartin Schwidefsky ptr = buffer;
574c10302efSMartin Schwidefsky opsize = insn_length(*code);
5757678dcfbSHeiko Carstens if (opsize > len)
5767678dcfbSHeiko Carstens break;
577544f1d62SIlya Leoshkevich ptr += sprintf(ptr, "%px: ", code);
578c10302efSMartin Schwidefsky for (i = 0; i < opsize; i++)
579c10302efSMartin Schwidefsky ptr += sprintf(ptr, "%02x", code[i]);
580c10302efSMartin Schwidefsky *ptr++ = '\t';
581c10302efSMartin Schwidefsky if (i < 4)
582c10302efSMartin Schwidefsky *ptr++ = '\t';
583c10302efSMartin Schwidefsky ptr += print_insn(ptr, code, (unsigned long) code);
584c10302efSMartin Schwidefsky *ptr++ = '\n';
585c10302efSMartin Schwidefsky *ptr++ = 0;
586561e1030SChristian Borntraeger printk("%s", buffer);
587c10302efSMartin Schwidefsky code += opsize;
588c10302efSMartin Schwidefsky len -= opsize;
589c10302efSMartin Schwidefsky }
590c10302efSMartin Schwidefsky }
591