1ff3a3e9bSPekka Paalanen /* 2ff3a3e9bSPekka Paalanen * Fault Injection Test harness (FI) 3ff3a3e9bSPekka Paalanen * Copyright (C) Intel Crop. 4ff3a3e9bSPekka Paalanen * 5ff3a3e9bSPekka Paalanen * This program is free software; you can redistribute it and/or 6ff3a3e9bSPekka Paalanen * modify it under the terms of the GNU General Public License 7ff3a3e9bSPekka Paalanen * as published by the Free Software Foundation; either version 2 8ff3a3e9bSPekka Paalanen * of the License, or (at your option) any later version. 9ff3a3e9bSPekka Paalanen * 10ff3a3e9bSPekka Paalanen * This program is distributed in the hope that it will be useful, 11ff3a3e9bSPekka Paalanen * but WITHOUT ANY WARRANTY; without even the implied warranty of 12ff3a3e9bSPekka Paalanen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13ff3a3e9bSPekka Paalanen * GNU General Public License for more details. 14ff3a3e9bSPekka Paalanen * 15ff3a3e9bSPekka Paalanen * You should have received a copy of the GNU General Public License 16ff3a3e9bSPekka Paalanen * along with this program; if not, write to the Free Software 17ff3a3e9bSPekka Paalanen * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 18ff3a3e9bSPekka Paalanen * USA. 19ff3a3e9bSPekka Paalanen * 20ff3a3e9bSPekka Paalanen */ 21ff3a3e9bSPekka Paalanen 22ff3a3e9bSPekka Paalanen /* Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp 23ff3a3e9bSPekka Paalanen * Copyright by Intel Crop., 2002 24ff3a3e9bSPekka Paalanen * Louis Zhuang (louis.zhuang@intel.com) 25ff3a3e9bSPekka Paalanen * 26ff3a3e9bSPekka Paalanen * Bjorn Steinbrink (B.Steinbrink@gmx.de), 2007 27ff3a3e9bSPekka Paalanen */ 28ff3a3e9bSPekka Paalanen 29ff3a3e9bSPekka Paalanen #include <linux/module.h> 30ff3a3e9bSPekka Paalanen #include <linux/ptrace.h> /* struct pt_regs */ 31ff3a3e9bSPekka Paalanen #include "pf_in.h" 32ff3a3e9bSPekka Paalanen 33ff3a3e9bSPekka Paalanen #ifdef __i386__ 34ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 2-1 */ 35ff3a3e9bSPekka Paalanen static unsigned char prefix_codes[] = { 36ff3a3e9bSPekka Paalanen 0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64, 37*841bca13SAkinobu Mita 0x65, 0x66, 0x67 38ff3a3e9bSPekka Paalanen }; 39ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 3-432*/ 40ff3a3e9bSPekka Paalanen static unsigned int reg_rop[] = { 41ff3a3e9bSPekka Paalanen 0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F 42ff3a3e9bSPekka Paalanen }; 43ff3a3e9bSPekka Paalanen static unsigned int reg_wop[] = { 0x88, 0x89 }; 44ff3a3e9bSPekka Paalanen static unsigned int imm_wop[] = { 0xC6, 0xC7 }; 45ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 3-432*/ 46ff3a3e9bSPekka Paalanen static unsigned int rw8[] = { 0x88, 0x8A, 0xC6 }; 47ff3a3e9bSPekka Paalanen static unsigned int rw32[] = { 48ff3a3e9bSPekka Paalanen 0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F 49ff3a3e9bSPekka Paalanen }; 50ff3a3e9bSPekka Paalanen static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F }; 51ff3a3e9bSPekka Paalanen static unsigned int mw16[] = { 0xB70F, 0xBF0F }; 52ff3a3e9bSPekka Paalanen static unsigned int mw32[] = { 0x89, 0x8B, 0xC7 }; 53ff3a3e9bSPekka Paalanen static unsigned int mw64[] = {}; 54ff3a3e9bSPekka Paalanen #else /* not __i386__ */ 55ff3a3e9bSPekka Paalanen static unsigned char prefix_codes[] = { 56ff3a3e9bSPekka Paalanen 0x66, 0x67, 0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36, 57ff3a3e9bSPekka Paalanen 0xF0, 0xF3, 0xF2, 58ff3a3e9bSPekka Paalanen /* REX Prefixes */ 59ff3a3e9bSPekka Paalanen 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 60ff3a3e9bSPekka Paalanen 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f 61ff3a3e9bSPekka Paalanen }; 62ff3a3e9bSPekka Paalanen /* AMD64 Manual 3, Appendix A*/ 63ff3a3e9bSPekka Paalanen static unsigned int reg_rop[] = { 64ff3a3e9bSPekka Paalanen 0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F 65ff3a3e9bSPekka Paalanen }; 66ff3a3e9bSPekka Paalanen static unsigned int reg_wop[] = { 0x88, 0x89 }; 67ff3a3e9bSPekka Paalanen static unsigned int imm_wop[] = { 0xC6, 0xC7 }; 68ff3a3e9bSPekka Paalanen static unsigned int rw8[] = { 0xC6, 0x88, 0x8A }; 69ff3a3e9bSPekka Paalanen static unsigned int rw32[] = { 70ff3a3e9bSPekka Paalanen 0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F 71ff3a3e9bSPekka Paalanen }; 72ff3a3e9bSPekka Paalanen /* 8 bit only */ 73ff3a3e9bSPekka Paalanen static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F }; 74ff3a3e9bSPekka Paalanen /* 16 bit only */ 75ff3a3e9bSPekka Paalanen static unsigned int mw16[] = { 0xB70F, 0xBF0F }; 76ff3a3e9bSPekka Paalanen /* 16 or 32 bit */ 77ff3a3e9bSPekka Paalanen static unsigned int mw32[] = { 0xC7 }; 78ff3a3e9bSPekka Paalanen /* 16, 32 or 64 bit */ 79ff3a3e9bSPekka Paalanen static unsigned int mw64[] = { 0x89, 0x8B }; 80ff3a3e9bSPekka Paalanen #endif /* not __i386__ */ 81ff3a3e9bSPekka Paalanen 82611b1597SPekka Paalanen struct prefix_bits { 83611b1597SPekka Paalanen unsigned shorted:1; 84611b1597SPekka Paalanen unsigned enlarged:1; 85611b1597SPekka Paalanen unsigned rexr:1; 86611b1597SPekka Paalanen unsigned rex:1; 87611b1597SPekka Paalanen }; 88611b1597SPekka Paalanen 89611b1597SPekka Paalanen static int skip_prefix(unsigned char *addr, struct prefix_bits *prf) 90ff3a3e9bSPekka Paalanen { 91ff3a3e9bSPekka Paalanen int i; 92ff3a3e9bSPekka Paalanen unsigned char *p = addr; 93611b1597SPekka Paalanen prf->shorted = 0; 94611b1597SPekka Paalanen prf->enlarged = 0; 95611b1597SPekka Paalanen prf->rexr = 0; 96611b1597SPekka Paalanen prf->rex = 0; 97ff3a3e9bSPekka Paalanen 98ff3a3e9bSPekka Paalanen restart: 99ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) { 100ff3a3e9bSPekka Paalanen if (*p == prefix_codes[i]) { 101ff3a3e9bSPekka Paalanen if (*p == 0x66) 102611b1597SPekka Paalanen prf->shorted = 1; 103ff3a3e9bSPekka Paalanen #ifdef __amd64__ 104ff3a3e9bSPekka Paalanen if ((*p & 0xf8) == 0x48) 105611b1597SPekka Paalanen prf->enlarged = 1; 106ff3a3e9bSPekka Paalanen if ((*p & 0xf4) == 0x44) 107611b1597SPekka Paalanen prf->rexr = 1; 108611b1597SPekka Paalanen if ((*p & 0xf0) == 0x40) 109611b1597SPekka Paalanen prf->rex = 1; 110ff3a3e9bSPekka Paalanen #endif 111ff3a3e9bSPekka Paalanen p++; 112ff3a3e9bSPekka Paalanen goto restart; 113ff3a3e9bSPekka Paalanen } 114ff3a3e9bSPekka Paalanen } 115ff3a3e9bSPekka Paalanen 116ff3a3e9bSPekka Paalanen return (p - addr); 117ff3a3e9bSPekka Paalanen } 118ff3a3e9bSPekka Paalanen 119ff3a3e9bSPekka Paalanen static int get_opcode(unsigned char *addr, unsigned int *opcode) 120ff3a3e9bSPekka Paalanen { 121ff3a3e9bSPekka Paalanen int len; 122ff3a3e9bSPekka Paalanen 123ff3a3e9bSPekka Paalanen if (*addr == 0x0F) { 124ff3a3e9bSPekka Paalanen /* 0x0F is extension instruction */ 125ff3a3e9bSPekka Paalanen *opcode = *(unsigned short *)addr; 126ff3a3e9bSPekka Paalanen len = 2; 127ff3a3e9bSPekka Paalanen } else { 128ff3a3e9bSPekka Paalanen *opcode = *addr; 129ff3a3e9bSPekka Paalanen len = 1; 130ff3a3e9bSPekka Paalanen } 131ff3a3e9bSPekka Paalanen 132ff3a3e9bSPekka Paalanen return len; 133ff3a3e9bSPekka Paalanen } 134ff3a3e9bSPekka Paalanen 135ff3a3e9bSPekka Paalanen #define CHECK_OP_TYPE(opcode, array, type) \ 136ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(array); i++) { \ 137ff3a3e9bSPekka Paalanen if (array[i] == opcode) { \ 138ff3a3e9bSPekka Paalanen rv = type; \ 139ff3a3e9bSPekka Paalanen goto exit; \ 140ff3a3e9bSPekka Paalanen } \ 141ff3a3e9bSPekka Paalanen } 142ff3a3e9bSPekka Paalanen 143ff3a3e9bSPekka Paalanen enum reason_type get_ins_type(unsigned long ins_addr) 144ff3a3e9bSPekka Paalanen { 145ff3a3e9bSPekka Paalanen unsigned int opcode; 146ff3a3e9bSPekka Paalanen unsigned char *p; 147611b1597SPekka Paalanen struct prefix_bits prf; 148ff3a3e9bSPekka Paalanen int i; 149ff3a3e9bSPekka Paalanen enum reason_type rv = OTHERS; 150ff3a3e9bSPekka Paalanen 151ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 152611b1597SPekka Paalanen p += skip_prefix(p, &prf); 153ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 154ff3a3e9bSPekka Paalanen 155ff3a3e9bSPekka Paalanen CHECK_OP_TYPE(opcode, reg_rop, REG_READ); 156ff3a3e9bSPekka Paalanen CHECK_OP_TYPE(opcode, reg_wop, REG_WRITE); 157ff3a3e9bSPekka Paalanen CHECK_OP_TYPE(opcode, imm_wop, IMM_WRITE); 158ff3a3e9bSPekka Paalanen 159ff3a3e9bSPekka Paalanen exit: 160ff3a3e9bSPekka Paalanen return rv; 161ff3a3e9bSPekka Paalanen } 162ff3a3e9bSPekka Paalanen #undef CHECK_OP_TYPE 163ff3a3e9bSPekka Paalanen 164ff3a3e9bSPekka Paalanen static unsigned int get_ins_reg_width(unsigned long ins_addr) 165ff3a3e9bSPekka Paalanen { 166ff3a3e9bSPekka Paalanen unsigned int opcode; 167ff3a3e9bSPekka Paalanen unsigned char *p; 168611b1597SPekka Paalanen struct prefix_bits prf; 169611b1597SPekka Paalanen int i; 170ff3a3e9bSPekka Paalanen 171ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 172611b1597SPekka Paalanen p += skip_prefix(p, &prf); 173ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 174ff3a3e9bSPekka Paalanen 175ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(rw8); i++) 176ff3a3e9bSPekka Paalanen if (rw8[i] == opcode) 177ff3a3e9bSPekka Paalanen return 1; 178ff3a3e9bSPekka Paalanen 179ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(rw32); i++) 180ff3a3e9bSPekka Paalanen if (rw32[i] == opcode) 181611b1597SPekka Paalanen return prf.shorted ? 2 : (prf.enlarged ? 8 : 4); 182ff3a3e9bSPekka Paalanen 183ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode); 184ff3a3e9bSPekka Paalanen return 0; 185ff3a3e9bSPekka Paalanen } 186ff3a3e9bSPekka Paalanen 187ff3a3e9bSPekka Paalanen unsigned int get_ins_mem_width(unsigned long ins_addr) 188ff3a3e9bSPekka Paalanen { 189ff3a3e9bSPekka Paalanen unsigned int opcode; 190ff3a3e9bSPekka Paalanen unsigned char *p; 191611b1597SPekka Paalanen struct prefix_bits prf; 192611b1597SPekka Paalanen int i; 193ff3a3e9bSPekka Paalanen 194ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 195611b1597SPekka Paalanen p += skip_prefix(p, &prf); 196ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 197ff3a3e9bSPekka Paalanen 198ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(mw8); i++) 199ff3a3e9bSPekka Paalanen if (mw8[i] == opcode) 200ff3a3e9bSPekka Paalanen return 1; 201ff3a3e9bSPekka Paalanen 202ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(mw16); i++) 203ff3a3e9bSPekka Paalanen if (mw16[i] == opcode) 204ff3a3e9bSPekka Paalanen return 2; 205ff3a3e9bSPekka Paalanen 206ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(mw32); i++) 207ff3a3e9bSPekka Paalanen if (mw32[i] == opcode) 208611b1597SPekka Paalanen return prf.shorted ? 2 : 4; 209ff3a3e9bSPekka Paalanen 210ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(mw64); i++) 211ff3a3e9bSPekka Paalanen if (mw64[i] == opcode) 212611b1597SPekka Paalanen return prf.shorted ? 2 : (prf.enlarged ? 8 : 4); 213ff3a3e9bSPekka Paalanen 214ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode); 215ff3a3e9bSPekka Paalanen return 0; 216ff3a3e9bSPekka Paalanen } 217ff3a3e9bSPekka Paalanen 218ff3a3e9bSPekka Paalanen /* 219ff3a3e9bSPekka Paalanen * Define register ident in mod/rm byte. 220ff3a3e9bSPekka Paalanen * Note: these are NOT the same as in ptrace-abi.h. 221ff3a3e9bSPekka Paalanen */ 222ff3a3e9bSPekka Paalanen enum { 223ff3a3e9bSPekka Paalanen arg_AL = 0, 224ff3a3e9bSPekka Paalanen arg_CL = 1, 225ff3a3e9bSPekka Paalanen arg_DL = 2, 226ff3a3e9bSPekka Paalanen arg_BL = 3, 227ff3a3e9bSPekka Paalanen arg_AH = 4, 228ff3a3e9bSPekka Paalanen arg_CH = 5, 229ff3a3e9bSPekka Paalanen arg_DH = 6, 230ff3a3e9bSPekka Paalanen arg_BH = 7, 231ff3a3e9bSPekka Paalanen 232ff3a3e9bSPekka Paalanen arg_AX = 0, 233ff3a3e9bSPekka Paalanen arg_CX = 1, 234ff3a3e9bSPekka Paalanen arg_DX = 2, 235ff3a3e9bSPekka Paalanen arg_BX = 3, 236ff3a3e9bSPekka Paalanen arg_SP = 4, 237ff3a3e9bSPekka Paalanen arg_BP = 5, 238ff3a3e9bSPekka Paalanen arg_SI = 6, 239ff3a3e9bSPekka Paalanen arg_DI = 7, 240ff3a3e9bSPekka Paalanen #ifdef __amd64__ 241ff3a3e9bSPekka Paalanen arg_R8 = 8, 242ff3a3e9bSPekka Paalanen arg_R9 = 9, 243ff3a3e9bSPekka Paalanen arg_R10 = 10, 244ff3a3e9bSPekka Paalanen arg_R11 = 11, 245ff3a3e9bSPekka Paalanen arg_R12 = 12, 246ff3a3e9bSPekka Paalanen arg_R13 = 13, 247ff3a3e9bSPekka Paalanen arg_R14 = 14, 248ff3a3e9bSPekka Paalanen arg_R15 = 15 249ff3a3e9bSPekka Paalanen #endif 250ff3a3e9bSPekka Paalanen }; 251ff3a3e9bSPekka Paalanen 252611b1597SPekka Paalanen static unsigned char *get_reg_w8(int no, int rex, struct pt_regs *regs) 253ff3a3e9bSPekka Paalanen { 254ff3a3e9bSPekka Paalanen unsigned char *rv = NULL; 255ff3a3e9bSPekka Paalanen 256ff3a3e9bSPekka Paalanen switch (no) { 257ff3a3e9bSPekka Paalanen case arg_AL: 258ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->ax; 259ff3a3e9bSPekka Paalanen break; 260ff3a3e9bSPekka Paalanen case arg_BL: 261ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->bx; 262ff3a3e9bSPekka Paalanen break; 263ff3a3e9bSPekka Paalanen case arg_CL: 264ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->cx; 265ff3a3e9bSPekka Paalanen break; 266ff3a3e9bSPekka Paalanen case arg_DL: 267ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->dx; 268ff3a3e9bSPekka Paalanen break; 269ff3a3e9bSPekka Paalanen #ifdef __amd64__ 270ff3a3e9bSPekka Paalanen case arg_R8: 271ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r8; 272ff3a3e9bSPekka Paalanen break; 273ff3a3e9bSPekka Paalanen case arg_R9: 274ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r9; 275ff3a3e9bSPekka Paalanen break; 276ff3a3e9bSPekka Paalanen case arg_R10: 277ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r10; 278ff3a3e9bSPekka Paalanen break; 279ff3a3e9bSPekka Paalanen case arg_R11: 280ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r11; 281ff3a3e9bSPekka Paalanen break; 282ff3a3e9bSPekka Paalanen case arg_R12: 283ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r12; 284ff3a3e9bSPekka Paalanen break; 285ff3a3e9bSPekka Paalanen case arg_R13: 286ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r13; 287ff3a3e9bSPekka Paalanen break; 288ff3a3e9bSPekka Paalanen case arg_R14: 289ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r14; 290ff3a3e9bSPekka Paalanen break; 291ff3a3e9bSPekka Paalanen case arg_R15: 292ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r15; 293ff3a3e9bSPekka Paalanen break; 294ff3a3e9bSPekka Paalanen #endif 295ff3a3e9bSPekka Paalanen default: 296ff3a3e9bSPekka Paalanen break; 297ff3a3e9bSPekka Paalanen } 298611b1597SPekka Paalanen 299611b1597SPekka Paalanen if (rv) 300611b1597SPekka Paalanen return rv; 301611b1597SPekka Paalanen 302611b1597SPekka Paalanen if (rex) { 303611b1597SPekka Paalanen /* 304611b1597SPekka Paalanen * If REX prefix exists, access low bytes of SI etc. 305611b1597SPekka Paalanen * instead of AH etc. 306611b1597SPekka Paalanen */ 307611b1597SPekka Paalanen switch (no) { 308611b1597SPekka Paalanen case arg_SI: 309611b1597SPekka Paalanen rv = (unsigned char *)®s->si; 310611b1597SPekka Paalanen break; 311611b1597SPekka Paalanen case arg_DI: 312611b1597SPekka Paalanen rv = (unsigned char *)®s->di; 313611b1597SPekka Paalanen break; 314611b1597SPekka Paalanen case arg_BP: 315611b1597SPekka Paalanen rv = (unsigned char *)®s->bp; 316611b1597SPekka Paalanen break; 317611b1597SPekka Paalanen case arg_SP: 318611b1597SPekka Paalanen rv = (unsigned char *)®s->sp; 319611b1597SPekka Paalanen break; 320611b1597SPekka Paalanen default: 321611b1597SPekka Paalanen break; 322611b1597SPekka Paalanen } 323611b1597SPekka Paalanen } else { 324611b1597SPekka Paalanen switch (no) { 325611b1597SPekka Paalanen case arg_AH: 326611b1597SPekka Paalanen rv = 1 + (unsigned char *)®s->ax; 327611b1597SPekka Paalanen break; 328611b1597SPekka Paalanen case arg_BH: 329611b1597SPekka Paalanen rv = 1 + (unsigned char *)®s->bx; 330611b1597SPekka Paalanen break; 331611b1597SPekka Paalanen case arg_CH: 332611b1597SPekka Paalanen rv = 1 + (unsigned char *)®s->cx; 333611b1597SPekka Paalanen break; 334611b1597SPekka Paalanen case arg_DH: 335611b1597SPekka Paalanen rv = 1 + (unsigned char *)®s->dx; 336611b1597SPekka Paalanen break; 337611b1597SPekka Paalanen default: 338611b1597SPekka Paalanen break; 339611b1597SPekka Paalanen } 340611b1597SPekka Paalanen } 341611b1597SPekka Paalanen 342611b1597SPekka Paalanen if (!rv) 343611b1597SPekka Paalanen printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no); 344611b1597SPekka Paalanen 345ff3a3e9bSPekka Paalanen return rv; 346ff3a3e9bSPekka Paalanen } 347ff3a3e9bSPekka Paalanen 348ff3a3e9bSPekka Paalanen static unsigned long *get_reg_w32(int no, struct pt_regs *regs) 349ff3a3e9bSPekka Paalanen { 350ff3a3e9bSPekka Paalanen unsigned long *rv = NULL; 351ff3a3e9bSPekka Paalanen 352ff3a3e9bSPekka Paalanen switch (no) { 353ff3a3e9bSPekka Paalanen case arg_AX: 354ff3a3e9bSPekka Paalanen rv = ®s->ax; 355ff3a3e9bSPekka Paalanen break; 356ff3a3e9bSPekka Paalanen case arg_BX: 357ff3a3e9bSPekka Paalanen rv = ®s->bx; 358ff3a3e9bSPekka Paalanen break; 359ff3a3e9bSPekka Paalanen case arg_CX: 360ff3a3e9bSPekka Paalanen rv = ®s->cx; 361ff3a3e9bSPekka Paalanen break; 362ff3a3e9bSPekka Paalanen case arg_DX: 363ff3a3e9bSPekka Paalanen rv = ®s->dx; 364ff3a3e9bSPekka Paalanen break; 365ff3a3e9bSPekka Paalanen case arg_SP: 366ff3a3e9bSPekka Paalanen rv = ®s->sp; 367ff3a3e9bSPekka Paalanen break; 368ff3a3e9bSPekka Paalanen case arg_BP: 369ff3a3e9bSPekka Paalanen rv = ®s->bp; 370ff3a3e9bSPekka Paalanen break; 371ff3a3e9bSPekka Paalanen case arg_SI: 372ff3a3e9bSPekka Paalanen rv = ®s->si; 373ff3a3e9bSPekka Paalanen break; 374ff3a3e9bSPekka Paalanen case arg_DI: 375ff3a3e9bSPekka Paalanen rv = ®s->di; 376ff3a3e9bSPekka Paalanen break; 377ff3a3e9bSPekka Paalanen #ifdef __amd64__ 378ff3a3e9bSPekka Paalanen case arg_R8: 379ff3a3e9bSPekka Paalanen rv = ®s->r8; 380ff3a3e9bSPekka Paalanen break; 381ff3a3e9bSPekka Paalanen case arg_R9: 382ff3a3e9bSPekka Paalanen rv = ®s->r9; 383ff3a3e9bSPekka Paalanen break; 384ff3a3e9bSPekka Paalanen case arg_R10: 385ff3a3e9bSPekka Paalanen rv = ®s->r10; 386ff3a3e9bSPekka Paalanen break; 387ff3a3e9bSPekka Paalanen case arg_R11: 388ff3a3e9bSPekka Paalanen rv = ®s->r11; 389ff3a3e9bSPekka Paalanen break; 390ff3a3e9bSPekka Paalanen case arg_R12: 391ff3a3e9bSPekka Paalanen rv = ®s->r12; 392ff3a3e9bSPekka Paalanen break; 393ff3a3e9bSPekka Paalanen case arg_R13: 394ff3a3e9bSPekka Paalanen rv = ®s->r13; 395ff3a3e9bSPekka Paalanen break; 396ff3a3e9bSPekka Paalanen case arg_R14: 397ff3a3e9bSPekka Paalanen rv = ®s->r14; 398ff3a3e9bSPekka Paalanen break; 399ff3a3e9bSPekka Paalanen case arg_R15: 400ff3a3e9bSPekka Paalanen rv = ®s->r15; 401ff3a3e9bSPekka Paalanen break; 402ff3a3e9bSPekka Paalanen #endif 403ff3a3e9bSPekka Paalanen default: 404ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no); 405ff3a3e9bSPekka Paalanen } 406ff3a3e9bSPekka Paalanen 407ff3a3e9bSPekka Paalanen return rv; 408ff3a3e9bSPekka Paalanen } 409ff3a3e9bSPekka Paalanen 410ff3a3e9bSPekka Paalanen unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs) 411ff3a3e9bSPekka Paalanen { 412ff3a3e9bSPekka Paalanen unsigned int opcode; 413ff3a3e9bSPekka Paalanen unsigned char mod_rm; 414ff3a3e9bSPekka Paalanen int reg; 415ff3a3e9bSPekka Paalanen unsigned char *p; 416611b1597SPekka Paalanen struct prefix_bits prf; 417611b1597SPekka Paalanen int i; 418ff3a3e9bSPekka Paalanen unsigned long rv; 419ff3a3e9bSPekka Paalanen 420ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 421611b1597SPekka Paalanen p += skip_prefix(p, &prf); 422ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 423ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(reg_rop); i++) 424ff3a3e9bSPekka Paalanen if (reg_rop[i] == opcode) { 425ff3a3e9bSPekka Paalanen rv = REG_READ; 426ff3a3e9bSPekka Paalanen goto do_work; 427ff3a3e9bSPekka Paalanen } 428ff3a3e9bSPekka Paalanen 429ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(reg_wop); i++) 430ff3a3e9bSPekka Paalanen if (reg_wop[i] == opcode) { 431ff3a3e9bSPekka Paalanen rv = REG_WRITE; 432ff3a3e9bSPekka Paalanen goto do_work; 433ff3a3e9bSPekka Paalanen } 434ff3a3e9bSPekka Paalanen 435ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Not a register instruction, opcode " 436ff3a3e9bSPekka Paalanen "0x%02x\n", opcode); 437ff3a3e9bSPekka Paalanen goto err; 438ff3a3e9bSPekka Paalanen 439ff3a3e9bSPekka Paalanen do_work: 440ff3a3e9bSPekka Paalanen mod_rm = *p; 441611b1597SPekka Paalanen reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3); 442ff3a3e9bSPekka Paalanen switch (get_ins_reg_width(ins_addr)) { 443ff3a3e9bSPekka Paalanen case 1: 444611b1597SPekka Paalanen return *get_reg_w8(reg, prf.rex, regs); 445ff3a3e9bSPekka Paalanen 446ff3a3e9bSPekka Paalanen case 2: 447ff3a3e9bSPekka Paalanen return *(unsigned short *)get_reg_w32(reg, regs); 448ff3a3e9bSPekka Paalanen 449ff3a3e9bSPekka Paalanen case 4: 450ff3a3e9bSPekka Paalanen return *(unsigned int *)get_reg_w32(reg, regs); 451ff3a3e9bSPekka Paalanen 452ff3a3e9bSPekka Paalanen #ifdef __amd64__ 453ff3a3e9bSPekka Paalanen case 8: 454ff3a3e9bSPekka Paalanen return *(unsigned long *)get_reg_w32(reg, regs); 455ff3a3e9bSPekka Paalanen #endif 456ff3a3e9bSPekka Paalanen 457ff3a3e9bSPekka Paalanen default: 458ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Error width# %d\n", reg); 459ff3a3e9bSPekka Paalanen } 460ff3a3e9bSPekka Paalanen 461ff3a3e9bSPekka Paalanen err: 462ff3a3e9bSPekka Paalanen return 0; 463ff3a3e9bSPekka Paalanen } 464ff3a3e9bSPekka Paalanen 465ff3a3e9bSPekka Paalanen unsigned long get_ins_imm_val(unsigned long ins_addr) 466ff3a3e9bSPekka Paalanen { 467ff3a3e9bSPekka Paalanen unsigned int opcode; 468ff3a3e9bSPekka Paalanen unsigned char mod_rm; 469ff3a3e9bSPekka Paalanen unsigned char mod; 470ff3a3e9bSPekka Paalanen unsigned char *p; 471611b1597SPekka Paalanen struct prefix_bits prf; 472611b1597SPekka Paalanen int i; 473ff3a3e9bSPekka Paalanen unsigned long rv; 474ff3a3e9bSPekka Paalanen 475ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 476611b1597SPekka Paalanen p += skip_prefix(p, &prf); 477ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 478ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(imm_wop); i++) 479ff3a3e9bSPekka Paalanen if (imm_wop[i] == opcode) { 480ff3a3e9bSPekka Paalanen rv = IMM_WRITE; 481ff3a3e9bSPekka Paalanen goto do_work; 482ff3a3e9bSPekka Paalanen } 483ff3a3e9bSPekka Paalanen 484ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Not an immediate instruction, opcode " 485ff3a3e9bSPekka Paalanen "0x%02x\n", opcode); 486ff3a3e9bSPekka Paalanen goto err; 487ff3a3e9bSPekka Paalanen 488ff3a3e9bSPekka Paalanen do_work: 489ff3a3e9bSPekka Paalanen mod_rm = *p; 490ff3a3e9bSPekka Paalanen mod = mod_rm >> 6; 491ff3a3e9bSPekka Paalanen p++; 492ff3a3e9bSPekka Paalanen switch (mod) { 493ff3a3e9bSPekka Paalanen case 0: 494ff3a3e9bSPekka Paalanen /* if r/m is 5 we have a 32 disp (IA32 Manual 3, Table 2-2) */ 495ff3a3e9bSPekka Paalanen /* AMD64: XXX Check for address size prefix? */ 496ff3a3e9bSPekka Paalanen if ((mod_rm & 0x7) == 0x5) 497ff3a3e9bSPekka Paalanen p += 4; 498ff3a3e9bSPekka Paalanen break; 499ff3a3e9bSPekka Paalanen 500ff3a3e9bSPekka Paalanen case 1: 501ff3a3e9bSPekka Paalanen p += 1; 502ff3a3e9bSPekka Paalanen break; 503ff3a3e9bSPekka Paalanen 504ff3a3e9bSPekka Paalanen case 2: 505ff3a3e9bSPekka Paalanen p += 4; 506ff3a3e9bSPekka Paalanen break; 507ff3a3e9bSPekka Paalanen 508ff3a3e9bSPekka Paalanen case 3: 509ff3a3e9bSPekka Paalanen default: 510ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: not a memory access instruction " 511ff3a3e9bSPekka Paalanen "at 0x%lx, rm_mod=0x%02x\n", 512ff3a3e9bSPekka Paalanen ins_addr, mod_rm); 513ff3a3e9bSPekka Paalanen } 514ff3a3e9bSPekka Paalanen 515ff3a3e9bSPekka Paalanen switch (get_ins_reg_width(ins_addr)) { 516ff3a3e9bSPekka Paalanen case 1: 517ff3a3e9bSPekka Paalanen return *(unsigned char *)p; 518ff3a3e9bSPekka Paalanen 519ff3a3e9bSPekka Paalanen case 2: 520ff3a3e9bSPekka Paalanen return *(unsigned short *)p; 521ff3a3e9bSPekka Paalanen 522ff3a3e9bSPekka Paalanen case 4: 523ff3a3e9bSPekka Paalanen return *(unsigned int *)p; 524ff3a3e9bSPekka Paalanen 525ff3a3e9bSPekka Paalanen #ifdef __amd64__ 526ff3a3e9bSPekka Paalanen case 8: 527ff3a3e9bSPekka Paalanen return *(unsigned long *)p; 528ff3a3e9bSPekka Paalanen #endif 529ff3a3e9bSPekka Paalanen 530ff3a3e9bSPekka Paalanen default: 531ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Error: width.\n"); 532ff3a3e9bSPekka Paalanen } 533ff3a3e9bSPekka Paalanen 534ff3a3e9bSPekka Paalanen err: 535ff3a3e9bSPekka Paalanen return 0; 536ff3a3e9bSPekka Paalanen } 537