instrlen.c

来自「xen 3.2.2 源码」· C语言 代码 · 共 420 行

C
420
字号
/* * instrlen.c - calculates the instruction length for all operating modes *  * Travis Betak, travis.betak@amd.com * Copyright (c) 2005,2006 AMD * Copyright (c) 2005 Keir Fraser * * Essentially a very, very stripped version of Keir Fraser's work in * x86_emulate.c.  Used for MMIO. */#include <xen/config.h>#include <xen/sched.h>#include <xen/mm.h>#include <asm-x86/x86_emulate.h>/* read from guest memory */extern int inst_copy_from_guest(unsigned char *buf, unsigned long eip,        int length);/* * Opcode effective-address decode tables. * Note that we only emulate instructions that have at least one memory * operand (excluding implicit stack references). We assume that stack * references and instruction fetches will never occur in special memory * areas that require emulation. So, for example, 'mov <imm>,<reg>' need * not be handled. *//* Operand sizes: 8-bit operands or specified/overridden size. */#define ByteOp      (1<<0) /* 8-bit operands. *//* Destination operand type. */#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */#define DstReg      (2<<1) /* Register operand. */#define DstMem      (3<<1) /* Memory operand. */#define DstMask     (3<<1)/* Source operand type. */#define SrcNone     (0<<3) /* No source operand. */#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */#define SrcReg      (1<<3) /* Register operand. */#define SrcMem      (2<<3) /* Memory operand. */#define SrcMem16    (3<<3) /* Memory operand (16-bit). */#define SrcMem32    (4<<3) /* Memory operand (32-bit). */#define SrcImm      (5<<3) /* Immediate operand. */#define SrcImmByte  (6<<3) /* 8-bit sign-extended immediate operand. */#define SrcMask     (7<<3)/* Generic ModRM decode. */#define ModRM       (1<<6)/* Destination is only written; never read. */#define Mov         (1<<7)static uint8_t opcode_table[256] = {    /* 0x00 - 0x07 */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, 0,    /* 0x08 - 0x0F */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, 0,    /* 0x10 - 0x17 */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, 0,    /* 0x18 - 0x1F */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, 0,    /* 0x20 - 0x27 */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, 0,    /* 0x28 - 0x2F */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, 0,    /* 0x30 - 0x37 */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, 0,    /* 0x38 - 0x3F */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, 0,    /* 0x40 - 0x4F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x50 - 0x5F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x60 - 0x6F */    0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x70 - 0x7F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x80 - 0x87 */    ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,    ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    /* 0x88 - 0x8F */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,    ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,    0, 0, 0, DstMem|SrcNone|ModRM|Mov,    /* 0x90 - 0x9F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0xA0 - 0xA7 */    ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov,    ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov,    ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,    ByteOp|ImplicitOps, ImplicitOps,    /* 0xA8 - 0xAF */    0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,    ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,    ByteOp|ImplicitOps, ImplicitOps,    /* 0xB0 - 0xBF */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0xC0 - 0xC7 */    ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0,    0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,    /* 0xC8 - 0xCF */    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xD0 - 0xD7 */    ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,     ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,     0, 0, 0, 0,    /* 0xD8 - 0xDF */    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xE0 - 0xEF */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0xF0 - 0xF7 */    0, 0, 0, 0,    0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,    /* 0xF8 - 0xFF */    0, 0, 0, 0,    0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM};static uint8_t twobyte_table[256] = {    /* 0x00 - 0x0F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0,    /* 0x10 - 0x1F */    0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0,    /* 0x20 - 0x2F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x30 - 0x3F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x40 - 0x47 */    DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,    DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,    DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,    DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,    /* 0x48 - 0x4F */    DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,    DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,    DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,    DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,    /* 0x50 - 0x5F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x60 - 0x6F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x70 - 0x7F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x80 - 0x8F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0x90 - 0x9F */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0xA0 - 0xA7 */    0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,     /* 0xA8 - 0xAF */    0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,    /* 0xB0 - 0xB7 */    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM,    0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,    /* 0xB8 - 0xBF */    0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM,    0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,    /* 0xC0 - 0xCF */    0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0xD0 - 0xDF */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0xE0 - 0xEF */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    /* 0xF0 - 0xFF */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};/*  * insn_fetch - fetch the next byte from instruction stream */#define insn_fetch()                                                      \({ uint8_t _x;                                                            \   if ( length >= 15 )                                                    \       return -1;                                                         \   if ( inst_copy_from_guest(&_x, pc, 1) != 1 ) {                         \       unsigned long err;                                                 \       struct segment_register ss;                                        \       gdprintk(XENLOG_WARNING,                                           \                "Cannot read from address %lx (eip %lx, mode %d)\n",      \                pc, org_pc, address_bytes);                               \       err = 0; /* Must be not-present: we don't enforce reserved bits */ \       if ( hvm_nx_enabled(current) )                                     \           err |= PFEC_insn_fetch;                                        \       hvm_get_segment_register(current, x86_seg_ss, &ss);                \       if ( ss.attr.fields.dpl == 3 )                                     \           err |= PFEC_user_mode;                                         \       hvm_inject_exception(TRAP_page_fault, err, pc);                    \       return -1;                                                         \   }                                                                      \   if ( buf )                                                             \       buf[length] = _x;                                                  \   length += 1;                                                           \   pc += 1;                                                               \   _x;                                                                    \})#define insn_skip(_n) do {                      \    int _i;                                     \    for ( _i = 0; _i < (_n); _i++) {            \        (void) insn_fetch();                    \    }                                           \} while (0)/** * hvm_instruction_fetch - read the current instruction and return its length * * @org_pc: guest instruction pointer * @address_bytes: guest address width * @buf: (optional) buffer to load actual instruction bytes into * * Doesn't increment the guest's instruction pointer, but may * issue faults to the guest.  Returns -1 on failure. */int hvm_instruction_fetch(unsigned long org_pc, int address_bytes,                          unsigned char *buf){    uint8_t b, d, twobyte = 0, rex_prefix = 0, modrm_reg = 0;    unsigned int op_default, op_bytes, ad_default, ad_bytes, tmp;    int length = 0;    unsigned long pc = org_pc;    op_bytes = op_default = ad_bytes = ad_default = address_bytes;    if ( op_bytes == 8 )    {        op_bytes = op_default = 4;#ifndef __x86_64__        return -1;#endif    }    /* Legacy prefixes. */    for ( ; ; )    {        switch ( b = insn_fetch() )        {        case 0x66: /* operand-size override */            op_bytes = op_default ^ 6;      /* switch between 2/4 bytes */            break;        case 0x67: /* address-size override */            if ( ad_default == 8 )                ad_bytes = ad_default ^ 12; /* switch between 4/8 bytes */            else                ad_bytes = ad_default ^ 6;  /* switch between 2/4 bytes */            break;        case 0x2e: /* CS override */        case 0x3e: /* DS override */        case 0x26: /* ES override */        case 0x64: /* FS override */        case 0x65: /* GS override */        case 0x36: /* SS override */        case 0xf0: /* LOCK */        case 0xf3: /* REP/REPE/REPZ */        case 0xf2: /* REPNE/REPNZ */            break;#ifdef __x86_64__        case 0x40 ... 0x4f:            if ( ad_default == 8 )            {                rex_prefix = b;                continue;            }            /* FALLTHRU */#endif        default:            goto done_prefixes;        }        rex_prefix = 0;    }done_prefixes:    /* REX prefix. */    if ( rex_prefix & 8 )        op_bytes = 8;                   /* REX.W */    /* REX.B, REX.R, and REX.X do not need to be decoded. */    /* Opcode byte(s). */    d = opcode_table[b];    if ( d == 0 )    {        /* Two-byte opcode? */        if ( b == 0x0f )        {            twobyte = 1;            b = insn_fetch();            d = twobyte_table[b];        }        /* Unrecognised? */        if ( d == 0 )            goto cannot_emulate;    }    /* ModRM and SIB bytes. */    if ( d & ModRM )    {        uint8_t modrm = insn_fetch();        uint8_t modrm_mod = (modrm & 0xc0) >> 6;        uint8_t modrm_rm  = (modrm & 0x07);        modrm_reg = (modrm & 0x38) >> 3;        if ( modrm_mod == 3 )        {            gdprintk(XENLOG_WARNING, "Cannot parse ModRM.mod == 3.\n");            goto cannot_emulate;        }        if ( ad_bytes == 2 )        {            /* 16-bit ModR/M decode. */            switch ( modrm_mod )            {            case 0:                if ( modrm_rm == 6 )                     insn_skip(2); /* skip disp16 */                break;            case 1:                insn_skip(1); /* skip disp8 */                break;            case 2:                insn_skip(2); /* skip disp16 */                break;            }        }        else        {            /* 32/64-bit ModR/M decode. */            switch ( modrm_mod )            {            case 0:                if ( (modrm_rm == 4) &&                      ((insn_fetch() & 7) == 5) )                    insn_skip(4); /* skip disp32 specified by SIB.base */                else if ( modrm_rm == 5 )                    insn_skip(4); /* skip disp32 */                break;            case 1:                if ( modrm_rm == 4 )                    insn_skip(1);                insn_skip(1); /* skip disp8 */                break;            case 2:                if ( modrm_rm == 4 )                    insn_skip(1);                insn_skip(4); /* skip disp32 */                break;            }        }    }    /* Decode and fetch the destination operand: register or memory. */    switch ( d & DstMask )    {    case ImplicitOps:        /* Special instructions do their own operand decoding. */        goto done;    }    /* Decode and fetch the source operand: register, memory or immediate. */    switch ( d & SrcMask )    {    case SrcImm:        tmp = (d & ByteOp) ? 1 : op_bytes;        if ( tmp == 8 ) tmp = 4;        /* NB. Immediates are sign-extended as necessary. */        insn_skip(tmp);        break;    case SrcImmByte:        insn_skip(1);        break;    }    if ( twobyte )        goto done;    switch ( b )    {    case 0xa0 ... 0xa3: /* mov */        insn_skip(ad_bytes); /* skip src/dst displacement */        break;    case 0xf6 ... 0xf7: /* Grp3 */        switch ( modrm_reg )        {        case 0 ... 1: /* test */            /* Special case in Grp3: test has an immediate source operand. */            tmp = (d & ByteOp) ? 1 : op_bytes;            if ( tmp == 8 ) tmp = 4;            insn_skip(tmp);            break;        }        break;    }done:    return length < 16 ? length : -1;cannot_emulate:    gdprintk(XENLOG_WARNING,            "Cannot emulate %02x at address %lx (%lx, addr_bytes %d)\n",            b, pc - 1, org_pc, address_bytes);    return -1;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?