x86_emulate.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,781 行 · 第 1/5 页

C
1,781
字号
        {            src.reg = decode_register(modrm_reg, &_regs, 0);            switch ( (src.bytes = op_bytes) )            {            case 2: src.val = *(uint16_t *)src.reg; break;            case 4: src.val = *(uint32_t *)src.reg; break;            case 8: src.val = *(uint64_t *)src.reg; break;            }        }        break;    case SrcMem16:        ea.bytes = 2;        goto srcmem_common;    case SrcMem:        ea.bytes = (d & ByteOp) ? 1 : op_bytes;    srcmem_common:        src = ea;        if ( src.type == OP_REG )        {            switch ( src.bytes )            {            case 1: src.val = *(uint8_t  *)src.reg; break;            case 2: src.val = *(uint16_t *)src.reg; break;            case 4: src.val = *(uint32_t *)src.reg; break;            case 8: src.val = *(uint64_t *)src.reg; break;            }        }        else if ( (rc = read_ulong(src.mem.seg, src.mem.off,                                   &src.val, src.bytes, ctxt, ops)) )            goto done;        break;    case SrcImm:        src.type  = OP_IMM;        src.bytes = (d & ByteOp) ? 1 : op_bytes;        if ( src.bytes == 8 ) src.bytes = 4;        /* NB. Immediates are sign-extended as necessary. */        switch ( src.bytes )        {        case 1: src.val = insn_fetch_type(int8_t);  break;        case 2: src.val = insn_fetch_type(int16_t); break;        case 4: src.val = insn_fetch_type(int32_t); break;        }        break;    case SrcImmByte:        src.type  = OP_IMM;        src.bytes = 1;        src.val   = insn_fetch_type(int8_t);        break;    }    /* Decode and fetch the destination operand: register or memory. */    switch ( d & DstMask )    {    case DstReg:        dst.type = OP_REG;        if ( d & ByteOp )        {            dst.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));            dst.val = *(uint8_t *)dst.reg;            dst.bytes = 1;        }        else        {            dst.reg = decode_register(modrm_reg, &_regs, 0);            switch ( (dst.bytes = op_bytes) )            {            case 2: dst.val = *(uint16_t *)dst.reg; break;            case 4: dst.val = *(uint32_t *)dst.reg; break;            case 8: dst.val = *(uint64_t *)dst.reg; break;            }        }        break;    case DstBitBase:        if ( ((d & SrcMask) == SrcImmByte) || (ea.type == OP_REG) )        {            src.val &= (op_bytes << 3) - 1;        }        else        {            /*             * EA       += BitOffset DIV op_bytes*8             * BitOffset = BitOffset MOD op_bytes*8             * DIV truncates towards negative infinity.             * MOD always produces a positive result.             */            if ( op_bytes == 2 )                src.val = (int16_t)src.val;            else if ( op_bytes == 4 )                src.val = (int32_t)src.val;            if ( (long)src.val < 0 )            {                unsigned long byte_offset;                byte_offset = op_bytes + (((-src.val-1) >> 3) & ~(op_bytes-1));                ea.mem.off -= byte_offset;                src.val = (byte_offset << 3) + src.val;            }            else            {                ea.mem.off += (src.val >> 3) & ~(op_bytes - 1);                src.val &= (op_bytes << 3) - 1;            }        }        /* Becomes a normal DstMem operation from here on. */        d = (d & ~DstMask) | DstMem;    case DstMem:        ea.bytes = (d & ByteOp) ? 1 : op_bytes;        dst = ea;        if ( dst.type == OP_REG )        {            switch ( dst.bytes )            {            case 1: dst.val = *(uint8_t  *)dst.reg; break;            case 2: dst.val = *(uint16_t *)dst.reg; break;            case 4: dst.val = *(uint32_t *)dst.reg; break;            case 8: dst.val = *(uint64_t *)dst.reg; break;            }        }        else if ( !(d & Mov) ) /* optimisation - avoid slow emulated read */        {            if ( (rc = read_ulong(dst.mem.seg, dst.mem.off,                                  &dst.val, dst.bytes, ctxt, ops)) )                goto done;            dst.orig_val = dst.val;        }        break;    }    /* LOCK prefix allowed only on instructions with memory destination. */    generate_exception_if(lock_prefix && (dst.type != OP_MEM), EXC_GP, 0);    if ( twobyte )        goto twobyte_insn;    switch ( b )    {    case 0x04 ... 0x05: /* add imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x00 ... 0x03: add: /* add */        emulate_2op_SrcV("add", src, dst, _regs.eflags);        break;    case 0x0c ... 0x0d: /* or imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x08 ... 0x0b: or:  /* or */        emulate_2op_SrcV("or", src, dst, _regs.eflags);        break;    case 0x14 ... 0x15: /* adc imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x10 ... 0x13: adc: /* adc */        emulate_2op_SrcV("adc", src, dst, _regs.eflags);        break;    case 0x1c ... 0x1d: /* sbb imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x18 ... 0x1b: sbb: /* sbb */        emulate_2op_SrcV("sbb", src, dst, _regs.eflags);        break;    case 0x24 ... 0x25: /* and imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x20 ... 0x23: and: /* and */        emulate_2op_SrcV("and", src, dst, _regs.eflags);        break;    case 0x2c ... 0x2d: /* sub imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x28 ... 0x2b: sub: /* sub */        emulate_2op_SrcV("sub", src, dst, _regs.eflags);        break;    case 0x34 ... 0x35: /* xor imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x30 ... 0x33: xor: /* xor */        emulate_2op_SrcV("xor", src, dst, _regs.eflags);        break;    case 0x3c ... 0x3d: /* cmp imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x38 ... 0x3b: cmp: /* cmp */        emulate_2op_SrcV("cmp", src, dst, _regs.eflags);        dst.type = OP_NONE;        break;    case 0x62: /* bound */ {        unsigned long src_val2;        int lb, ub, idx;        generate_exception_if(mode_64bit() || (src.type != OP_MEM),                              EXC_UD, -1);        if ( (rc = read_ulong(src.mem.seg, src.mem.off + op_bytes,                              &src_val2, op_bytes, ctxt, ops)) )            goto done;        ub  = (op_bytes == 2) ? (int16_t)src_val2 : (int32_t)src_val2;        lb  = (op_bytes == 2) ? (int16_t)src.val  : (int32_t)src.val;        idx = (op_bytes == 2) ? (int16_t)dst.val  : (int32_t)dst.val;        generate_exception_if((idx < lb) || (idx > ub), EXC_BR, -1);        dst.type = OP_NONE;        break;    }    case 0x63: /* movsxd (x86/64) / arpl (x86/32) */        if ( mode_64bit() )        {            /* movsxd */            if ( src.type == OP_REG )                src.val = *(int32_t *)src.reg;            else if ( (rc = read_ulong(src.mem.seg, src.mem.off,                                       &src.val, 4, ctxt, ops)) )                goto done;            dst.val = (int32_t)src.val;        }        else        {            /* arpl */            uint16_t src_val = dst.val;            dst = src;            _regs.eflags &= ~EFLG_ZF;            _regs.eflags |= ((src_val & 3) > (dst.val & 3)) ? EFLG_ZF : 0;            if ( _regs.eflags & EFLG_ZF )                dst.val  = (dst.val & ~3) | (src_val & 3);            else                dst.type = OP_NONE;            generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);        }        break;    case 0x69: /* imul imm16/32 */    case 0x6b: /* imul imm8 */ {        unsigned long src1; /* ModR/M source operand */        if ( ea.type == OP_REG )            src1 = *ea.reg;        else if ( (rc = read_ulong(ea.mem.seg, ea.mem.off,                                   &src1, op_bytes, ctxt, ops)) )            goto done;        _regs.eflags &= ~(EFLG_OF|EFLG_CF);        switch ( dst.bytes )        {        case 2:            dst.val = ((uint32_t)(int16_t)src.val *                       (uint32_t)(int16_t)src1);            if ( (int16_t)dst.val != (uint32_t)dst.val )                _regs.eflags |= EFLG_OF|EFLG_CF;            break;#ifdef __x86_64__        case 4:            dst.val = ((uint64_t)(int32_t)src.val *                       (uint64_t)(int32_t)src1);            if ( (int32_t)dst.val != dst.val )                _regs.eflags |= EFLG_OF|EFLG_CF;            break;#endif        default: {            unsigned long m[2] = { src.val, src1 };            if ( imul_dbl(m) )                _regs.eflags |= EFLG_OF|EFLG_CF;            dst.val = m[0];            break;        }        }        break;    }    case 0x82: /* Grp1 (x86/32 only) */        generate_exception_if(mode_64bit(), EXC_UD, -1);    case 0x80: case 0x81: case 0x83: /* Grp1 */        switch ( modrm_reg & 7 )        {        case 0: goto add;        case 1: goto or;        case 2: goto adc;        case 3: goto sbb;        case 4: goto and;        case 5: goto sub;        case 6: goto xor;        case 7: goto cmp;        }        break;    case 0xa8 ... 0xa9: /* test imm,%%eax */        dst.reg = (unsigned long *)&_regs.eax;        dst.val = _regs.eax;    case 0x84 ... 0x85: test: /* test */        emulate_2op_SrcV("test", src, dst, _regs.eflags);        dst.type = OP_NONE;        break;    case 0x86 ... 0x87: xchg: /* xchg */        /* Write back the register source. */        switch ( dst.bytes )        {        case 1: *(uint8_t  *)src.reg = (uint8_t)dst.val; break;        case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break;        case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */        case 8: *src.reg = dst.val; break;        }        /* Write back the memory destination with implicit LOCK prefix. */        dst.val = src.val;        lock_prefix = 1;        break;    case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */        generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1);    case 0x88 ... 0x8b: /* mov */        dst.val = src.val;        break;    case 0x8c: /* mov Sreg,r/m */ {        struct segment_register reg;        enum x86_segment seg = decode_segment(modrm_reg);        generate_exception_if(seg == decode_segment_failed, EXC_UD, -1);        fail_if(ops->read_segment == NULL);        if ( (rc = ops->read_segment(seg, &reg, ctxt)) != 0 )            goto done;        dst.val = reg.sel;        if ( dst.type == OP_MEM )            dst.bytes = 2;        break;    }    case 0x8e: /* mov r/m,Sreg */ {        enum x86_segment seg = decode_segment(modrm_reg);        generate_exception_if(seg == decode_segment_failed, EXC_UD, -1);        if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 )            goto done;        if ( seg == x86_seg_ss )            ctxt->retire.flags.mov_ss = 1;        dst.type = OP_NONE;        break;    }    case 0x8d: /* lea */        dst.val = ea.mem.off;        break;    case 0x8f: /* pop (sole member of Grp1a) */        generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1);        /* 64-bit mode: POP defaults to a 64-bit operand. */        if ( mode_64bit() && (dst.bytes == 4) )            dst.bytes = 8;        if ( (rc = read_ulong(x86_seg_ss, sp_post_inc(dst.bytes),                              &dst.val, dst.bytes, ctxt, ops)) != 0 )            goto done;        break;    case 

⌨️ 快捷键说明

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