xref: /openbmc/linux/arch/x86/mm/pf_in.c (revision ff3a3e9ba5e4273a8bc10570adab4a390fb90757)
1*ff3a3e9bSPekka Paalanen /*
2*ff3a3e9bSPekka Paalanen  *  Fault Injection Test harness (FI)
3*ff3a3e9bSPekka Paalanen  *  Copyright (C) Intel Crop.
4*ff3a3e9bSPekka Paalanen  *
5*ff3a3e9bSPekka Paalanen  *  This program is free software; you can redistribute it and/or
6*ff3a3e9bSPekka Paalanen  *  modify it under the terms of the GNU General Public License
7*ff3a3e9bSPekka Paalanen  *  as published by the Free Software Foundation; either version 2
8*ff3a3e9bSPekka Paalanen  *  of the License, or (at your option) any later version.
9*ff3a3e9bSPekka Paalanen  *
10*ff3a3e9bSPekka Paalanen  *  This program is distributed in the hope that it will be useful,
11*ff3a3e9bSPekka Paalanen  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12*ff3a3e9bSPekka Paalanen  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*ff3a3e9bSPekka Paalanen  *  GNU General Public License for more details.
14*ff3a3e9bSPekka Paalanen  *
15*ff3a3e9bSPekka Paalanen  *  You should have received a copy of the GNU General Public License
16*ff3a3e9bSPekka Paalanen  *  along with this program; if not, write to the Free Software
17*ff3a3e9bSPekka Paalanen  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
18*ff3a3e9bSPekka Paalanen  *  USA.
19*ff3a3e9bSPekka Paalanen  *
20*ff3a3e9bSPekka Paalanen  */
21*ff3a3e9bSPekka Paalanen 
22*ff3a3e9bSPekka Paalanen /*  Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp
23*ff3a3e9bSPekka Paalanen  *  Copyright by Intel Crop., 2002
24*ff3a3e9bSPekka Paalanen  *  Louis Zhuang (louis.zhuang@intel.com)
25*ff3a3e9bSPekka Paalanen  *
26*ff3a3e9bSPekka Paalanen  *  Bjorn Steinbrink (B.Steinbrink@gmx.de), 2007
27*ff3a3e9bSPekka Paalanen  */
28*ff3a3e9bSPekka Paalanen 
29*ff3a3e9bSPekka Paalanen #include <linux/module.h>
30*ff3a3e9bSPekka Paalanen #include <linux/ptrace.h> /* struct pt_regs */
31*ff3a3e9bSPekka Paalanen #include "pf_in.h"
32*ff3a3e9bSPekka Paalanen 
33*ff3a3e9bSPekka Paalanen #ifdef __i386__
34*ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 2-1 */
35*ff3a3e9bSPekka Paalanen static unsigned char prefix_codes[] = {
36*ff3a3e9bSPekka Paalanen 	0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64,
37*ff3a3e9bSPekka Paalanen 	0x65, 0x2E, 0x3E, 0x66, 0x67
38*ff3a3e9bSPekka Paalanen };
39*ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 3-432*/
40*ff3a3e9bSPekka Paalanen static unsigned int reg_rop[] = {
41*ff3a3e9bSPekka Paalanen 	0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
42*ff3a3e9bSPekka Paalanen };
43*ff3a3e9bSPekka Paalanen static unsigned int reg_wop[] = { 0x88, 0x89 };
44*ff3a3e9bSPekka Paalanen static unsigned int imm_wop[] = { 0xC6, 0xC7 };
45*ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 3-432*/
46*ff3a3e9bSPekka Paalanen static unsigned int rw8[] = { 0x88, 0x8A, 0xC6 };
47*ff3a3e9bSPekka Paalanen static unsigned int rw32[] = {
48*ff3a3e9bSPekka Paalanen 	0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
49*ff3a3e9bSPekka Paalanen };
50*ff3a3e9bSPekka Paalanen static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F };
51*ff3a3e9bSPekka Paalanen static unsigned int mw16[] = { 0xB70F, 0xBF0F };
52*ff3a3e9bSPekka Paalanen static unsigned int mw32[] = { 0x89, 0x8B, 0xC7 };
53*ff3a3e9bSPekka Paalanen static unsigned int mw64[] = {};
54*ff3a3e9bSPekka Paalanen #else /* not __i386__ */
55*ff3a3e9bSPekka Paalanen static unsigned char prefix_codes[] = {
56*ff3a3e9bSPekka Paalanen 	0x66, 0x67, 0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36,
57*ff3a3e9bSPekka Paalanen 	0xF0, 0xF3, 0xF2,
58*ff3a3e9bSPekka Paalanen 	/* REX Prefixes */
59*ff3a3e9bSPekka Paalanen 	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
60*ff3a3e9bSPekka Paalanen 	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
61*ff3a3e9bSPekka Paalanen };
62*ff3a3e9bSPekka Paalanen /* AMD64 Manual 3, Appendix A*/
63*ff3a3e9bSPekka Paalanen static unsigned int reg_rop[] = {
64*ff3a3e9bSPekka Paalanen 	0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
65*ff3a3e9bSPekka Paalanen };
66*ff3a3e9bSPekka Paalanen static unsigned int reg_wop[] = { 0x88, 0x89 };
67*ff3a3e9bSPekka Paalanen static unsigned int imm_wop[] = { 0xC6, 0xC7 };
68*ff3a3e9bSPekka Paalanen static unsigned int rw8[] = { 0xC6, 0x88, 0x8A };
69*ff3a3e9bSPekka Paalanen static unsigned int rw32[] = {
70*ff3a3e9bSPekka Paalanen 	0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
71*ff3a3e9bSPekka Paalanen };
72*ff3a3e9bSPekka Paalanen /* 8 bit only */
73*ff3a3e9bSPekka Paalanen static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F };
74*ff3a3e9bSPekka Paalanen /* 16 bit only */
75*ff3a3e9bSPekka Paalanen static unsigned int mw16[] = { 0xB70F, 0xBF0F };
76*ff3a3e9bSPekka Paalanen /* 16 or 32 bit */
77*ff3a3e9bSPekka Paalanen static unsigned int mw32[] = { 0xC7 };
78*ff3a3e9bSPekka Paalanen /* 16, 32 or 64 bit */
79*ff3a3e9bSPekka Paalanen static unsigned int mw64[] = { 0x89, 0x8B };
80*ff3a3e9bSPekka Paalanen #endif /* not __i386__ */
81*ff3a3e9bSPekka Paalanen 
82*ff3a3e9bSPekka Paalanen static int skip_prefix(unsigned char *addr, int *shorted, int *enlarged,
83*ff3a3e9bSPekka Paalanen 								int *rexr)
84*ff3a3e9bSPekka Paalanen {
85*ff3a3e9bSPekka Paalanen 	int i;
86*ff3a3e9bSPekka Paalanen 	unsigned char *p = addr;
87*ff3a3e9bSPekka Paalanen 	*shorted = 0;
88*ff3a3e9bSPekka Paalanen 	*enlarged = 0;
89*ff3a3e9bSPekka Paalanen 	*rexr = 0;
90*ff3a3e9bSPekka Paalanen 
91*ff3a3e9bSPekka Paalanen restart:
92*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) {
93*ff3a3e9bSPekka Paalanen 		if (*p == prefix_codes[i]) {
94*ff3a3e9bSPekka Paalanen 			if (*p == 0x66)
95*ff3a3e9bSPekka Paalanen 				*shorted = 1;
96*ff3a3e9bSPekka Paalanen #ifdef __amd64__
97*ff3a3e9bSPekka Paalanen 			if ((*p & 0xf8) == 0x48)
98*ff3a3e9bSPekka Paalanen 				*enlarged = 1;
99*ff3a3e9bSPekka Paalanen 			if ((*p & 0xf4) == 0x44)
100*ff3a3e9bSPekka Paalanen 				*rexr = 1;
101*ff3a3e9bSPekka Paalanen #endif
102*ff3a3e9bSPekka Paalanen 			p++;
103*ff3a3e9bSPekka Paalanen 			goto restart;
104*ff3a3e9bSPekka Paalanen 		}
105*ff3a3e9bSPekka Paalanen 	}
106*ff3a3e9bSPekka Paalanen 
107*ff3a3e9bSPekka Paalanen 	return (p - addr);
108*ff3a3e9bSPekka Paalanen }
109*ff3a3e9bSPekka Paalanen 
110*ff3a3e9bSPekka Paalanen static int get_opcode(unsigned char *addr, unsigned int *opcode)
111*ff3a3e9bSPekka Paalanen {
112*ff3a3e9bSPekka Paalanen 	int len;
113*ff3a3e9bSPekka Paalanen 
114*ff3a3e9bSPekka Paalanen 	if (*addr == 0x0F) {
115*ff3a3e9bSPekka Paalanen 		/* 0x0F is extension instruction */
116*ff3a3e9bSPekka Paalanen 		*opcode = *(unsigned short *)addr;
117*ff3a3e9bSPekka Paalanen 		len = 2;
118*ff3a3e9bSPekka Paalanen 	} else {
119*ff3a3e9bSPekka Paalanen 		*opcode = *addr;
120*ff3a3e9bSPekka Paalanen 		len = 1;
121*ff3a3e9bSPekka Paalanen 	}
122*ff3a3e9bSPekka Paalanen 
123*ff3a3e9bSPekka Paalanen 	return len;
124*ff3a3e9bSPekka Paalanen }
125*ff3a3e9bSPekka Paalanen 
126*ff3a3e9bSPekka Paalanen #define CHECK_OP_TYPE(opcode, array, type) \
127*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(array); i++) { \
128*ff3a3e9bSPekka Paalanen 		if (array[i] == opcode) { \
129*ff3a3e9bSPekka Paalanen 			rv = type; \
130*ff3a3e9bSPekka Paalanen 			goto exit; \
131*ff3a3e9bSPekka Paalanen 		} \
132*ff3a3e9bSPekka Paalanen 	}
133*ff3a3e9bSPekka Paalanen 
134*ff3a3e9bSPekka Paalanen enum reason_type get_ins_type(unsigned long ins_addr)
135*ff3a3e9bSPekka Paalanen {
136*ff3a3e9bSPekka Paalanen 	unsigned int opcode;
137*ff3a3e9bSPekka Paalanen 	unsigned char *p;
138*ff3a3e9bSPekka Paalanen 	int shorted, enlarged, rexr;
139*ff3a3e9bSPekka Paalanen 	int i;
140*ff3a3e9bSPekka Paalanen 	enum reason_type rv = OTHERS;
141*ff3a3e9bSPekka Paalanen 
142*ff3a3e9bSPekka Paalanen 	p = (unsigned char *)ins_addr;
143*ff3a3e9bSPekka Paalanen 	p += skip_prefix(p, &shorted, &enlarged, &rexr);
144*ff3a3e9bSPekka Paalanen 	p += get_opcode(p, &opcode);
145*ff3a3e9bSPekka Paalanen 
146*ff3a3e9bSPekka Paalanen 	CHECK_OP_TYPE(opcode, reg_rop, REG_READ);
147*ff3a3e9bSPekka Paalanen 	CHECK_OP_TYPE(opcode, reg_wop, REG_WRITE);
148*ff3a3e9bSPekka Paalanen 	CHECK_OP_TYPE(opcode, imm_wop, IMM_WRITE);
149*ff3a3e9bSPekka Paalanen 
150*ff3a3e9bSPekka Paalanen exit:
151*ff3a3e9bSPekka Paalanen 	return rv;
152*ff3a3e9bSPekka Paalanen }
153*ff3a3e9bSPekka Paalanen #undef CHECK_OP_TYPE
154*ff3a3e9bSPekka Paalanen 
155*ff3a3e9bSPekka Paalanen static unsigned int get_ins_reg_width(unsigned long ins_addr)
156*ff3a3e9bSPekka Paalanen {
157*ff3a3e9bSPekka Paalanen 	unsigned int opcode;
158*ff3a3e9bSPekka Paalanen 	unsigned char *p;
159*ff3a3e9bSPekka Paalanen 	int i, shorted, enlarged, rexr;
160*ff3a3e9bSPekka Paalanen 
161*ff3a3e9bSPekka Paalanen 	p = (unsigned char *)ins_addr;
162*ff3a3e9bSPekka Paalanen 	p += skip_prefix(p, &shorted, &enlarged, &rexr);
163*ff3a3e9bSPekka Paalanen 	p += get_opcode(p, &opcode);
164*ff3a3e9bSPekka Paalanen 
165*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(rw8); i++)
166*ff3a3e9bSPekka Paalanen 		if (rw8[i] == opcode)
167*ff3a3e9bSPekka Paalanen 			return 1;
168*ff3a3e9bSPekka Paalanen 
169*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(rw32); i++)
170*ff3a3e9bSPekka Paalanen 		if (rw32[i] == opcode)
171*ff3a3e9bSPekka Paalanen 			return (shorted ? 2 : (enlarged ? 8 : 4));
172*ff3a3e9bSPekka Paalanen 
173*ff3a3e9bSPekka Paalanen 	printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
174*ff3a3e9bSPekka Paalanen 	return 0;
175*ff3a3e9bSPekka Paalanen }
176*ff3a3e9bSPekka Paalanen 
177*ff3a3e9bSPekka Paalanen unsigned int get_ins_mem_width(unsigned long ins_addr)
178*ff3a3e9bSPekka Paalanen {
179*ff3a3e9bSPekka Paalanen 	unsigned int opcode;
180*ff3a3e9bSPekka Paalanen 	unsigned char *p;
181*ff3a3e9bSPekka Paalanen 	int i, shorted, enlarged, rexr;
182*ff3a3e9bSPekka Paalanen 
183*ff3a3e9bSPekka Paalanen 	p = (unsigned char *)ins_addr;
184*ff3a3e9bSPekka Paalanen 	p += skip_prefix(p, &shorted, &enlarged, &rexr);
185*ff3a3e9bSPekka Paalanen 	p += get_opcode(p, &opcode);
186*ff3a3e9bSPekka Paalanen 
187*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(mw8); i++)
188*ff3a3e9bSPekka Paalanen 		if (mw8[i] == opcode)
189*ff3a3e9bSPekka Paalanen 			return 1;
190*ff3a3e9bSPekka Paalanen 
191*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(mw16); i++)
192*ff3a3e9bSPekka Paalanen 		if (mw16[i] == opcode)
193*ff3a3e9bSPekka Paalanen 			return 2;
194*ff3a3e9bSPekka Paalanen 
195*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(mw32); i++)
196*ff3a3e9bSPekka Paalanen 		if (mw32[i] == opcode)
197*ff3a3e9bSPekka Paalanen 			return shorted ? 2 : 4;
198*ff3a3e9bSPekka Paalanen 
199*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(mw64); i++)
200*ff3a3e9bSPekka Paalanen 		if (mw64[i] == opcode)
201*ff3a3e9bSPekka Paalanen 			return shorted ? 2 : (enlarged ? 8 : 4);
202*ff3a3e9bSPekka Paalanen 
203*ff3a3e9bSPekka Paalanen 	printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
204*ff3a3e9bSPekka Paalanen 	return 0;
205*ff3a3e9bSPekka Paalanen }
206*ff3a3e9bSPekka Paalanen 
207*ff3a3e9bSPekka Paalanen /*
208*ff3a3e9bSPekka Paalanen  * Define register ident in mod/rm byte.
209*ff3a3e9bSPekka Paalanen  * Note: these are NOT the same as in ptrace-abi.h.
210*ff3a3e9bSPekka Paalanen  */
211*ff3a3e9bSPekka Paalanen enum {
212*ff3a3e9bSPekka Paalanen 	arg_AL = 0,
213*ff3a3e9bSPekka Paalanen 	arg_CL = 1,
214*ff3a3e9bSPekka Paalanen 	arg_DL = 2,
215*ff3a3e9bSPekka Paalanen 	arg_BL = 3,
216*ff3a3e9bSPekka Paalanen 	arg_AH = 4,
217*ff3a3e9bSPekka Paalanen 	arg_CH = 5,
218*ff3a3e9bSPekka Paalanen 	arg_DH = 6,
219*ff3a3e9bSPekka Paalanen 	arg_BH = 7,
220*ff3a3e9bSPekka Paalanen 
221*ff3a3e9bSPekka Paalanen 	arg_AX = 0,
222*ff3a3e9bSPekka Paalanen 	arg_CX = 1,
223*ff3a3e9bSPekka Paalanen 	arg_DX = 2,
224*ff3a3e9bSPekka Paalanen 	arg_BX = 3,
225*ff3a3e9bSPekka Paalanen 	arg_SP = 4,
226*ff3a3e9bSPekka Paalanen 	arg_BP = 5,
227*ff3a3e9bSPekka Paalanen 	arg_SI = 6,
228*ff3a3e9bSPekka Paalanen 	arg_DI = 7,
229*ff3a3e9bSPekka Paalanen #ifdef __amd64__
230*ff3a3e9bSPekka Paalanen 	arg_R8  = 8,
231*ff3a3e9bSPekka Paalanen 	arg_R9  = 9,
232*ff3a3e9bSPekka Paalanen 	arg_R10 = 10,
233*ff3a3e9bSPekka Paalanen 	arg_R11 = 11,
234*ff3a3e9bSPekka Paalanen 	arg_R12 = 12,
235*ff3a3e9bSPekka Paalanen 	arg_R13 = 13,
236*ff3a3e9bSPekka Paalanen 	arg_R14 = 14,
237*ff3a3e9bSPekka Paalanen 	arg_R15 = 15
238*ff3a3e9bSPekka Paalanen #endif
239*ff3a3e9bSPekka Paalanen };
240*ff3a3e9bSPekka Paalanen 
241*ff3a3e9bSPekka Paalanen static unsigned char *get_reg_w8(int no, struct pt_regs *regs)
242*ff3a3e9bSPekka Paalanen {
243*ff3a3e9bSPekka Paalanen 	unsigned char *rv = NULL;
244*ff3a3e9bSPekka Paalanen 
245*ff3a3e9bSPekka Paalanen 	switch (no) {
246*ff3a3e9bSPekka Paalanen 	case arg_AL:
247*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->ax;
248*ff3a3e9bSPekka Paalanen 		break;
249*ff3a3e9bSPekka Paalanen 	case arg_BL:
250*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->bx;
251*ff3a3e9bSPekka Paalanen 		break;
252*ff3a3e9bSPekka Paalanen 	case arg_CL:
253*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->cx;
254*ff3a3e9bSPekka Paalanen 		break;
255*ff3a3e9bSPekka Paalanen 	case arg_DL:
256*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->dx;
257*ff3a3e9bSPekka Paalanen 		break;
258*ff3a3e9bSPekka Paalanen 	case arg_AH:
259*ff3a3e9bSPekka Paalanen 		rv = 1 + (unsigned char *)&regs->ax;
260*ff3a3e9bSPekka Paalanen 		break;
261*ff3a3e9bSPekka Paalanen 	case arg_BH:
262*ff3a3e9bSPekka Paalanen 		rv = 1 + (unsigned char *)&regs->bx;
263*ff3a3e9bSPekka Paalanen 		break;
264*ff3a3e9bSPekka Paalanen 	case arg_CH:
265*ff3a3e9bSPekka Paalanen 		rv = 1 + (unsigned char *)&regs->cx;
266*ff3a3e9bSPekka Paalanen 		break;
267*ff3a3e9bSPekka Paalanen 	case arg_DH:
268*ff3a3e9bSPekka Paalanen 		rv = 1 + (unsigned char *)&regs->dx;
269*ff3a3e9bSPekka Paalanen 		break;
270*ff3a3e9bSPekka Paalanen #ifdef __amd64__
271*ff3a3e9bSPekka Paalanen 	case arg_R8:
272*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->r8;
273*ff3a3e9bSPekka Paalanen 		break;
274*ff3a3e9bSPekka Paalanen 	case arg_R9:
275*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->r9;
276*ff3a3e9bSPekka Paalanen 		break;
277*ff3a3e9bSPekka Paalanen 	case arg_R10:
278*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->r10;
279*ff3a3e9bSPekka Paalanen 		break;
280*ff3a3e9bSPekka Paalanen 	case arg_R11:
281*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->r11;
282*ff3a3e9bSPekka Paalanen 		break;
283*ff3a3e9bSPekka Paalanen 	case arg_R12:
284*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->r12;
285*ff3a3e9bSPekka Paalanen 		break;
286*ff3a3e9bSPekka Paalanen 	case arg_R13:
287*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->r13;
288*ff3a3e9bSPekka Paalanen 		break;
289*ff3a3e9bSPekka Paalanen 	case arg_R14:
290*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->r14;
291*ff3a3e9bSPekka Paalanen 		break;
292*ff3a3e9bSPekka Paalanen 	case arg_R15:
293*ff3a3e9bSPekka Paalanen 		rv = (unsigned char *)&regs->r15;
294*ff3a3e9bSPekka Paalanen 		break;
295*ff3a3e9bSPekka Paalanen #endif
296*ff3a3e9bSPekka Paalanen 	default:
297*ff3a3e9bSPekka Paalanen 		printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
298*ff3a3e9bSPekka Paalanen 		break;
299*ff3a3e9bSPekka Paalanen 	}
300*ff3a3e9bSPekka Paalanen 	return rv;
301*ff3a3e9bSPekka Paalanen }
302*ff3a3e9bSPekka Paalanen 
303*ff3a3e9bSPekka Paalanen static unsigned long *get_reg_w32(int no, struct pt_regs *regs)
304*ff3a3e9bSPekka Paalanen {
305*ff3a3e9bSPekka Paalanen 	unsigned long *rv = NULL;
306*ff3a3e9bSPekka Paalanen 
307*ff3a3e9bSPekka Paalanen 	switch (no) {
308*ff3a3e9bSPekka Paalanen 	case arg_AX:
309*ff3a3e9bSPekka Paalanen 		rv = &regs->ax;
310*ff3a3e9bSPekka Paalanen 		break;
311*ff3a3e9bSPekka Paalanen 	case arg_BX:
312*ff3a3e9bSPekka Paalanen 		rv = &regs->bx;
313*ff3a3e9bSPekka Paalanen 		break;
314*ff3a3e9bSPekka Paalanen 	case arg_CX:
315*ff3a3e9bSPekka Paalanen 		rv = &regs->cx;
316*ff3a3e9bSPekka Paalanen 		break;
317*ff3a3e9bSPekka Paalanen 	case arg_DX:
318*ff3a3e9bSPekka Paalanen 		rv = &regs->dx;
319*ff3a3e9bSPekka Paalanen 		break;
320*ff3a3e9bSPekka Paalanen 	case arg_SP:
321*ff3a3e9bSPekka Paalanen 		rv = &regs->sp;
322*ff3a3e9bSPekka Paalanen 		break;
323*ff3a3e9bSPekka Paalanen 	case arg_BP:
324*ff3a3e9bSPekka Paalanen 		rv = &regs->bp;
325*ff3a3e9bSPekka Paalanen 		break;
326*ff3a3e9bSPekka Paalanen 	case arg_SI:
327*ff3a3e9bSPekka Paalanen 		rv = &regs->si;
328*ff3a3e9bSPekka Paalanen 		break;
329*ff3a3e9bSPekka Paalanen 	case arg_DI:
330*ff3a3e9bSPekka Paalanen 		rv = &regs->di;
331*ff3a3e9bSPekka Paalanen 		break;
332*ff3a3e9bSPekka Paalanen #ifdef __amd64__
333*ff3a3e9bSPekka Paalanen 	case arg_R8:
334*ff3a3e9bSPekka Paalanen 		rv = &regs->r8;
335*ff3a3e9bSPekka Paalanen 		break;
336*ff3a3e9bSPekka Paalanen 	case arg_R9:
337*ff3a3e9bSPekka Paalanen 		rv = &regs->r9;
338*ff3a3e9bSPekka Paalanen 		break;
339*ff3a3e9bSPekka Paalanen 	case arg_R10:
340*ff3a3e9bSPekka Paalanen 		rv = &regs->r10;
341*ff3a3e9bSPekka Paalanen 		break;
342*ff3a3e9bSPekka Paalanen 	case arg_R11:
343*ff3a3e9bSPekka Paalanen 		rv = &regs->r11;
344*ff3a3e9bSPekka Paalanen 		break;
345*ff3a3e9bSPekka Paalanen 	case arg_R12:
346*ff3a3e9bSPekka Paalanen 		rv = &regs->r12;
347*ff3a3e9bSPekka Paalanen 		break;
348*ff3a3e9bSPekka Paalanen 	case arg_R13:
349*ff3a3e9bSPekka Paalanen 		rv = &regs->r13;
350*ff3a3e9bSPekka Paalanen 		break;
351*ff3a3e9bSPekka Paalanen 	case arg_R14:
352*ff3a3e9bSPekka Paalanen 		rv = &regs->r14;
353*ff3a3e9bSPekka Paalanen 		break;
354*ff3a3e9bSPekka Paalanen 	case arg_R15:
355*ff3a3e9bSPekka Paalanen 		rv = &regs->r15;
356*ff3a3e9bSPekka Paalanen 		break;
357*ff3a3e9bSPekka Paalanen #endif
358*ff3a3e9bSPekka Paalanen 	default:
359*ff3a3e9bSPekka Paalanen 		printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
360*ff3a3e9bSPekka Paalanen 	}
361*ff3a3e9bSPekka Paalanen 
362*ff3a3e9bSPekka Paalanen 	return rv;
363*ff3a3e9bSPekka Paalanen }
364*ff3a3e9bSPekka Paalanen 
365*ff3a3e9bSPekka Paalanen unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs)
366*ff3a3e9bSPekka Paalanen {
367*ff3a3e9bSPekka Paalanen 	unsigned int opcode;
368*ff3a3e9bSPekka Paalanen 	unsigned char mod_rm;
369*ff3a3e9bSPekka Paalanen 	int reg;
370*ff3a3e9bSPekka Paalanen 	unsigned char *p;
371*ff3a3e9bSPekka Paalanen 	int i, shorted, enlarged, rexr;
372*ff3a3e9bSPekka Paalanen 	unsigned long rv;
373*ff3a3e9bSPekka Paalanen 
374*ff3a3e9bSPekka Paalanen 	p = (unsigned char *)ins_addr;
375*ff3a3e9bSPekka Paalanen 	p += skip_prefix(p, &shorted, &enlarged, &rexr);
376*ff3a3e9bSPekka Paalanen 	p += get_opcode(p, &opcode);
377*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(reg_rop); i++)
378*ff3a3e9bSPekka Paalanen 		if (reg_rop[i] == opcode) {
379*ff3a3e9bSPekka Paalanen 			rv = REG_READ;
380*ff3a3e9bSPekka Paalanen 			goto do_work;
381*ff3a3e9bSPekka Paalanen 		}
382*ff3a3e9bSPekka Paalanen 
383*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(reg_wop); i++)
384*ff3a3e9bSPekka Paalanen 		if (reg_wop[i] == opcode) {
385*ff3a3e9bSPekka Paalanen 			rv = REG_WRITE;
386*ff3a3e9bSPekka Paalanen 			goto do_work;
387*ff3a3e9bSPekka Paalanen 		}
388*ff3a3e9bSPekka Paalanen 
389*ff3a3e9bSPekka Paalanen 	printk(KERN_ERR "mmiotrace: Not a register instruction, opcode "
390*ff3a3e9bSPekka Paalanen 							"0x%02x\n", opcode);
391*ff3a3e9bSPekka Paalanen 	goto err;
392*ff3a3e9bSPekka Paalanen 
393*ff3a3e9bSPekka Paalanen do_work:
394*ff3a3e9bSPekka Paalanen 	mod_rm = *p;
395*ff3a3e9bSPekka Paalanen 	reg = ((mod_rm >> 3) & 0x7) | (rexr << 3);
396*ff3a3e9bSPekka Paalanen 	switch (get_ins_reg_width(ins_addr)) {
397*ff3a3e9bSPekka Paalanen 	case 1:
398*ff3a3e9bSPekka Paalanen 		return *get_reg_w8(reg, regs);
399*ff3a3e9bSPekka Paalanen 
400*ff3a3e9bSPekka Paalanen 	case 2:
401*ff3a3e9bSPekka Paalanen 		return *(unsigned short *)get_reg_w32(reg, regs);
402*ff3a3e9bSPekka Paalanen 
403*ff3a3e9bSPekka Paalanen 	case 4:
404*ff3a3e9bSPekka Paalanen 		return *(unsigned int *)get_reg_w32(reg, regs);
405*ff3a3e9bSPekka Paalanen 
406*ff3a3e9bSPekka Paalanen #ifdef __amd64__
407*ff3a3e9bSPekka Paalanen 	case 8:
408*ff3a3e9bSPekka Paalanen 		return *(unsigned long *)get_reg_w32(reg, regs);
409*ff3a3e9bSPekka Paalanen #endif
410*ff3a3e9bSPekka Paalanen 
411*ff3a3e9bSPekka Paalanen 	default:
412*ff3a3e9bSPekka Paalanen 		printk(KERN_ERR "mmiotrace: Error width# %d\n", reg);
413*ff3a3e9bSPekka Paalanen 	}
414*ff3a3e9bSPekka Paalanen 
415*ff3a3e9bSPekka Paalanen err:
416*ff3a3e9bSPekka Paalanen 	return 0;
417*ff3a3e9bSPekka Paalanen }
418*ff3a3e9bSPekka Paalanen 
419*ff3a3e9bSPekka Paalanen unsigned long get_ins_imm_val(unsigned long ins_addr)
420*ff3a3e9bSPekka Paalanen {
421*ff3a3e9bSPekka Paalanen 	unsigned int opcode;
422*ff3a3e9bSPekka Paalanen 	unsigned char mod_rm;
423*ff3a3e9bSPekka Paalanen 	unsigned char mod;
424*ff3a3e9bSPekka Paalanen 	unsigned char *p;
425*ff3a3e9bSPekka Paalanen 	int i, shorted, enlarged, rexr;
426*ff3a3e9bSPekka Paalanen 	unsigned long rv;
427*ff3a3e9bSPekka Paalanen 
428*ff3a3e9bSPekka Paalanen 	p = (unsigned char *)ins_addr;
429*ff3a3e9bSPekka Paalanen 	p += skip_prefix(p, &shorted, &enlarged, &rexr);
430*ff3a3e9bSPekka Paalanen 	p += get_opcode(p, &opcode);
431*ff3a3e9bSPekka Paalanen 	for (i = 0; i < ARRAY_SIZE(imm_wop); i++)
432*ff3a3e9bSPekka Paalanen 		if (imm_wop[i] == opcode) {
433*ff3a3e9bSPekka Paalanen 			rv = IMM_WRITE;
434*ff3a3e9bSPekka Paalanen 			goto do_work;
435*ff3a3e9bSPekka Paalanen 		}
436*ff3a3e9bSPekka Paalanen 
437*ff3a3e9bSPekka Paalanen 	printk(KERN_ERR "mmiotrace: Not an immediate instruction, opcode "
438*ff3a3e9bSPekka Paalanen 							"0x%02x\n", opcode);
439*ff3a3e9bSPekka Paalanen 	goto err;
440*ff3a3e9bSPekka Paalanen 
441*ff3a3e9bSPekka Paalanen do_work:
442*ff3a3e9bSPekka Paalanen 	mod_rm = *p;
443*ff3a3e9bSPekka Paalanen 	mod = mod_rm >> 6;
444*ff3a3e9bSPekka Paalanen 	p++;
445*ff3a3e9bSPekka Paalanen 	switch (mod) {
446*ff3a3e9bSPekka Paalanen 	case 0:
447*ff3a3e9bSPekka Paalanen 		/* if r/m is 5 we have a 32 disp (IA32 Manual 3, Table 2-2)  */
448*ff3a3e9bSPekka Paalanen 		/* AMD64: XXX Check for address size prefix? */
449*ff3a3e9bSPekka Paalanen 		if ((mod_rm & 0x7) == 0x5)
450*ff3a3e9bSPekka Paalanen 			p += 4;
451*ff3a3e9bSPekka Paalanen 		break;
452*ff3a3e9bSPekka Paalanen 
453*ff3a3e9bSPekka Paalanen 	case 1:
454*ff3a3e9bSPekka Paalanen 		p += 1;
455*ff3a3e9bSPekka Paalanen 		break;
456*ff3a3e9bSPekka Paalanen 
457*ff3a3e9bSPekka Paalanen 	case 2:
458*ff3a3e9bSPekka Paalanen 		p += 4;
459*ff3a3e9bSPekka Paalanen 		break;
460*ff3a3e9bSPekka Paalanen 
461*ff3a3e9bSPekka Paalanen 	case 3:
462*ff3a3e9bSPekka Paalanen 	default:
463*ff3a3e9bSPekka Paalanen 		printk(KERN_ERR "mmiotrace: not a memory access instruction "
464*ff3a3e9bSPekka Paalanen 						"at 0x%lx, rm_mod=0x%02x\n",
465*ff3a3e9bSPekka Paalanen 						ins_addr, mod_rm);
466*ff3a3e9bSPekka Paalanen 	}
467*ff3a3e9bSPekka Paalanen 
468*ff3a3e9bSPekka Paalanen 	switch (get_ins_reg_width(ins_addr)) {
469*ff3a3e9bSPekka Paalanen 	case 1:
470*ff3a3e9bSPekka Paalanen 		return *(unsigned char *)p;
471*ff3a3e9bSPekka Paalanen 
472*ff3a3e9bSPekka Paalanen 	case 2:
473*ff3a3e9bSPekka Paalanen 		return *(unsigned short *)p;
474*ff3a3e9bSPekka Paalanen 
475*ff3a3e9bSPekka Paalanen 	case 4:
476*ff3a3e9bSPekka Paalanen 		return *(unsigned int *)p;
477*ff3a3e9bSPekka Paalanen 
478*ff3a3e9bSPekka Paalanen #ifdef __amd64__
479*ff3a3e9bSPekka Paalanen 	case 8:
480*ff3a3e9bSPekka Paalanen 		return *(unsigned long *)p;
481*ff3a3e9bSPekka Paalanen #endif
482*ff3a3e9bSPekka Paalanen 
483*ff3a3e9bSPekka Paalanen 	default:
484*ff3a3e9bSPekka Paalanen 		printk(KERN_ERR "mmiotrace: Error: width.\n");
485*ff3a3e9bSPekka Paalanen 	}
486*ff3a3e9bSPekka Paalanen 
487*ff3a3e9bSPekka Paalanen err:
488*ff3a3e9bSPekka Paalanen 	return 0;
489*ff3a3e9bSPekka Paalanen }
490