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 + -
显示快捷键?