18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Fault Injection Test harness (FI)
48c2ecf20Sopenharmony_ci *  Copyright (C) Intel Crop.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/*  Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp
88c2ecf20Sopenharmony_ci *  Copyright by Intel Crop., 2002
98c2ecf20Sopenharmony_ci *  Louis Zhuang (louis.zhuang@intel.com)
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  Bjorn Steinbrink (B.Steinbrink@gmx.de), 2007
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/ptrace.h> /* struct pt_regs */
158c2ecf20Sopenharmony_ci#include "pf_in.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#ifdef __i386__
188c2ecf20Sopenharmony_ci/* IA32 Manual 3, 2-1 */
198c2ecf20Sopenharmony_cistatic unsigned char prefix_codes[] = {
208c2ecf20Sopenharmony_ci	0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64,
218c2ecf20Sopenharmony_ci	0x65, 0x66, 0x67
228c2ecf20Sopenharmony_ci};
238c2ecf20Sopenharmony_ci/* IA32 Manual 3, 3-432*/
248c2ecf20Sopenharmony_cistatic unsigned int reg_rop[] = {
258c2ecf20Sopenharmony_ci	0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_cistatic unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
288c2ecf20Sopenharmony_cistatic unsigned int imm_wop[] = { 0xC6, 0xC7 };
298c2ecf20Sopenharmony_ci/* IA32 Manual 3, 3-432*/
308c2ecf20Sopenharmony_cistatic unsigned int rw8[] = { 0x88, 0x8A, 0xC6, 0xAA };
318c2ecf20Sopenharmony_cistatic unsigned int rw32[] = {
328c2ecf20Sopenharmony_ci	0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_cistatic unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F, 0xAA };
358c2ecf20Sopenharmony_cistatic unsigned int mw16[] = { 0xB70F, 0xBF0F };
368c2ecf20Sopenharmony_cistatic unsigned int mw32[] = { 0x89, 0x8B, 0xC7, 0xAB };
378c2ecf20Sopenharmony_cistatic unsigned int mw64[] = {};
388c2ecf20Sopenharmony_ci#else /* not __i386__ */
398c2ecf20Sopenharmony_cistatic unsigned char prefix_codes[] = {
408c2ecf20Sopenharmony_ci	0x66, 0x67, 0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36,
418c2ecf20Sopenharmony_ci	0xF0, 0xF3, 0xF2,
428c2ecf20Sopenharmony_ci	/* REX Prefixes */
438c2ecf20Sopenharmony_ci	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
448c2ecf20Sopenharmony_ci	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci/* AMD64 Manual 3, Appendix A*/
478c2ecf20Sopenharmony_cistatic unsigned int reg_rop[] = {
488c2ecf20Sopenharmony_ci	0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_cistatic unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
518c2ecf20Sopenharmony_cistatic unsigned int imm_wop[] = { 0xC6, 0xC7 };
528c2ecf20Sopenharmony_cistatic unsigned int rw8[] = { 0xC6, 0x88, 0x8A, 0xAA };
538c2ecf20Sopenharmony_cistatic unsigned int rw32[] = {
548c2ecf20Sopenharmony_ci	0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci/* 8 bit only */
578c2ecf20Sopenharmony_cistatic unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F, 0xAA };
588c2ecf20Sopenharmony_ci/* 16 bit only */
598c2ecf20Sopenharmony_cistatic unsigned int mw16[] = { 0xB70F, 0xBF0F };
608c2ecf20Sopenharmony_ci/* 16 or 32 bit */
618c2ecf20Sopenharmony_cistatic unsigned int mw32[] = { 0xC7 };
628c2ecf20Sopenharmony_ci/* 16, 32 or 64 bit */
638c2ecf20Sopenharmony_cistatic unsigned int mw64[] = { 0x89, 0x8B, 0xAB };
648c2ecf20Sopenharmony_ci#endif /* not __i386__ */
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistruct prefix_bits {
678c2ecf20Sopenharmony_ci	unsigned shorted:1;
688c2ecf20Sopenharmony_ci	unsigned enlarged:1;
698c2ecf20Sopenharmony_ci	unsigned rexr:1;
708c2ecf20Sopenharmony_ci	unsigned rex:1;
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int skip_prefix(unsigned char *addr, struct prefix_bits *prf)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	int i;
768c2ecf20Sopenharmony_ci	unsigned char *p = addr;
778c2ecf20Sopenharmony_ci	prf->shorted = 0;
788c2ecf20Sopenharmony_ci	prf->enlarged = 0;
798c2ecf20Sopenharmony_ci	prf->rexr = 0;
808c2ecf20Sopenharmony_ci	prf->rex = 0;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cirestart:
838c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) {
848c2ecf20Sopenharmony_ci		if (*p == prefix_codes[i]) {
858c2ecf20Sopenharmony_ci			if (*p == 0x66)
868c2ecf20Sopenharmony_ci				prf->shorted = 1;
878c2ecf20Sopenharmony_ci#ifdef __amd64__
888c2ecf20Sopenharmony_ci			if ((*p & 0xf8) == 0x48)
898c2ecf20Sopenharmony_ci				prf->enlarged = 1;
908c2ecf20Sopenharmony_ci			if ((*p & 0xf4) == 0x44)
918c2ecf20Sopenharmony_ci				prf->rexr = 1;
928c2ecf20Sopenharmony_ci			if ((*p & 0xf0) == 0x40)
938c2ecf20Sopenharmony_ci				prf->rex = 1;
948c2ecf20Sopenharmony_ci#endif
958c2ecf20Sopenharmony_ci			p++;
968c2ecf20Sopenharmony_ci			goto restart;
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return (p - addr);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int get_opcode(unsigned char *addr, unsigned int *opcode)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int len;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (*addr == 0x0F) {
1088c2ecf20Sopenharmony_ci		/* 0x0F is extension instruction */
1098c2ecf20Sopenharmony_ci		*opcode = *(unsigned short *)addr;
1108c2ecf20Sopenharmony_ci		len = 2;
1118c2ecf20Sopenharmony_ci	} else {
1128c2ecf20Sopenharmony_ci		*opcode = *addr;
1138c2ecf20Sopenharmony_ci		len = 1;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return len;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci#define CHECK_OP_TYPE(opcode, array, type) \
1208c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(array); i++) { \
1218c2ecf20Sopenharmony_ci		if (array[i] == opcode) { \
1228c2ecf20Sopenharmony_ci			rv = type; \
1238c2ecf20Sopenharmony_ci			goto exit; \
1248c2ecf20Sopenharmony_ci		} \
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cienum reason_type get_ins_type(unsigned long ins_addr)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	unsigned int opcode;
1308c2ecf20Sopenharmony_ci	unsigned char *p;
1318c2ecf20Sopenharmony_ci	struct prefix_bits prf;
1328c2ecf20Sopenharmony_ci	int i;
1338c2ecf20Sopenharmony_ci	enum reason_type rv = OTHERS;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	p = (unsigned char *)ins_addr;
1368c2ecf20Sopenharmony_ci	p += skip_prefix(p, &prf);
1378c2ecf20Sopenharmony_ci	p += get_opcode(p, &opcode);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	CHECK_OP_TYPE(opcode, reg_rop, REG_READ);
1408c2ecf20Sopenharmony_ci	CHECK_OP_TYPE(opcode, reg_wop, REG_WRITE);
1418c2ecf20Sopenharmony_ci	CHECK_OP_TYPE(opcode, imm_wop, IMM_WRITE);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ciexit:
1448c2ecf20Sopenharmony_ci	return rv;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci#undef CHECK_OP_TYPE
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic unsigned int get_ins_reg_width(unsigned long ins_addr)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	unsigned int opcode;
1518c2ecf20Sopenharmony_ci	unsigned char *p;
1528c2ecf20Sopenharmony_ci	struct prefix_bits prf;
1538c2ecf20Sopenharmony_ci	int i;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	p = (unsigned char *)ins_addr;
1568c2ecf20Sopenharmony_ci	p += skip_prefix(p, &prf);
1578c2ecf20Sopenharmony_ci	p += get_opcode(p, &opcode);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rw8); i++)
1608c2ecf20Sopenharmony_ci		if (rw8[i] == opcode)
1618c2ecf20Sopenharmony_ci			return 1;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rw32); i++)
1648c2ecf20Sopenharmony_ci		if (rw32[i] == opcode)
1658c2ecf20Sopenharmony_ci			return prf.shorted ? 2 : (prf.enlarged ? 8 : 4);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
1688c2ecf20Sopenharmony_ci	return 0;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ciunsigned int get_ins_mem_width(unsigned long ins_addr)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	unsigned int opcode;
1748c2ecf20Sopenharmony_ci	unsigned char *p;
1758c2ecf20Sopenharmony_ci	struct prefix_bits prf;
1768c2ecf20Sopenharmony_ci	int i;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	p = (unsigned char *)ins_addr;
1798c2ecf20Sopenharmony_ci	p += skip_prefix(p, &prf);
1808c2ecf20Sopenharmony_ci	p += get_opcode(p, &opcode);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mw8); i++)
1838c2ecf20Sopenharmony_ci		if (mw8[i] == opcode)
1848c2ecf20Sopenharmony_ci			return 1;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mw16); i++)
1878c2ecf20Sopenharmony_ci		if (mw16[i] == opcode)
1888c2ecf20Sopenharmony_ci			return 2;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mw32); i++)
1918c2ecf20Sopenharmony_ci		if (mw32[i] == opcode)
1928c2ecf20Sopenharmony_ci			return prf.shorted ? 2 : 4;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mw64); i++)
1958c2ecf20Sopenharmony_ci		if (mw64[i] == opcode)
1968c2ecf20Sopenharmony_ci			return prf.shorted ? 2 : (prf.enlarged ? 8 : 4);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/*
2038c2ecf20Sopenharmony_ci * Define register ident in mod/rm byte.
2048c2ecf20Sopenharmony_ci * Note: these are NOT the same as in ptrace-abi.h.
2058c2ecf20Sopenharmony_ci */
2068c2ecf20Sopenharmony_cienum {
2078c2ecf20Sopenharmony_ci	arg_AL = 0,
2088c2ecf20Sopenharmony_ci	arg_CL = 1,
2098c2ecf20Sopenharmony_ci	arg_DL = 2,
2108c2ecf20Sopenharmony_ci	arg_BL = 3,
2118c2ecf20Sopenharmony_ci	arg_AH = 4,
2128c2ecf20Sopenharmony_ci	arg_CH = 5,
2138c2ecf20Sopenharmony_ci	arg_DH = 6,
2148c2ecf20Sopenharmony_ci	arg_BH = 7,
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	arg_AX = 0,
2178c2ecf20Sopenharmony_ci	arg_CX = 1,
2188c2ecf20Sopenharmony_ci	arg_DX = 2,
2198c2ecf20Sopenharmony_ci	arg_BX = 3,
2208c2ecf20Sopenharmony_ci	arg_SP = 4,
2218c2ecf20Sopenharmony_ci	arg_BP = 5,
2228c2ecf20Sopenharmony_ci	arg_SI = 6,
2238c2ecf20Sopenharmony_ci	arg_DI = 7,
2248c2ecf20Sopenharmony_ci#ifdef __amd64__
2258c2ecf20Sopenharmony_ci	arg_R8  = 8,
2268c2ecf20Sopenharmony_ci	arg_R9  = 9,
2278c2ecf20Sopenharmony_ci	arg_R10 = 10,
2288c2ecf20Sopenharmony_ci	arg_R11 = 11,
2298c2ecf20Sopenharmony_ci	arg_R12 = 12,
2308c2ecf20Sopenharmony_ci	arg_R13 = 13,
2318c2ecf20Sopenharmony_ci	arg_R14 = 14,
2328c2ecf20Sopenharmony_ci	arg_R15 = 15
2338c2ecf20Sopenharmony_ci#endif
2348c2ecf20Sopenharmony_ci};
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic unsigned char *get_reg_w8(int no, int rex, struct pt_regs *regs)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	unsigned char *rv = NULL;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	switch (no) {
2418c2ecf20Sopenharmony_ci	case arg_AL:
2428c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->ax;
2438c2ecf20Sopenharmony_ci		break;
2448c2ecf20Sopenharmony_ci	case arg_BL:
2458c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->bx;
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci	case arg_CL:
2488c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->cx;
2498c2ecf20Sopenharmony_ci		break;
2508c2ecf20Sopenharmony_ci	case arg_DL:
2518c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->dx;
2528c2ecf20Sopenharmony_ci		break;
2538c2ecf20Sopenharmony_ci#ifdef __amd64__
2548c2ecf20Sopenharmony_ci	case arg_R8:
2558c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->r8;
2568c2ecf20Sopenharmony_ci		break;
2578c2ecf20Sopenharmony_ci	case arg_R9:
2588c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->r9;
2598c2ecf20Sopenharmony_ci		break;
2608c2ecf20Sopenharmony_ci	case arg_R10:
2618c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->r10;
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	case arg_R11:
2648c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->r11;
2658c2ecf20Sopenharmony_ci		break;
2668c2ecf20Sopenharmony_ci	case arg_R12:
2678c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->r12;
2688c2ecf20Sopenharmony_ci		break;
2698c2ecf20Sopenharmony_ci	case arg_R13:
2708c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->r13;
2718c2ecf20Sopenharmony_ci		break;
2728c2ecf20Sopenharmony_ci	case arg_R14:
2738c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->r14;
2748c2ecf20Sopenharmony_ci		break;
2758c2ecf20Sopenharmony_ci	case arg_R15:
2768c2ecf20Sopenharmony_ci		rv = (unsigned char *)&regs->r15;
2778c2ecf20Sopenharmony_ci		break;
2788c2ecf20Sopenharmony_ci#endif
2798c2ecf20Sopenharmony_ci	default:
2808c2ecf20Sopenharmony_ci		break;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (rv)
2848c2ecf20Sopenharmony_ci		return rv;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (rex) {
2878c2ecf20Sopenharmony_ci		/*
2888c2ecf20Sopenharmony_ci		 * If REX prefix exists, access low bytes of SI etc.
2898c2ecf20Sopenharmony_ci		 * instead of AH etc.
2908c2ecf20Sopenharmony_ci		 */
2918c2ecf20Sopenharmony_ci		switch (no) {
2928c2ecf20Sopenharmony_ci		case arg_SI:
2938c2ecf20Sopenharmony_ci			rv = (unsigned char *)&regs->si;
2948c2ecf20Sopenharmony_ci			break;
2958c2ecf20Sopenharmony_ci		case arg_DI:
2968c2ecf20Sopenharmony_ci			rv = (unsigned char *)&regs->di;
2978c2ecf20Sopenharmony_ci			break;
2988c2ecf20Sopenharmony_ci		case arg_BP:
2998c2ecf20Sopenharmony_ci			rv = (unsigned char *)&regs->bp;
3008c2ecf20Sopenharmony_ci			break;
3018c2ecf20Sopenharmony_ci		case arg_SP:
3028c2ecf20Sopenharmony_ci			rv = (unsigned char *)&regs->sp;
3038c2ecf20Sopenharmony_ci			break;
3048c2ecf20Sopenharmony_ci		default:
3058c2ecf20Sopenharmony_ci			break;
3068c2ecf20Sopenharmony_ci		}
3078c2ecf20Sopenharmony_ci	} else {
3088c2ecf20Sopenharmony_ci		switch (no) {
3098c2ecf20Sopenharmony_ci		case arg_AH:
3108c2ecf20Sopenharmony_ci			rv = 1 + (unsigned char *)&regs->ax;
3118c2ecf20Sopenharmony_ci			break;
3128c2ecf20Sopenharmony_ci		case arg_BH:
3138c2ecf20Sopenharmony_ci			rv = 1 + (unsigned char *)&regs->bx;
3148c2ecf20Sopenharmony_ci			break;
3158c2ecf20Sopenharmony_ci		case arg_CH:
3168c2ecf20Sopenharmony_ci			rv = 1 + (unsigned char *)&regs->cx;
3178c2ecf20Sopenharmony_ci			break;
3188c2ecf20Sopenharmony_ci		case arg_DH:
3198c2ecf20Sopenharmony_ci			rv = 1 + (unsigned char *)&regs->dx;
3208c2ecf20Sopenharmony_ci			break;
3218c2ecf20Sopenharmony_ci		default:
3228c2ecf20Sopenharmony_ci			break;
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (!rv)
3278c2ecf20Sopenharmony_ci		printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return rv;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic unsigned long *get_reg_w32(int no, struct pt_regs *regs)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	unsigned long *rv = NULL;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	switch (no) {
3378c2ecf20Sopenharmony_ci	case arg_AX:
3388c2ecf20Sopenharmony_ci		rv = &regs->ax;
3398c2ecf20Sopenharmony_ci		break;
3408c2ecf20Sopenharmony_ci	case arg_BX:
3418c2ecf20Sopenharmony_ci		rv = &regs->bx;
3428c2ecf20Sopenharmony_ci		break;
3438c2ecf20Sopenharmony_ci	case arg_CX:
3448c2ecf20Sopenharmony_ci		rv = &regs->cx;
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	case arg_DX:
3478c2ecf20Sopenharmony_ci		rv = &regs->dx;
3488c2ecf20Sopenharmony_ci		break;
3498c2ecf20Sopenharmony_ci	case arg_SP:
3508c2ecf20Sopenharmony_ci		rv = &regs->sp;
3518c2ecf20Sopenharmony_ci		break;
3528c2ecf20Sopenharmony_ci	case arg_BP:
3538c2ecf20Sopenharmony_ci		rv = &regs->bp;
3548c2ecf20Sopenharmony_ci		break;
3558c2ecf20Sopenharmony_ci	case arg_SI:
3568c2ecf20Sopenharmony_ci		rv = &regs->si;
3578c2ecf20Sopenharmony_ci		break;
3588c2ecf20Sopenharmony_ci	case arg_DI:
3598c2ecf20Sopenharmony_ci		rv = &regs->di;
3608c2ecf20Sopenharmony_ci		break;
3618c2ecf20Sopenharmony_ci#ifdef __amd64__
3628c2ecf20Sopenharmony_ci	case arg_R8:
3638c2ecf20Sopenharmony_ci		rv = &regs->r8;
3648c2ecf20Sopenharmony_ci		break;
3658c2ecf20Sopenharmony_ci	case arg_R9:
3668c2ecf20Sopenharmony_ci		rv = &regs->r9;
3678c2ecf20Sopenharmony_ci		break;
3688c2ecf20Sopenharmony_ci	case arg_R10:
3698c2ecf20Sopenharmony_ci		rv = &regs->r10;
3708c2ecf20Sopenharmony_ci		break;
3718c2ecf20Sopenharmony_ci	case arg_R11:
3728c2ecf20Sopenharmony_ci		rv = &regs->r11;
3738c2ecf20Sopenharmony_ci		break;
3748c2ecf20Sopenharmony_ci	case arg_R12:
3758c2ecf20Sopenharmony_ci		rv = &regs->r12;
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	case arg_R13:
3788c2ecf20Sopenharmony_ci		rv = &regs->r13;
3798c2ecf20Sopenharmony_ci		break;
3808c2ecf20Sopenharmony_ci	case arg_R14:
3818c2ecf20Sopenharmony_ci		rv = &regs->r14;
3828c2ecf20Sopenharmony_ci		break;
3838c2ecf20Sopenharmony_ci	case arg_R15:
3848c2ecf20Sopenharmony_ci		rv = &regs->r15;
3858c2ecf20Sopenharmony_ci		break;
3868c2ecf20Sopenharmony_ci#endif
3878c2ecf20Sopenharmony_ci	default:
3888c2ecf20Sopenharmony_ci		printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return rv;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciunsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	unsigned int opcode;
3978c2ecf20Sopenharmony_ci	int reg;
3988c2ecf20Sopenharmony_ci	unsigned char *p;
3998c2ecf20Sopenharmony_ci	struct prefix_bits prf;
4008c2ecf20Sopenharmony_ci	int i;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	p = (unsigned char *)ins_addr;
4038c2ecf20Sopenharmony_ci	p += skip_prefix(p, &prf);
4048c2ecf20Sopenharmony_ci	p += get_opcode(p, &opcode);
4058c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(reg_rop); i++)
4068c2ecf20Sopenharmony_ci		if (reg_rop[i] == opcode)
4078c2ecf20Sopenharmony_ci			goto do_work;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(reg_wop); i++)
4108c2ecf20Sopenharmony_ci		if (reg_wop[i] == opcode)
4118c2ecf20Sopenharmony_ci			goto do_work;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	printk(KERN_ERR "mmiotrace: Not a register instruction, opcode "
4148c2ecf20Sopenharmony_ci							"0x%02x\n", opcode);
4158c2ecf20Sopenharmony_ci	goto err;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cido_work:
4188c2ecf20Sopenharmony_ci	/* for STOS, source register is fixed */
4198c2ecf20Sopenharmony_ci	if (opcode == 0xAA || opcode == 0xAB) {
4208c2ecf20Sopenharmony_ci		reg = arg_AX;
4218c2ecf20Sopenharmony_ci	} else {
4228c2ecf20Sopenharmony_ci		unsigned char mod_rm = *p;
4238c2ecf20Sopenharmony_ci		reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3);
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci	switch (get_ins_reg_width(ins_addr)) {
4268c2ecf20Sopenharmony_ci	case 1:
4278c2ecf20Sopenharmony_ci		return *get_reg_w8(reg, prf.rex, regs);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	case 2:
4308c2ecf20Sopenharmony_ci		return *(unsigned short *)get_reg_w32(reg, regs);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	case 4:
4338c2ecf20Sopenharmony_ci		return *(unsigned int *)get_reg_w32(reg, regs);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci#ifdef __amd64__
4368c2ecf20Sopenharmony_ci	case 8:
4378c2ecf20Sopenharmony_ci		return *(unsigned long *)get_reg_w32(reg, regs);
4388c2ecf20Sopenharmony_ci#endif
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	default:
4418c2ecf20Sopenharmony_ci		printk(KERN_ERR "mmiotrace: Error width# %d\n", reg);
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cierr:
4458c2ecf20Sopenharmony_ci	return 0;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ciunsigned long get_ins_imm_val(unsigned long ins_addr)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	unsigned int opcode;
4518c2ecf20Sopenharmony_ci	unsigned char mod_rm;
4528c2ecf20Sopenharmony_ci	unsigned char mod;
4538c2ecf20Sopenharmony_ci	unsigned char *p;
4548c2ecf20Sopenharmony_ci	struct prefix_bits prf;
4558c2ecf20Sopenharmony_ci	int i;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	p = (unsigned char *)ins_addr;
4588c2ecf20Sopenharmony_ci	p += skip_prefix(p, &prf);
4598c2ecf20Sopenharmony_ci	p += get_opcode(p, &opcode);
4608c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(imm_wop); i++)
4618c2ecf20Sopenharmony_ci		if (imm_wop[i] == opcode)
4628c2ecf20Sopenharmony_ci			goto do_work;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	printk(KERN_ERR "mmiotrace: Not an immediate instruction, opcode "
4658c2ecf20Sopenharmony_ci							"0x%02x\n", opcode);
4668c2ecf20Sopenharmony_ci	goto err;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cido_work:
4698c2ecf20Sopenharmony_ci	mod_rm = *p;
4708c2ecf20Sopenharmony_ci	mod = mod_rm >> 6;
4718c2ecf20Sopenharmony_ci	p++;
4728c2ecf20Sopenharmony_ci	switch (mod) {
4738c2ecf20Sopenharmony_ci	case 0:
4748c2ecf20Sopenharmony_ci		/* if r/m is 5 we have a 32 disp (IA32 Manual 3, Table 2-2)  */
4758c2ecf20Sopenharmony_ci		/* AMD64: XXX Check for address size prefix? */
4768c2ecf20Sopenharmony_ci		if ((mod_rm & 0x7) == 0x5)
4778c2ecf20Sopenharmony_ci			p += 4;
4788c2ecf20Sopenharmony_ci		break;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	case 1:
4818c2ecf20Sopenharmony_ci		p += 1;
4828c2ecf20Sopenharmony_ci		break;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	case 2:
4858c2ecf20Sopenharmony_ci		p += 4;
4868c2ecf20Sopenharmony_ci		break;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	case 3:
4898c2ecf20Sopenharmony_ci	default:
4908c2ecf20Sopenharmony_ci		printk(KERN_ERR "mmiotrace: not a memory access instruction "
4918c2ecf20Sopenharmony_ci						"at 0x%lx, rm_mod=0x%02x\n",
4928c2ecf20Sopenharmony_ci						ins_addr, mod_rm);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	switch (get_ins_reg_width(ins_addr)) {
4968c2ecf20Sopenharmony_ci	case 1:
4978c2ecf20Sopenharmony_ci		return *(unsigned char *)p;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	case 2:
5008c2ecf20Sopenharmony_ci		return *(unsigned short *)p;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	case 4:
5038c2ecf20Sopenharmony_ci		return *(unsigned int *)p;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci#ifdef __amd64__
5068c2ecf20Sopenharmony_ci	case 8:
5078c2ecf20Sopenharmony_ci		return *(unsigned long *)p;
5088c2ecf20Sopenharmony_ci#endif
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	default:
5118c2ecf20Sopenharmony_ci		printk(KERN_ERR "mmiotrace: Error: width.\n");
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cierr:
5158c2ecf20Sopenharmony_ci	return 0;
5168c2ecf20Sopenharmony_ci}
517