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