x86_emulate.c

来自「xen 3.2.2 源码」· C语言 代码 · 共 1,803 行 · 第 1/5 页

C
1,803
字号
/* Raw emulation: instruction has two explicit operands. */#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy)\do{ unsigned long _tmp;                                                    \    switch ( (_dst).bytes )                                                \    {                                                                      \    case 2:                                                                \        asm volatile (                                                     \            _PRE_EFLAGS("0","4","2")                                       \            _op"w %"_wx"3,%1; "                                            \            _POST_EFLAGS("0","4","2")                                      \            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \            : _wy ((_src).val), "i" (EFLAGS_MASK),                         \              "m" (_eflags), "m" ((_dst).val) );                           \        break;                                                             \    case 4:                                                                \        asm volatile (                                                     \            _PRE_EFLAGS("0","4","2")                                       \            _op"l %"_lx"3,%1; "                                            \            _POST_EFLAGS("0","4","2")                                      \            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \            : _ly ((_src).val), "i" (EFLAGS_MASK),                         \              "m" (_eflags), "m" ((_dst).val) );                           \        break;                                                             \    case 8:                                                                \        __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy);           \        break;                                                             \    }                                                                      \} while (0)#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy)\do{ unsigned long _tmp;                                                    \    switch ( (_dst).bytes )                                                \    {                                                                      \    case 1:                                                                \        asm volatile (                                                     \            _PRE_EFLAGS("0","4","2")                                       \            _op"b %"_bx"3,%1; "                                            \            _POST_EFLAGS("0","4","2")                                      \            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \            : _by ((_src).val), "i" (EFLAGS_MASK),                         \              "m" (_eflags), "m" ((_dst).val) );                           \        break;                                                             \    default:                                                               \        __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy);\        break;                                                             \    }                                                                      \} while (0)/* Source operand is byte-sized and may be restricted to just %cl. */#define emulate_2op_SrcB(_op, _src, _dst, _eflags)                         \    __emulate_2op(_op, _src, _dst, _eflags,                                \                  "b", "c", "b", "c", "b", "c", "b", "c")/* Source operand is byte, word, long or quad sized. */#define emulate_2op_SrcV(_op, _src, _dst, _eflags)                         \    __emulate_2op(_op, _src, _dst, _eflags,                                \                  "b", "q", "w", "r", _LO32, "r", "", "r")/* Source operand is word, long or quad sized. */#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags)                  \    __emulate_2op_nobyte(_op, _src, _dst, _eflags,                         \                  "w", "r", _LO32, "r", "", "r")/* Instruction has only one explicit operand (no source operand). */#define emulate_1op(_op,_dst,_eflags)                                      \do{ unsigned long _tmp;                                                    \    switch ( (_dst).bytes )                                                \    {                                                                      \    case 1:                                                                \        asm volatile (                                                     \            _PRE_EFLAGS("0","3","2")                                       \            _op"b %1; "                                                    \            _POST_EFLAGS("0","3","2")                                      \            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \            : "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) );        \        break;                                                             \    case 2:                                                                \        asm volatile (                                                     \            _PRE_EFLAGS("0","3","2")                                       \            _op"w %1; "                                                    \            _POST_EFLAGS("0","3","2")                                      \            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \            : "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) );        \        break;                                                             \    case 4:                                                                \        asm volatile (                                                     \            _PRE_EFLAGS("0","3","2")                                       \            _op"l %1; "                                                    \            _POST_EFLAGS("0","3","2")                                      \            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \            : "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) );        \        break;                                                             \    case 8:                                                                \        __emulate_1op_8byte(_op, _dst, _eflags);                           \        break;                                                             \    }                                                                      \} while (0)/* Emulate an instruction with quadword operands (x86/64 only). */#if defined(__x86_64__)#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)         \do{ asm volatile (                                                      \        _PRE_EFLAGS("0","4","2")                                        \        _op"q %"_qx"3,%1; "                                             \        _POST_EFLAGS("0","4","2")                                       \        : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)               \        : _qy ((_src).val), "i" (EFLAGS_MASK),                          \          "m" (_eflags), "m" ((_dst).val) );                            \} while (0)#define __emulate_1op_8byte(_op, _dst, _eflags)                         \do{ asm volatile (                                                      \        _PRE_EFLAGS("0","3","2")                                        \        _op"q %1; "                                                     \        _POST_EFLAGS("0","3","2")                                       \        : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)               \        : "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) );         \} while (0)#elif defined(__i386__)#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)#define __emulate_1op_8byte(_op, _dst, _eflags)#endif /* __i386__ */#ifdef __XEN__#define __emulate_fpu_insn(_op)                 \do{ int _exn;                                   \    asm volatile (                              \        "1: " _op "\n"                          \        "2: \n"                                 \        ".section .fixup,\"ax\"\n"              \        "3: mov $1,%0\n"                        \        "   jmp 2b\n"                           \        ".previous\n"                           \        ".section __ex_table,\"a\"\n"           \        "   "__FIXUP_ALIGN"\n"                  \        "   "__FIXUP_WORD" 1b,3b\n"             \        ".previous"                             \        : "=r" (_exn) : "0" (0) );              \    generate_exception_if(_exn, EXC_MF);        \} while (0)#else#define __emulate_fpu_insn(_op)                 \do{ rc = X86EMUL_UNHANDLEABLE;                  \    goto done;                                  \} while (0)#endif/* Fetch next part of the instruction being emulated. */#define insn_fetch_bytes(_size)                                         \({ unsigned long _x, _eip = _regs.eip;                                  \   if ( !mode_64bit() ) _eip = (uint32_t)_eip; /* ignore upper dword */ \   _regs.eip += (_size); /* real hardware doesn't truncate */           \   generate_exception_if((uint8_t)(_regs.eip - ctxt->regs->eip) > 15,   \                         EXC_GP);                                       \   rc = ops->insn_fetch(x86_seg_cs, _eip, &_x, (_size), ctxt);          \   if ( rc ) goto done;                                                 \   _x;                                                                  \})#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))#define truncate_word(ea, byte_width)           \({  unsigned long __ea = (ea);                  \    unsigned int _width = (byte_width);         \    ((_width == sizeof(unsigned long)) ? __ea : \     (__ea & ((1UL << (_width << 3)) - 1)));    \})#define truncate_ea(ea) truncate_word((ea), ad_bytes)#define mode_64bit() (def_ad_bytes == 8)#define fail_if(p)                                      \do {                                                    \    rc = (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY;     \    if ( rc ) goto done;                                \} while (0)#define generate_exception_if(p, e)                                      \({  if ( (p) ) {                                                         \        fail_if(ops->inject_hw_exception == NULL);                       \        rc = ops->inject_hw_exception(e, 0, ctxt) ? : X86EMUL_EXCEPTION; \        goto done;                                                       \    }                                                                    \})/* * Given byte has even parity (even number of 1s)? SDM Vol. 1 Sec. 3.4.3.1, * "Status Flags": EFLAGS.PF reflects parity of least-sig. byte of result only. */static int even_parity(uint8_t v){    asm ( "test %b0,%b0; setp %b0" : "=a" (v) : "0" (v) );    return v;}/* Update address held in a register, based on addressing mode. */#define _register_address_increment(reg, inc, byte_width)               \do {                                                                    \    int _inc = (inc); /* signed type ensures sign extension to long */  \    unsigned int _width = (byte_width);                                 \    if ( _width == sizeof(unsigned long) )                              \        (reg) += _inc;                                                  \    else if ( mode_64bit() )                                            \        (reg) = ((reg) + _inc) & ((1UL << (_width << 3)) - 1);          \    else                                                                \        (reg) = ((reg) & ~((1UL << (_width << 3)) - 1)) |               \                (((reg) + _inc) & ((1UL << (_width << 3)) - 1));        \} while (0)#define register_address_increment(reg, inc) \    _register_address_increment((reg), (inc), ad_bytes)#define sp_pre_dec(dec) ({                                              \    _register_address_increment(_regs.esp, -(dec), ctxt->sp_size/8);    \    truncate_word(_regs.esp, ctxt->sp_size/8);                          \})#define sp_post_inc(inc) ({                                             \    unsigned long __esp = truncate_word(_regs.esp, ctxt->sp_size/8);    \    _register_address_increment(_regs.esp, (inc), ctxt->sp_size/8);     \    __esp;                                                              \})#define jmp_rel(rel)                                                    \do {                                                                    \    int _rel = (int)(rel);                                              \    _regs.eip += _rel;                                                  \    if ( !mode_64bit() )                                                \        _regs.eip = ((op_bytes == 2)                                    \                     ? (uint16_t)_regs.eip : (uint32_t)_regs.eip);      \} while (0)static unsigned long __get_rep_prefix(    struct cpu_user_regs *int_regs,    struct cpu_user_regs *ext_regs,    int ad_bytes){    unsigned long ecx = ((ad_bytes == 2) ? (uint16_t)int_regs->ecx :                         (ad_bytes == 4) ? (uint32_t)int_regs->ecx :                         int_regs->ecx);    /* Skip the instruction if no repetitions are required. */    if ( ecx == 0 )        ext_regs->eip = int_regs->eip;    return ecx;}#define get_rep_prefix() ({                                             \    unsigned long max_reps = 1;                                         \    if ( rep_prefix )                                                   \        max_reps = __get_rep_prefix(&_regs, ctxt->regs, ad_bytes);      \    if ( max_reps == 0 )                                                \        goto done;                                                      \   max_reps;                                                            \})static void __put_rep_prefix(    struct cpu_user_regs *int_regs,    struct cpu_user_regs *ext_regs,    int ad_bytes,    unsigned long reps_completed){    unsigned long ecx = ((ad_bytes == 2) ? (uint16_t)int_regs->ecx :                         (ad_bytes == 4) ? (uint32_t)int_regs->ecx :                         int_regs->ecx);    /* Reduce counter appropriately, and repeat instruction if non-zero. */    ecx -= reps_completed;    if ( ecx != 0 )        int_regs->eip = ext_regs->eip;    if ( ad_bytes == 2 )        *(uint16_t *)&int_regs->ecx = ecx;    else if ( ad_bytes == 4 )        int_regs->ecx = (uint32_t)ecx;    else        int_regs->ecx = ecx;}#define put_rep_prefix(reps_completed) ({                               \    if ( rep_prefix )                                                   \        __put_rep_prefix(&_regs, ctxt->regs, ad_bytes, reps_completed); \})/* * Unsigned multiplication with double-word result. * IN:  Multiplicand=m[0], Multiplier=m[1] * OUT: Return CF/OF (overflow status); Result=m[1]:m[0] */static int mul_dbl(unsigned long m[2]){    int rc;    asm ( "mul %4; seto %b2"          : "=a" (m[0]), "=d" (m[1]), "=q" (rc)          : "0" (m[0]), "1" (m[1]), "2" (0) );    return rc;}/* * Signed multiplication with double-word result. * IN:  Multiplicand=m[0], Multiplier=m[1] * OUT: Return CF/OF (overflow status); Result=m[1]:m[0] */static int imul_dbl(unsigned long m[2]){    int rc;    asm ( "imul %4; seto %b2"          : "=a" (m[0]), "=d" (m[1]), "=q" (rc)          : "0" (m[0]), "1" (m[1]), "2" (0) );    return rc;}/* * Unsigned division of double-word dividend. * IN:  Dividend=u[1]:u[0], Divisor=v * OUT: Return 1: #DE *      Return 0: Quotient=u[0], Remainder=u[1] */static int div_dbl(unsigned long u[2], unsigned long v){    if ( (v == 0) || (u[1] >= v) )        return 1;    asm ( "div %4"          : "=a" (u[0]), "=d" (u[1])          : "0" (u[0]), "1" (u[1]), "r" (v) );    return 0;}/* * Signed division of double-word dividend. * IN:  Dividend=u[1]:u[0], Divisor=v * OUT: Return 1: #DE *      Return 0: Quotient=u[0], Remainder=u[1] * NB. We don't use idiv directly as it's moderately hard to work out *     ahead of time whether it will #DE, which we cannot allow to happen. */static int idiv_dbl(unsigned long u[2], unsigned long v){    int negu = (long)u[1] < 0, negv = (long)v < 0;    /* u = abs(u) */    if ( negu )    {        u[1] = ~u[1];        if ( (u[0] = -u[0]) == 0 )            u[1]++;    }    /* abs(u) / abs(v) */    if ( div_dbl(u, negv ? -v : v) )        return 1;    /* Remainder has same sign as dividend. It cannot overflow. */    if ( negu )        u[1] = -u[1];    /* Quotient is overflowed if sign bit is set. */    if ( negu ^ negv )    {        if ( (long)u[0] >= 0 )            u[0] = -u[0];        else if ( (u[0] << 1) != 0 ) /* == 0x80...0 is okay */            return 1;    }    else if ( (long)u[0] < 0 )        return 1;

⌨️ 快捷键说明

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