Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Fault Injection Test harness (FI)
0004  *  Copyright (C) Intel Crop.
0005  */
0006 
0007 /*  Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp
0008  *  Copyright by Intel Crop., 2002
0009  *  Louis Zhuang (louis.zhuang@intel.com)
0010  *
0011  *  Bjorn Steinbrink (B.Steinbrink@gmx.de), 2007
0012  */
0013 
0014 #include <linux/ptrace.h> /* struct pt_regs */
0015 #include "pf_in.h"
0016 
0017 #ifdef __i386__
0018 /* IA32 Manual 3, 2-1 */
0019 static unsigned char prefix_codes[] = {
0020     0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64,
0021     0x65, 0x66, 0x67
0022 };
0023 /* IA32 Manual 3, 3-432*/
0024 static unsigned int reg_rop[] = {
0025     0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
0026 };
0027 static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
0028 static unsigned int imm_wop[] = { 0xC6, 0xC7 };
0029 /* IA32 Manual 3, 3-432*/
0030 static unsigned int rw8[] = { 0x88, 0x8A, 0xC6, 0xAA };
0031 static unsigned int rw32[] = {
0032     0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
0033 };
0034 static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F, 0xAA };
0035 static unsigned int mw16[] = { 0xB70F, 0xBF0F };
0036 static unsigned int mw32[] = { 0x89, 0x8B, 0xC7, 0xAB };
0037 static unsigned int mw64[] = {};
0038 #else /* not __i386__ */
0039 static unsigned char prefix_codes[] = {
0040     0x66, 0x67, 0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36,
0041     0xF0, 0xF3, 0xF2,
0042     /* REX Prefixes */
0043     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0044     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
0045 };
0046 /* AMD64 Manual 3, Appendix A*/
0047 static unsigned int reg_rop[] = {
0048     0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
0049 };
0050 static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
0051 static unsigned int imm_wop[] = { 0xC6, 0xC7 };
0052 static unsigned int rw8[] = { 0xC6, 0x88, 0x8A, 0xAA };
0053 static unsigned int rw32[] = {
0054     0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
0055 };
0056 /* 8 bit only */
0057 static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F, 0xAA };
0058 /* 16 bit only */
0059 static unsigned int mw16[] = { 0xB70F, 0xBF0F };
0060 /* 16 or 32 bit */
0061 static unsigned int mw32[] = { 0xC7 };
0062 /* 16, 32 or 64 bit */
0063 static unsigned int mw64[] = { 0x89, 0x8B, 0xAB };
0064 #endif /* not __i386__ */
0065 
0066 struct prefix_bits {
0067     unsigned shorted:1;
0068     unsigned enlarged:1;
0069     unsigned rexr:1;
0070     unsigned rex:1;
0071 };
0072 
0073 static int skip_prefix(unsigned char *addr, struct prefix_bits *prf)
0074 {
0075     int i;
0076     unsigned char *p = addr;
0077     prf->shorted = 0;
0078     prf->enlarged = 0;
0079     prf->rexr = 0;
0080     prf->rex = 0;
0081 
0082 restart:
0083     for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) {
0084         if (*p == prefix_codes[i]) {
0085             if (*p == 0x66)
0086                 prf->shorted = 1;
0087 #ifdef __amd64__
0088             if ((*p & 0xf8) == 0x48)
0089                 prf->enlarged = 1;
0090             if ((*p & 0xf4) == 0x44)
0091                 prf->rexr = 1;
0092             if ((*p & 0xf0) == 0x40)
0093                 prf->rex = 1;
0094 #endif
0095             p++;
0096             goto restart;
0097         }
0098     }
0099 
0100     return (p - addr);
0101 }
0102 
0103 static int get_opcode(unsigned char *addr, unsigned int *opcode)
0104 {
0105     int len;
0106 
0107     if (*addr == 0x0F) {
0108         /* 0x0F is extension instruction */
0109         *opcode = *(unsigned short *)addr;
0110         len = 2;
0111     } else {
0112         *opcode = *addr;
0113         len = 1;
0114     }
0115 
0116     return len;
0117 }
0118 
0119 #define CHECK_OP_TYPE(opcode, array, type) \
0120     for (i = 0; i < ARRAY_SIZE(array); i++) { \
0121         if (array[i] == opcode) { \
0122             rv = type; \
0123             goto exit; \
0124         } \
0125     }
0126 
0127 enum reason_type get_ins_type(unsigned long ins_addr)
0128 {
0129     unsigned int opcode;
0130     unsigned char *p;
0131     struct prefix_bits prf;
0132     int i;
0133     enum reason_type rv = OTHERS;
0134 
0135     p = (unsigned char *)ins_addr;
0136     p += skip_prefix(p, &prf);
0137     p += get_opcode(p, &opcode);
0138 
0139     CHECK_OP_TYPE(opcode, reg_rop, REG_READ);
0140     CHECK_OP_TYPE(opcode, reg_wop, REG_WRITE);
0141     CHECK_OP_TYPE(opcode, imm_wop, IMM_WRITE);
0142 
0143 exit:
0144     return rv;
0145 }
0146 #undef CHECK_OP_TYPE
0147 
0148 static unsigned int get_ins_reg_width(unsigned long ins_addr)
0149 {
0150     unsigned int opcode;
0151     unsigned char *p;
0152     struct prefix_bits prf;
0153     int i;
0154 
0155     p = (unsigned char *)ins_addr;
0156     p += skip_prefix(p, &prf);
0157     p += get_opcode(p, &opcode);
0158 
0159     for (i = 0; i < ARRAY_SIZE(rw8); i++)
0160         if (rw8[i] == opcode)
0161             return 1;
0162 
0163     for (i = 0; i < ARRAY_SIZE(rw32); i++)
0164         if (rw32[i] == opcode)
0165             return prf.shorted ? 2 : (prf.enlarged ? 8 : 4);
0166 
0167     printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
0168     return 0;
0169 }
0170 
0171 unsigned int get_ins_mem_width(unsigned long ins_addr)
0172 {
0173     unsigned int opcode;
0174     unsigned char *p;
0175     struct prefix_bits prf;
0176     int i;
0177 
0178     p = (unsigned char *)ins_addr;
0179     p += skip_prefix(p, &prf);
0180     p += get_opcode(p, &opcode);
0181 
0182     for (i = 0; i < ARRAY_SIZE(mw8); i++)
0183         if (mw8[i] == opcode)
0184             return 1;
0185 
0186     for (i = 0; i < ARRAY_SIZE(mw16); i++)
0187         if (mw16[i] == opcode)
0188             return 2;
0189 
0190     for (i = 0; i < ARRAY_SIZE(mw32); i++)
0191         if (mw32[i] == opcode)
0192             return prf.shorted ? 2 : 4;
0193 
0194     for (i = 0; i < ARRAY_SIZE(mw64); i++)
0195         if (mw64[i] == opcode)
0196             return prf.shorted ? 2 : (prf.enlarged ? 8 : 4);
0197 
0198     printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
0199     return 0;
0200 }
0201 
0202 /*
0203  * Define register ident in mod/rm byte.
0204  * Note: these are NOT the same as in ptrace-abi.h.
0205  */
0206 enum {
0207     arg_AL = 0,
0208     arg_CL = 1,
0209     arg_DL = 2,
0210     arg_BL = 3,
0211     arg_AH = 4,
0212     arg_CH = 5,
0213     arg_DH = 6,
0214     arg_BH = 7,
0215 
0216     arg_AX = 0,
0217     arg_CX = 1,
0218     arg_DX = 2,
0219     arg_BX = 3,
0220     arg_SP = 4,
0221     arg_BP = 5,
0222     arg_SI = 6,
0223     arg_DI = 7,
0224 #ifdef __amd64__
0225     arg_R8  = 8,
0226     arg_R9  = 9,
0227     arg_R10 = 10,
0228     arg_R11 = 11,
0229     arg_R12 = 12,
0230     arg_R13 = 13,
0231     arg_R14 = 14,
0232     arg_R15 = 15
0233 #endif
0234 };
0235 
0236 static unsigned char *get_reg_w8(int no, int rex, struct pt_regs *regs)
0237 {
0238     unsigned char *rv = NULL;
0239 
0240     switch (no) {
0241     case arg_AL:
0242         rv = (unsigned char *)&regs->ax;
0243         break;
0244     case arg_BL:
0245         rv = (unsigned char *)&regs->bx;
0246         break;
0247     case arg_CL:
0248         rv = (unsigned char *)&regs->cx;
0249         break;
0250     case arg_DL:
0251         rv = (unsigned char *)&regs->dx;
0252         break;
0253 #ifdef __amd64__
0254     case arg_R8:
0255         rv = (unsigned char *)&regs->r8;
0256         break;
0257     case arg_R9:
0258         rv = (unsigned char *)&regs->r9;
0259         break;
0260     case arg_R10:
0261         rv = (unsigned char *)&regs->r10;
0262         break;
0263     case arg_R11:
0264         rv = (unsigned char *)&regs->r11;
0265         break;
0266     case arg_R12:
0267         rv = (unsigned char *)&regs->r12;
0268         break;
0269     case arg_R13:
0270         rv = (unsigned char *)&regs->r13;
0271         break;
0272     case arg_R14:
0273         rv = (unsigned char *)&regs->r14;
0274         break;
0275     case arg_R15:
0276         rv = (unsigned char *)&regs->r15;
0277         break;
0278 #endif
0279     default:
0280         break;
0281     }
0282 
0283     if (rv)
0284         return rv;
0285 
0286     if (rex) {
0287         /*
0288          * If REX prefix exists, access low bytes of SI etc.
0289          * instead of AH etc.
0290          */
0291         switch (no) {
0292         case arg_SI:
0293             rv = (unsigned char *)&regs->si;
0294             break;
0295         case arg_DI:
0296             rv = (unsigned char *)&regs->di;
0297             break;
0298         case arg_BP:
0299             rv = (unsigned char *)&regs->bp;
0300             break;
0301         case arg_SP:
0302             rv = (unsigned char *)&regs->sp;
0303             break;
0304         default:
0305             break;
0306         }
0307     } else {
0308         switch (no) {
0309         case arg_AH:
0310             rv = 1 + (unsigned char *)&regs->ax;
0311             break;
0312         case arg_BH:
0313             rv = 1 + (unsigned char *)&regs->bx;
0314             break;
0315         case arg_CH:
0316             rv = 1 + (unsigned char *)&regs->cx;
0317             break;
0318         case arg_DH:
0319             rv = 1 + (unsigned char *)&regs->dx;
0320             break;
0321         default:
0322             break;
0323         }
0324     }
0325 
0326     if (!rv)
0327         printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
0328 
0329     return rv;
0330 }
0331 
0332 static unsigned long *get_reg_w32(int no, struct pt_regs *regs)
0333 {
0334     unsigned long *rv = NULL;
0335 
0336     switch (no) {
0337     case arg_AX:
0338         rv = &regs->ax;
0339         break;
0340     case arg_BX:
0341         rv = &regs->bx;
0342         break;
0343     case arg_CX:
0344         rv = &regs->cx;
0345         break;
0346     case arg_DX:
0347         rv = &regs->dx;
0348         break;
0349     case arg_SP:
0350         rv = &regs->sp;
0351         break;
0352     case arg_BP:
0353         rv = &regs->bp;
0354         break;
0355     case arg_SI:
0356         rv = &regs->si;
0357         break;
0358     case arg_DI:
0359         rv = &regs->di;
0360         break;
0361 #ifdef __amd64__
0362     case arg_R8:
0363         rv = &regs->r8;
0364         break;
0365     case arg_R9:
0366         rv = &regs->r9;
0367         break;
0368     case arg_R10:
0369         rv = &regs->r10;
0370         break;
0371     case arg_R11:
0372         rv = &regs->r11;
0373         break;
0374     case arg_R12:
0375         rv = &regs->r12;
0376         break;
0377     case arg_R13:
0378         rv = &regs->r13;
0379         break;
0380     case arg_R14:
0381         rv = &regs->r14;
0382         break;
0383     case arg_R15:
0384         rv = &regs->r15;
0385         break;
0386 #endif
0387     default:
0388         printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
0389     }
0390 
0391     return rv;
0392 }
0393 
0394 unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs)
0395 {
0396     unsigned int opcode;
0397     int reg;
0398     unsigned char *p;
0399     struct prefix_bits prf;
0400     int i;
0401 
0402     p = (unsigned char *)ins_addr;
0403     p += skip_prefix(p, &prf);
0404     p += get_opcode(p, &opcode);
0405     for (i = 0; i < ARRAY_SIZE(reg_rop); i++)
0406         if (reg_rop[i] == opcode)
0407             goto do_work;
0408 
0409     for (i = 0; i < ARRAY_SIZE(reg_wop); i++)
0410         if (reg_wop[i] == opcode)
0411             goto do_work;
0412 
0413     printk(KERN_ERR "mmiotrace: Not a register instruction, opcode "
0414                             "0x%02x\n", opcode);
0415     goto err;
0416 
0417 do_work:
0418     /* for STOS, source register is fixed */
0419     if (opcode == 0xAA || opcode == 0xAB) {
0420         reg = arg_AX;
0421     } else {
0422         unsigned char mod_rm = *p;
0423         reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3);
0424     }
0425     switch (get_ins_reg_width(ins_addr)) {
0426     case 1:
0427         return *get_reg_w8(reg, prf.rex, regs);
0428 
0429     case 2:
0430         return *(unsigned short *)get_reg_w32(reg, regs);
0431 
0432     case 4:
0433         return *(unsigned int *)get_reg_w32(reg, regs);
0434 
0435 #ifdef __amd64__
0436     case 8:
0437         return *(unsigned long *)get_reg_w32(reg, regs);
0438 #endif
0439 
0440     default:
0441         printk(KERN_ERR "mmiotrace: Error width# %d\n", reg);
0442     }
0443 
0444 err:
0445     return 0;
0446 }
0447 
0448 unsigned long get_ins_imm_val(unsigned long ins_addr)
0449 {
0450     unsigned int opcode;
0451     unsigned char mod_rm;
0452     unsigned char mod;
0453     unsigned char *p;
0454     struct prefix_bits prf;
0455     int i;
0456 
0457     p = (unsigned char *)ins_addr;
0458     p += skip_prefix(p, &prf);
0459     p += get_opcode(p, &opcode);
0460     for (i = 0; i < ARRAY_SIZE(imm_wop); i++)
0461         if (imm_wop[i] == opcode)
0462             goto do_work;
0463 
0464     printk(KERN_ERR "mmiotrace: Not an immediate instruction, opcode "
0465                             "0x%02x\n", opcode);
0466     goto err;
0467 
0468 do_work:
0469     mod_rm = *p;
0470     mod = mod_rm >> 6;
0471     p++;
0472     switch (mod) {
0473     case 0:
0474         /* if r/m is 5 we have a 32 disp (IA32 Manual 3, Table 2-2)  */
0475         /* AMD64: XXX Check for address size prefix? */
0476         if ((mod_rm & 0x7) == 0x5)
0477             p += 4;
0478         break;
0479 
0480     case 1:
0481         p += 1;
0482         break;
0483 
0484     case 2:
0485         p += 4;
0486         break;
0487 
0488     case 3:
0489     default:
0490         printk(KERN_ERR "mmiotrace: not a memory access instruction "
0491                         "at 0x%lx, rm_mod=0x%02x\n",
0492                         ins_addr, mod_rm);
0493     }
0494 
0495     switch (get_ins_reg_width(ins_addr)) {
0496     case 1:
0497         return *(unsigned char *)p;
0498 
0499     case 2:
0500         return *(unsigned short *)p;
0501 
0502     case 4:
0503         return *(unsigned int *)p;
0504 
0505 #ifdef __amd64__
0506     case 8:
0507         return *(unsigned long *)p;
0508 #endif
0509 
0510     default:
0511         printk(KERN_ERR "mmiotrace: Error: width.\n");
0512     }
0513 
0514 err:
0515     return 0;
0516 }