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 *)®s->ax; 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case arg_BL: 2458c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->bx; 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci case arg_CL: 2488c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->cx; 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci case arg_DL: 2518c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->dx; 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci#ifdef __amd64__ 2548c2ecf20Sopenharmony_ci case arg_R8: 2558c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->r8; 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci case arg_R9: 2588c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->r9; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci case arg_R10: 2618c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->r10; 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci case arg_R11: 2648c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->r11; 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci case arg_R12: 2678c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->r12; 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci case arg_R13: 2708c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->r13; 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci case arg_R14: 2738c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->r14; 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci case arg_R15: 2768c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->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 *)®s->si; 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci case arg_DI: 2968c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->di; 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case arg_BP: 2998c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->bp; 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case arg_SP: 3028c2ecf20Sopenharmony_ci rv = (unsigned char *)®s->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 *)®s->ax; 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci case arg_BH: 3138c2ecf20Sopenharmony_ci rv = 1 + (unsigned char *)®s->bx; 3148c2ecf20Sopenharmony_ci break; 3158c2ecf20Sopenharmony_ci case arg_CH: 3168c2ecf20Sopenharmony_ci rv = 1 + (unsigned char *)®s->cx; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case arg_DH: 3198c2ecf20Sopenharmony_ci rv = 1 + (unsigned char *)®s->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 = ®s->ax; 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci case arg_BX: 3418c2ecf20Sopenharmony_ci rv = ®s->bx; 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci case arg_CX: 3448c2ecf20Sopenharmony_ci rv = ®s->cx; 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci case arg_DX: 3478c2ecf20Sopenharmony_ci rv = ®s->dx; 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci case arg_SP: 3508c2ecf20Sopenharmony_ci rv = ®s->sp; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci case arg_BP: 3538c2ecf20Sopenharmony_ci rv = ®s->bp; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case arg_SI: 3568c2ecf20Sopenharmony_ci rv = ®s->si; 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci case arg_DI: 3598c2ecf20Sopenharmony_ci rv = ®s->di; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci#ifdef __amd64__ 3628c2ecf20Sopenharmony_ci case arg_R8: 3638c2ecf20Sopenharmony_ci rv = ®s->r8; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci case arg_R9: 3668c2ecf20Sopenharmony_ci rv = ®s->r9; 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci case arg_R10: 3698c2ecf20Sopenharmony_ci rv = ®s->r10; 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci case arg_R11: 3728c2ecf20Sopenharmony_ci rv = ®s->r11; 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci case arg_R12: 3758c2ecf20Sopenharmony_ci rv = ®s->r12; 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci case arg_R13: 3788c2ecf20Sopenharmony_ci rv = ®s->r13; 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci case arg_R14: 3818c2ecf20Sopenharmony_ci rv = ®s->r14; 3828c2ecf20Sopenharmony_ci break; 3838c2ecf20Sopenharmony_ci case arg_R15: 3848c2ecf20Sopenharmony_ci rv = ®s->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