1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2ff3a3e9bSPekka Paalanen /* 3ff3a3e9bSPekka Paalanen * Fault Injection Test harness (FI) 4ff3a3e9bSPekka Paalanen * Copyright (C) Intel Crop. 5ff3a3e9bSPekka Paalanen */ 6ff3a3e9bSPekka Paalanen 7ff3a3e9bSPekka Paalanen /* Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp 8ff3a3e9bSPekka Paalanen * Copyright by Intel Crop., 2002 9ff3a3e9bSPekka Paalanen * Louis Zhuang (louis.zhuang@intel.com) 10ff3a3e9bSPekka Paalanen * 11ff3a3e9bSPekka Paalanen * Bjorn Steinbrink (B.Steinbrink@gmx.de), 2007 12ff3a3e9bSPekka Paalanen */ 13ff3a3e9bSPekka Paalanen 14ff3a3e9bSPekka Paalanen #include <linux/ptrace.h> /* struct pt_regs */ 15ff3a3e9bSPekka Paalanen #include "pf_in.h" 16ff3a3e9bSPekka Paalanen 17ff3a3e9bSPekka Paalanen #ifdef __i386__ 18ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 2-1 */ 19ff3a3e9bSPekka Paalanen static unsigned char prefix_codes[] = { 20ff3a3e9bSPekka Paalanen 0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64, 21841bca13SAkinobu Mita 0x65, 0x66, 0x67 22ff3a3e9bSPekka Paalanen }; 23ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 3-432*/ 24ff3a3e9bSPekka Paalanen static unsigned int reg_rop[] = { 25ff3a3e9bSPekka Paalanen 0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F 26ff3a3e9bSPekka Paalanen }; 27cc05152aSMarcin Slusarz static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB }; 28ff3a3e9bSPekka Paalanen static unsigned int imm_wop[] = { 0xC6, 0xC7 }; 29ff3a3e9bSPekka Paalanen /* IA32 Manual 3, 3-432*/ 30cc05152aSMarcin Slusarz static unsigned int rw8[] = { 0x88, 0x8A, 0xC6, 0xAA }; 31ff3a3e9bSPekka Paalanen static unsigned int rw32[] = { 32cc05152aSMarcin Slusarz 0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB 33ff3a3e9bSPekka Paalanen }; 34cc05152aSMarcin Slusarz static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F, 0xAA }; 35ff3a3e9bSPekka Paalanen static unsigned int mw16[] = { 0xB70F, 0xBF0F }; 36cc05152aSMarcin Slusarz static unsigned int mw32[] = { 0x89, 0x8B, 0xC7, 0xAB }; 37ff3a3e9bSPekka Paalanen static unsigned int mw64[] = {}; 38ff3a3e9bSPekka Paalanen #else /* not __i386__ */ 39ff3a3e9bSPekka Paalanen static unsigned char prefix_codes[] = { 40ff3a3e9bSPekka Paalanen 0x66, 0x67, 0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36, 41ff3a3e9bSPekka Paalanen 0xF0, 0xF3, 0xF2, 42ff3a3e9bSPekka Paalanen /* REX Prefixes */ 43ff3a3e9bSPekka Paalanen 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 44ff3a3e9bSPekka Paalanen 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f 45ff3a3e9bSPekka Paalanen }; 46ff3a3e9bSPekka Paalanen /* AMD64 Manual 3, Appendix A*/ 47ff3a3e9bSPekka Paalanen static unsigned int reg_rop[] = { 48ff3a3e9bSPekka Paalanen 0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F 49ff3a3e9bSPekka Paalanen }; 50cc05152aSMarcin Slusarz static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB }; 51ff3a3e9bSPekka Paalanen static unsigned int imm_wop[] = { 0xC6, 0xC7 }; 52cc05152aSMarcin Slusarz static unsigned int rw8[] = { 0xC6, 0x88, 0x8A, 0xAA }; 53ff3a3e9bSPekka Paalanen static unsigned int rw32[] = { 54cc05152aSMarcin Slusarz 0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB 55ff3a3e9bSPekka Paalanen }; 56ff3a3e9bSPekka Paalanen /* 8 bit only */ 57cc05152aSMarcin Slusarz static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F, 0xAA }; 58ff3a3e9bSPekka Paalanen /* 16 bit only */ 59ff3a3e9bSPekka Paalanen static unsigned int mw16[] = { 0xB70F, 0xBF0F }; 60ff3a3e9bSPekka Paalanen /* 16 or 32 bit */ 61ff3a3e9bSPekka Paalanen static unsigned int mw32[] = { 0xC7 }; 62ff3a3e9bSPekka Paalanen /* 16, 32 or 64 bit */ 63cc05152aSMarcin Slusarz static unsigned int mw64[] = { 0x89, 0x8B, 0xAB }; 64ff3a3e9bSPekka Paalanen #endif /* not __i386__ */ 65ff3a3e9bSPekka Paalanen 66611b1597SPekka Paalanen struct prefix_bits { 67611b1597SPekka Paalanen unsigned shorted:1; 68611b1597SPekka Paalanen unsigned enlarged:1; 69611b1597SPekka Paalanen unsigned rexr:1; 70611b1597SPekka Paalanen unsigned rex:1; 71611b1597SPekka Paalanen }; 72611b1597SPekka Paalanen 73611b1597SPekka Paalanen static int skip_prefix(unsigned char *addr, struct prefix_bits *prf) 74ff3a3e9bSPekka Paalanen { 75ff3a3e9bSPekka Paalanen int i; 76ff3a3e9bSPekka Paalanen unsigned char *p = addr; 77611b1597SPekka Paalanen prf->shorted = 0; 78611b1597SPekka Paalanen prf->enlarged = 0; 79611b1597SPekka Paalanen prf->rexr = 0; 80611b1597SPekka Paalanen prf->rex = 0; 81ff3a3e9bSPekka Paalanen 82ff3a3e9bSPekka Paalanen restart: 83ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) { 84ff3a3e9bSPekka Paalanen if (*p == prefix_codes[i]) { 85ff3a3e9bSPekka Paalanen if (*p == 0x66) 86611b1597SPekka Paalanen prf->shorted = 1; 87ff3a3e9bSPekka Paalanen #ifdef __amd64__ 88ff3a3e9bSPekka Paalanen if ((*p & 0xf8) == 0x48) 89611b1597SPekka Paalanen prf->enlarged = 1; 90ff3a3e9bSPekka Paalanen if ((*p & 0xf4) == 0x44) 91611b1597SPekka Paalanen prf->rexr = 1; 92611b1597SPekka Paalanen if ((*p & 0xf0) == 0x40) 93611b1597SPekka Paalanen prf->rex = 1; 94ff3a3e9bSPekka Paalanen #endif 95ff3a3e9bSPekka Paalanen p++; 96ff3a3e9bSPekka Paalanen goto restart; 97ff3a3e9bSPekka Paalanen } 98ff3a3e9bSPekka Paalanen } 99ff3a3e9bSPekka Paalanen 100ff3a3e9bSPekka Paalanen return (p - addr); 101ff3a3e9bSPekka Paalanen } 102ff3a3e9bSPekka Paalanen 103ff3a3e9bSPekka Paalanen static int get_opcode(unsigned char *addr, unsigned int *opcode) 104ff3a3e9bSPekka Paalanen { 105ff3a3e9bSPekka Paalanen int len; 106ff3a3e9bSPekka Paalanen 107ff3a3e9bSPekka Paalanen if (*addr == 0x0F) { 108ff3a3e9bSPekka Paalanen /* 0x0F is extension instruction */ 109ff3a3e9bSPekka Paalanen *opcode = *(unsigned short *)addr; 110ff3a3e9bSPekka Paalanen len = 2; 111ff3a3e9bSPekka Paalanen } else { 112ff3a3e9bSPekka Paalanen *opcode = *addr; 113ff3a3e9bSPekka Paalanen len = 1; 114ff3a3e9bSPekka Paalanen } 115ff3a3e9bSPekka Paalanen 116ff3a3e9bSPekka Paalanen return len; 117ff3a3e9bSPekka Paalanen } 118ff3a3e9bSPekka Paalanen 119ff3a3e9bSPekka Paalanen #define CHECK_OP_TYPE(opcode, array, type) \ 120ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(array); i++) { \ 121ff3a3e9bSPekka Paalanen if (array[i] == opcode) { \ 122ff3a3e9bSPekka Paalanen rv = type; \ 123ff3a3e9bSPekka Paalanen goto exit; \ 124ff3a3e9bSPekka Paalanen } \ 125ff3a3e9bSPekka Paalanen } 126ff3a3e9bSPekka Paalanen 127ff3a3e9bSPekka Paalanen enum reason_type get_ins_type(unsigned long ins_addr) 128ff3a3e9bSPekka Paalanen { 129ff3a3e9bSPekka Paalanen unsigned int opcode; 130ff3a3e9bSPekka Paalanen unsigned char *p; 131611b1597SPekka Paalanen struct prefix_bits prf; 132ff3a3e9bSPekka Paalanen int i; 133ff3a3e9bSPekka Paalanen enum reason_type rv = OTHERS; 134ff3a3e9bSPekka Paalanen 135ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 136611b1597SPekka Paalanen p += skip_prefix(p, &prf); 137ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 138ff3a3e9bSPekka Paalanen 139ff3a3e9bSPekka Paalanen CHECK_OP_TYPE(opcode, reg_rop, REG_READ); 140ff3a3e9bSPekka Paalanen CHECK_OP_TYPE(opcode, reg_wop, REG_WRITE); 141ff3a3e9bSPekka Paalanen CHECK_OP_TYPE(opcode, imm_wop, IMM_WRITE); 142ff3a3e9bSPekka Paalanen 143ff3a3e9bSPekka Paalanen exit: 144ff3a3e9bSPekka Paalanen return rv; 145ff3a3e9bSPekka Paalanen } 146ff3a3e9bSPekka Paalanen #undef CHECK_OP_TYPE 147ff3a3e9bSPekka Paalanen 148ff3a3e9bSPekka Paalanen static unsigned int get_ins_reg_width(unsigned long ins_addr) 149ff3a3e9bSPekka Paalanen { 150ff3a3e9bSPekka Paalanen unsigned int opcode; 151ff3a3e9bSPekka Paalanen unsigned char *p; 152611b1597SPekka Paalanen struct prefix_bits prf; 153611b1597SPekka Paalanen int i; 154ff3a3e9bSPekka Paalanen 155ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 156611b1597SPekka Paalanen p += skip_prefix(p, &prf); 157ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 158ff3a3e9bSPekka Paalanen 159ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(rw8); i++) 160ff3a3e9bSPekka Paalanen if (rw8[i] == opcode) 161ff3a3e9bSPekka Paalanen return 1; 162ff3a3e9bSPekka Paalanen 163ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(rw32); i++) 164ff3a3e9bSPekka Paalanen if (rw32[i] == opcode) 165611b1597SPekka Paalanen return prf.shorted ? 2 : (prf.enlarged ? 8 : 4); 166ff3a3e9bSPekka Paalanen 167ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode); 168ff3a3e9bSPekka Paalanen return 0; 169ff3a3e9bSPekka Paalanen } 170ff3a3e9bSPekka Paalanen 171ff3a3e9bSPekka Paalanen unsigned int get_ins_mem_width(unsigned long ins_addr) 172ff3a3e9bSPekka Paalanen { 173ff3a3e9bSPekka Paalanen unsigned int opcode; 174ff3a3e9bSPekka Paalanen unsigned char *p; 175611b1597SPekka Paalanen struct prefix_bits prf; 176611b1597SPekka Paalanen int i; 177ff3a3e9bSPekka Paalanen 178ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 179611b1597SPekka Paalanen p += skip_prefix(p, &prf); 180ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 181ff3a3e9bSPekka Paalanen 182ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(mw8); i++) 183ff3a3e9bSPekka Paalanen if (mw8[i] == opcode) 184ff3a3e9bSPekka Paalanen return 1; 185ff3a3e9bSPekka Paalanen 186ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(mw16); i++) 187ff3a3e9bSPekka Paalanen if (mw16[i] == opcode) 188ff3a3e9bSPekka Paalanen return 2; 189ff3a3e9bSPekka Paalanen 190ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(mw32); i++) 191ff3a3e9bSPekka Paalanen if (mw32[i] == opcode) 192611b1597SPekka Paalanen return prf.shorted ? 2 : 4; 193ff3a3e9bSPekka Paalanen 194ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(mw64); i++) 195ff3a3e9bSPekka Paalanen if (mw64[i] == opcode) 196611b1597SPekka Paalanen return prf.shorted ? 2 : (prf.enlarged ? 8 : 4); 197ff3a3e9bSPekka Paalanen 198ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode); 199ff3a3e9bSPekka Paalanen return 0; 200ff3a3e9bSPekka Paalanen } 201ff3a3e9bSPekka Paalanen 202ff3a3e9bSPekka Paalanen /* 203ff3a3e9bSPekka Paalanen * Define register ident in mod/rm byte. 204ff3a3e9bSPekka Paalanen * Note: these are NOT the same as in ptrace-abi.h. 205ff3a3e9bSPekka Paalanen */ 206ff3a3e9bSPekka Paalanen enum { 207ff3a3e9bSPekka Paalanen arg_AL = 0, 208ff3a3e9bSPekka Paalanen arg_CL = 1, 209ff3a3e9bSPekka Paalanen arg_DL = 2, 210ff3a3e9bSPekka Paalanen arg_BL = 3, 211ff3a3e9bSPekka Paalanen arg_AH = 4, 212ff3a3e9bSPekka Paalanen arg_CH = 5, 213ff3a3e9bSPekka Paalanen arg_DH = 6, 214ff3a3e9bSPekka Paalanen arg_BH = 7, 215ff3a3e9bSPekka Paalanen 216ff3a3e9bSPekka Paalanen arg_AX = 0, 217ff3a3e9bSPekka Paalanen arg_CX = 1, 218ff3a3e9bSPekka Paalanen arg_DX = 2, 219ff3a3e9bSPekka Paalanen arg_BX = 3, 220ff3a3e9bSPekka Paalanen arg_SP = 4, 221ff3a3e9bSPekka Paalanen arg_BP = 5, 222ff3a3e9bSPekka Paalanen arg_SI = 6, 223ff3a3e9bSPekka Paalanen arg_DI = 7, 224ff3a3e9bSPekka Paalanen #ifdef __amd64__ 225ff3a3e9bSPekka Paalanen arg_R8 = 8, 226ff3a3e9bSPekka Paalanen arg_R9 = 9, 227ff3a3e9bSPekka Paalanen arg_R10 = 10, 228ff3a3e9bSPekka Paalanen arg_R11 = 11, 229ff3a3e9bSPekka Paalanen arg_R12 = 12, 230ff3a3e9bSPekka Paalanen arg_R13 = 13, 231ff3a3e9bSPekka Paalanen arg_R14 = 14, 232ff3a3e9bSPekka Paalanen arg_R15 = 15 233ff3a3e9bSPekka Paalanen #endif 234ff3a3e9bSPekka Paalanen }; 235ff3a3e9bSPekka Paalanen 236611b1597SPekka Paalanen static unsigned char *get_reg_w8(int no, int rex, struct pt_regs *regs) 237ff3a3e9bSPekka Paalanen { 238ff3a3e9bSPekka Paalanen unsigned char *rv = NULL; 239ff3a3e9bSPekka Paalanen 240ff3a3e9bSPekka Paalanen switch (no) { 241ff3a3e9bSPekka Paalanen case arg_AL: 242ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->ax; 243ff3a3e9bSPekka Paalanen break; 244ff3a3e9bSPekka Paalanen case arg_BL: 245ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->bx; 246ff3a3e9bSPekka Paalanen break; 247ff3a3e9bSPekka Paalanen case arg_CL: 248ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->cx; 249ff3a3e9bSPekka Paalanen break; 250ff3a3e9bSPekka Paalanen case arg_DL: 251ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->dx; 252ff3a3e9bSPekka Paalanen break; 253ff3a3e9bSPekka Paalanen #ifdef __amd64__ 254ff3a3e9bSPekka Paalanen case arg_R8: 255ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r8; 256ff3a3e9bSPekka Paalanen break; 257ff3a3e9bSPekka Paalanen case arg_R9: 258ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r9; 259ff3a3e9bSPekka Paalanen break; 260ff3a3e9bSPekka Paalanen case arg_R10: 261ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r10; 262ff3a3e9bSPekka Paalanen break; 263ff3a3e9bSPekka Paalanen case arg_R11: 264ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r11; 265ff3a3e9bSPekka Paalanen break; 266ff3a3e9bSPekka Paalanen case arg_R12: 267ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r12; 268ff3a3e9bSPekka Paalanen break; 269ff3a3e9bSPekka Paalanen case arg_R13: 270ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r13; 271ff3a3e9bSPekka Paalanen break; 272ff3a3e9bSPekka Paalanen case arg_R14: 273ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r14; 274ff3a3e9bSPekka Paalanen break; 275ff3a3e9bSPekka Paalanen case arg_R15: 276ff3a3e9bSPekka Paalanen rv = (unsigned char *)®s->r15; 277ff3a3e9bSPekka Paalanen break; 278ff3a3e9bSPekka Paalanen #endif 279ff3a3e9bSPekka Paalanen default: 280ff3a3e9bSPekka Paalanen break; 281ff3a3e9bSPekka Paalanen } 282611b1597SPekka Paalanen 283611b1597SPekka Paalanen if (rv) 284611b1597SPekka Paalanen return rv; 285611b1597SPekka Paalanen 286611b1597SPekka Paalanen if (rex) { 287611b1597SPekka Paalanen /* 288611b1597SPekka Paalanen * If REX prefix exists, access low bytes of SI etc. 289611b1597SPekka Paalanen * instead of AH etc. 290611b1597SPekka Paalanen */ 291611b1597SPekka Paalanen switch (no) { 292611b1597SPekka Paalanen case arg_SI: 293611b1597SPekka Paalanen rv = (unsigned char *)®s->si; 294611b1597SPekka Paalanen break; 295611b1597SPekka Paalanen case arg_DI: 296611b1597SPekka Paalanen rv = (unsigned char *)®s->di; 297611b1597SPekka Paalanen break; 298611b1597SPekka Paalanen case arg_BP: 299611b1597SPekka Paalanen rv = (unsigned char *)®s->bp; 300611b1597SPekka Paalanen break; 301611b1597SPekka Paalanen case arg_SP: 302611b1597SPekka Paalanen rv = (unsigned char *)®s->sp; 303611b1597SPekka Paalanen break; 304611b1597SPekka Paalanen default: 305611b1597SPekka Paalanen break; 306611b1597SPekka Paalanen } 307611b1597SPekka Paalanen } else { 308611b1597SPekka Paalanen switch (no) { 309611b1597SPekka Paalanen case arg_AH: 310611b1597SPekka Paalanen rv = 1 + (unsigned char *)®s->ax; 311611b1597SPekka Paalanen break; 312611b1597SPekka Paalanen case arg_BH: 313611b1597SPekka Paalanen rv = 1 + (unsigned char *)®s->bx; 314611b1597SPekka Paalanen break; 315611b1597SPekka Paalanen case arg_CH: 316611b1597SPekka Paalanen rv = 1 + (unsigned char *)®s->cx; 317611b1597SPekka Paalanen break; 318611b1597SPekka Paalanen case arg_DH: 319611b1597SPekka Paalanen rv = 1 + (unsigned char *)®s->dx; 320611b1597SPekka Paalanen break; 321611b1597SPekka Paalanen default: 322611b1597SPekka Paalanen break; 323611b1597SPekka Paalanen } 324611b1597SPekka Paalanen } 325611b1597SPekka Paalanen 326611b1597SPekka Paalanen if (!rv) 327611b1597SPekka Paalanen printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no); 328611b1597SPekka Paalanen 329ff3a3e9bSPekka Paalanen return rv; 330ff3a3e9bSPekka Paalanen } 331ff3a3e9bSPekka Paalanen 332ff3a3e9bSPekka Paalanen static unsigned long *get_reg_w32(int no, struct pt_regs *regs) 333ff3a3e9bSPekka Paalanen { 334ff3a3e9bSPekka Paalanen unsigned long *rv = NULL; 335ff3a3e9bSPekka Paalanen 336ff3a3e9bSPekka Paalanen switch (no) { 337ff3a3e9bSPekka Paalanen case arg_AX: 338ff3a3e9bSPekka Paalanen rv = ®s->ax; 339ff3a3e9bSPekka Paalanen break; 340ff3a3e9bSPekka Paalanen case arg_BX: 341ff3a3e9bSPekka Paalanen rv = ®s->bx; 342ff3a3e9bSPekka Paalanen break; 343ff3a3e9bSPekka Paalanen case arg_CX: 344ff3a3e9bSPekka Paalanen rv = ®s->cx; 345ff3a3e9bSPekka Paalanen break; 346ff3a3e9bSPekka Paalanen case arg_DX: 347ff3a3e9bSPekka Paalanen rv = ®s->dx; 348ff3a3e9bSPekka Paalanen break; 349ff3a3e9bSPekka Paalanen case arg_SP: 350ff3a3e9bSPekka Paalanen rv = ®s->sp; 351ff3a3e9bSPekka Paalanen break; 352ff3a3e9bSPekka Paalanen case arg_BP: 353ff3a3e9bSPekka Paalanen rv = ®s->bp; 354ff3a3e9bSPekka Paalanen break; 355ff3a3e9bSPekka Paalanen case arg_SI: 356ff3a3e9bSPekka Paalanen rv = ®s->si; 357ff3a3e9bSPekka Paalanen break; 358ff3a3e9bSPekka Paalanen case arg_DI: 359ff3a3e9bSPekka Paalanen rv = ®s->di; 360ff3a3e9bSPekka Paalanen break; 361ff3a3e9bSPekka Paalanen #ifdef __amd64__ 362ff3a3e9bSPekka Paalanen case arg_R8: 363ff3a3e9bSPekka Paalanen rv = ®s->r8; 364ff3a3e9bSPekka Paalanen break; 365ff3a3e9bSPekka Paalanen case arg_R9: 366ff3a3e9bSPekka Paalanen rv = ®s->r9; 367ff3a3e9bSPekka Paalanen break; 368ff3a3e9bSPekka Paalanen case arg_R10: 369ff3a3e9bSPekka Paalanen rv = ®s->r10; 370ff3a3e9bSPekka Paalanen break; 371ff3a3e9bSPekka Paalanen case arg_R11: 372ff3a3e9bSPekka Paalanen rv = ®s->r11; 373ff3a3e9bSPekka Paalanen break; 374ff3a3e9bSPekka Paalanen case arg_R12: 375ff3a3e9bSPekka Paalanen rv = ®s->r12; 376ff3a3e9bSPekka Paalanen break; 377ff3a3e9bSPekka Paalanen case arg_R13: 378ff3a3e9bSPekka Paalanen rv = ®s->r13; 379ff3a3e9bSPekka Paalanen break; 380ff3a3e9bSPekka Paalanen case arg_R14: 381ff3a3e9bSPekka Paalanen rv = ®s->r14; 382ff3a3e9bSPekka Paalanen break; 383ff3a3e9bSPekka Paalanen case arg_R15: 384ff3a3e9bSPekka Paalanen rv = ®s->r15; 385ff3a3e9bSPekka Paalanen break; 386ff3a3e9bSPekka Paalanen #endif 387ff3a3e9bSPekka Paalanen default: 388ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no); 389ff3a3e9bSPekka Paalanen } 390ff3a3e9bSPekka Paalanen 391ff3a3e9bSPekka Paalanen return rv; 392ff3a3e9bSPekka Paalanen } 393ff3a3e9bSPekka Paalanen 394ff3a3e9bSPekka Paalanen unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs) 395ff3a3e9bSPekka Paalanen { 396ff3a3e9bSPekka Paalanen unsigned int opcode; 397ff3a3e9bSPekka Paalanen int reg; 398ff3a3e9bSPekka Paalanen unsigned char *p; 399611b1597SPekka Paalanen struct prefix_bits prf; 400611b1597SPekka Paalanen int i; 401ff3a3e9bSPekka Paalanen 402ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 403611b1597SPekka Paalanen p += skip_prefix(p, &prf); 404ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 405ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(reg_rop); i++) 4066ec5ff4bSGustavo F. Padovan if (reg_rop[i] == opcode) 407ff3a3e9bSPekka Paalanen goto do_work; 408ff3a3e9bSPekka Paalanen 409ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(reg_wop); i++) 4106ec5ff4bSGustavo F. Padovan if (reg_wop[i] == opcode) 411ff3a3e9bSPekka Paalanen goto do_work; 412ff3a3e9bSPekka Paalanen 413ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Not a register instruction, opcode " 414ff3a3e9bSPekka Paalanen "0x%02x\n", opcode); 415ff3a3e9bSPekka Paalanen goto err; 416ff3a3e9bSPekka Paalanen 417ff3a3e9bSPekka Paalanen do_work: 418cc05152aSMarcin Slusarz /* for STOS, source register is fixed */ 419cc05152aSMarcin Slusarz if (opcode == 0xAA || opcode == 0xAB) { 420cc05152aSMarcin Slusarz reg = arg_AX; 421cc05152aSMarcin Slusarz } else { 422cc05152aSMarcin Slusarz unsigned char mod_rm = *p; 423611b1597SPekka Paalanen reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3); 424cc05152aSMarcin Slusarz } 425ff3a3e9bSPekka Paalanen switch (get_ins_reg_width(ins_addr)) { 426ff3a3e9bSPekka Paalanen case 1: 427611b1597SPekka Paalanen return *get_reg_w8(reg, prf.rex, regs); 428ff3a3e9bSPekka Paalanen 429ff3a3e9bSPekka Paalanen case 2: 430ff3a3e9bSPekka Paalanen return *(unsigned short *)get_reg_w32(reg, regs); 431ff3a3e9bSPekka Paalanen 432ff3a3e9bSPekka Paalanen case 4: 433ff3a3e9bSPekka Paalanen return *(unsigned int *)get_reg_w32(reg, regs); 434ff3a3e9bSPekka Paalanen 435ff3a3e9bSPekka Paalanen #ifdef __amd64__ 436ff3a3e9bSPekka Paalanen case 8: 437ff3a3e9bSPekka Paalanen return *(unsigned long *)get_reg_w32(reg, regs); 438ff3a3e9bSPekka Paalanen #endif 439ff3a3e9bSPekka Paalanen 440ff3a3e9bSPekka Paalanen default: 441ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Error width# %d\n", reg); 442ff3a3e9bSPekka Paalanen } 443ff3a3e9bSPekka Paalanen 444ff3a3e9bSPekka Paalanen err: 445ff3a3e9bSPekka Paalanen return 0; 446ff3a3e9bSPekka Paalanen } 447ff3a3e9bSPekka Paalanen 448ff3a3e9bSPekka Paalanen unsigned long get_ins_imm_val(unsigned long ins_addr) 449ff3a3e9bSPekka Paalanen { 450ff3a3e9bSPekka Paalanen unsigned int opcode; 451ff3a3e9bSPekka Paalanen unsigned char mod_rm; 452ff3a3e9bSPekka Paalanen unsigned char mod; 453ff3a3e9bSPekka Paalanen unsigned char *p; 454611b1597SPekka Paalanen struct prefix_bits prf; 455611b1597SPekka Paalanen int i; 456ff3a3e9bSPekka Paalanen 457ff3a3e9bSPekka Paalanen p = (unsigned char *)ins_addr; 458611b1597SPekka Paalanen p += skip_prefix(p, &prf); 459ff3a3e9bSPekka Paalanen p += get_opcode(p, &opcode); 460ff3a3e9bSPekka Paalanen for (i = 0; i < ARRAY_SIZE(imm_wop); i++) 4616ec5ff4bSGustavo F. Padovan if (imm_wop[i] == opcode) 462ff3a3e9bSPekka Paalanen goto do_work; 463ff3a3e9bSPekka Paalanen 464ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Not an immediate instruction, opcode " 465ff3a3e9bSPekka Paalanen "0x%02x\n", opcode); 466ff3a3e9bSPekka Paalanen goto err; 467ff3a3e9bSPekka Paalanen 468ff3a3e9bSPekka Paalanen do_work: 469ff3a3e9bSPekka Paalanen mod_rm = *p; 470ff3a3e9bSPekka Paalanen mod = mod_rm >> 6; 471ff3a3e9bSPekka Paalanen p++; 472ff3a3e9bSPekka Paalanen switch (mod) { 473ff3a3e9bSPekka Paalanen case 0: 474ff3a3e9bSPekka Paalanen /* if r/m is 5 we have a 32 disp (IA32 Manual 3, Table 2-2) */ 475ff3a3e9bSPekka Paalanen /* AMD64: XXX Check for address size prefix? */ 476ff3a3e9bSPekka Paalanen if ((mod_rm & 0x7) == 0x5) 477ff3a3e9bSPekka Paalanen p += 4; 478ff3a3e9bSPekka Paalanen break; 479ff3a3e9bSPekka Paalanen 480ff3a3e9bSPekka Paalanen case 1: 481ff3a3e9bSPekka Paalanen p += 1; 482ff3a3e9bSPekka Paalanen break; 483ff3a3e9bSPekka Paalanen 484ff3a3e9bSPekka Paalanen case 2: 485ff3a3e9bSPekka Paalanen p += 4; 486ff3a3e9bSPekka Paalanen break; 487ff3a3e9bSPekka Paalanen 488ff3a3e9bSPekka Paalanen case 3: 489ff3a3e9bSPekka Paalanen default: 490ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: not a memory access instruction " 491ff3a3e9bSPekka Paalanen "at 0x%lx, rm_mod=0x%02x\n", 492ff3a3e9bSPekka Paalanen ins_addr, mod_rm); 493ff3a3e9bSPekka Paalanen } 494ff3a3e9bSPekka Paalanen 495ff3a3e9bSPekka Paalanen switch (get_ins_reg_width(ins_addr)) { 496ff3a3e9bSPekka Paalanen case 1: 497ff3a3e9bSPekka Paalanen return *(unsigned char *)p; 498ff3a3e9bSPekka Paalanen 499ff3a3e9bSPekka Paalanen case 2: 500ff3a3e9bSPekka Paalanen return *(unsigned short *)p; 501ff3a3e9bSPekka Paalanen 502ff3a3e9bSPekka Paalanen case 4: 503ff3a3e9bSPekka Paalanen return *(unsigned int *)p; 504ff3a3e9bSPekka Paalanen 505ff3a3e9bSPekka Paalanen #ifdef __amd64__ 506ff3a3e9bSPekka Paalanen case 8: 507ff3a3e9bSPekka Paalanen return *(unsigned long *)p; 508ff3a3e9bSPekka Paalanen #endif 509ff3a3e9bSPekka Paalanen 510ff3a3e9bSPekka Paalanen default: 511ff3a3e9bSPekka Paalanen printk(KERN_ERR "mmiotrace: Error: width.\n"); 512ff3a3e9bSPekka Paalanen } 513ff3a3e9bSPekka Paalanen 514ff3a3e9bSPekka Paalanen err: 515ff3a3e9bSPekka Paalanen return 0; 516ff3a3e9bSPekka Paalanen } 517