x86_emulate.c

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

C
1,781
字号
    if ( segr.attr.fields.g )        segr.limit = (segr.limit << 12) | 0xfffu;    segr.sel = sel;    return ops->write_segment(seg, &segr, ctxt); raise_exn:    if ( ops->inject_hw_exception == NULL )        return X86EMUL_UNHANDLEABLE;    if ( (rc = ops->inject_hw_exception(fault_type, sel & 0xfffc, ctxt)) )        return rc;    return X86EMUL_EXCEPTION;}static intload_seg(    enum x86_segment seg,    uint16_t sel,    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops *ops){    if ( (ops->read_segment == NULL) ||         (ops->write_segment == NULL) )        return X86EMUL_UNHANDLEABLE;    if ( in_protmode(ctxt, ops) )        return protmode_load_seg(seg, sel, ctxt, ops);    return realmode_load_seg(seg, sel, ctxt, ops);}void *decode_register(    uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs){    void *p;    switch ( modrm_reg )    {    case  0: p = &regs->eax; break;    case  1: p = &regs->ecx; break;    case  2: p = &regs->edx; break;    case  3: p = &regs->ebx; break;    case  4: p = (highbyte_regs ?                  ((unsigned char *)&regs->eax + 1) :                  (unsigned char *)&regs->esp); break;    case  5: p = (highbyte_regs ?                  ((unsigned char *)&regs->ecx + 1) :                  (unsigned char *)&regs->ebp); break;    case  6: p = (highbyte_regs ?                  ((unsigned char *)&regs->edx + 1) :                  (unsigned char *)&regs->esi); break;    case  7: p = (highbyte_regs ?                  ((unsigned char *)&regs->ebx + 1) :                  (unsigned char *)&regs->edi); break;#if defined(__x86_64__)    case  8: p = &regs->r8;  break;    case  9: p = &regs->r9;  break;    case 10: p = &regs->r10; break;    case 11: p = &regs->r11; break;    case 12: p = &regs->r12; break;    case 13: p = &regs->r13; break;    case 14: p = &regs->r14; break;    case 15: p = &regs->r15; break;#endif    default: p = NULL; break;    }    return p;}#define decode_segment_failed x86_seg_trenum x86_segmentdecode_segment(    uint8_t modrm_reg){    switch ( modrm_reg )    {    case 0: return x86_seg_es;    case 1: return x86_seg_cs;    case 2: return x86_seg_ss;    case 3: return x86_seg_ds;    case 4: return x86_seg_fs;    case 5: return x86_seg_gs;    default: break;    }    return decode_segment_failed;}intx86_emulate(    struct x86_emulate_ctxt *ctxt,    struct x86_emulate_ops  *ops){    /* Shadow copy of register state. Committed on successful emulation. */    struct cpu_user_regs _regs = *ctxt->regs;    uint8_t b, d, sib, sib_index, sib_base, twobyte = 0, rex_prefix = 0;    uint8_t modrm = 0, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;    unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes;#define REPE_PREFIX  1#define REPNE_PREFIX 2    unsigned int lock_prefix = 0, rep_prefix = 0;    int override_seg = -1, rc = X86EMUL_OKAY;    struct operand src, dst;    /* Data operand effective address (usually computed from ModRM). */    struct operand ea;    /* Default is a memory operand relative to segment DS. */    ea.type    = OP_MEM;    ea.mem.seg = x86_seg_ds;    ea.mem.off = 0;    ctxt->retire.byte = 0;    op_bytes = def_op_bytes = ad_bytes = def_ad_bytes = ctxt->addr_size/8;    if ( op_bytes == 8 )    {        op_bytes = def_op_bytes = 4;#ifndef __x86_64__        return X86EMUL_UNHANDLEABLE;#endif    }    /* Prefix bytes. */    for ( ; ; )    {        switch ( b = insn_fetch_type(uint8_t) )        {        case 0x66: /* operand-size override */            op_bytes = def_op_bytes ^ 6;            break;        case 0x67: /* address-size override */            ad_bytes = def_ad_bytes ^ (mode_64bit() ? 12 : 6);            break;        case 0x2e: /* CS override */            override_seg = x86_seg_cs;            break;        case 0x3e: /* DS override */            override_seg = x86_seg_ds;            break;        case 0x26: /* ES override */            override_seg = x86_seg_es;            break;        case 0x64: /* FS override */            override_seg = x86_seg_fs;            break;        case 0x65: /* GS override */            override_seg = x86_seg_gs;            break;        case 0x36: /* SS override */            override_seg = x86_seg_ss;            break;        case 0xf0: /* LOCK */            lock_prefix = 1;            break;        case 0xf2: /* REPNE/REPNZ */            rep_prefix = REPNE_PREFIX;            break;        case 0xf3: /* REP/REPE/REPZ */            rep_prefix = REPE_PREFIX;            break;        case 0x40 ... 0x4f: /* REX */            if ( !mode_64bit() )                goto done_prefixes;            rex_prefix = b;            continue;        default:            goto done_prefixes;        }        /* Any legacy prefix after a REX prefix nullifies its effect. */        rex_prefix = 0;    } done_prefixes:    if ( rex_prefix & 8 ) /* REX.W */        op_bytes = 8;    /* Opcode byte(s). */    d = opcode_table[b];    if ( d == 0 )    {        /* Two-byte opcode? */        if ( b == 0x0f )        {            twobyte = 1;            b = insn_fetch_type(uint8_t);            d = twobyte_table[b];        }        /* Unrecognised? */        if ( d == 0 )            goto cannot_emulate;    }    /* Lock prefix is allowed only on RMW instructions. */    generate_exception_if((d & Mov) && lock_prefix, EXC_GP, 0);    /* ModRM and SIB bytes. */    if ( d & ModRM )    {        modrm = insn_fetch_type(uint8_t);        modrm_mod = (modrm & 0xc0) >> 6;        modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3);        modrm_rm  = modrm & 0x07;        if ( modrm_mod == 3 )        {            modrm_rm |= (rex_prefix & 1) << 3;            ea.type = OP_REG;            ea.reg  = decode_register(                modrm_rm, &_regs, (d & ByteOp) && (rex_prefix == 0));        }        else if ( ad_bytes == 2 )        {            /* 16-bit ModR/M decode. */            switch ( modrm_rm )            {            case 0:                ea.mem.off = _regs.ebx + _regs.esi;                break;            case 1:                ea.mem.off = _regs.ebx + _regs.edi;                break;            case 2:                ea.mem.seg = x86_seg_ss;                ea.mem.off = _regs.ebp + _regs.esi;                break;            case 3:                ea.mem.seg = x86_seg_ss;                ea.mem.off = _regs.ebp + _regs.edi;                break;            case 4:                ea.mem.off = _regs.esi;                break;            case 5:                ea.mem.off = _regs.edi;                break;            case 6:                if ( modrm_mod == 0 )                    break;                ea.mem.seg = x86_seg_ss;                ea.mem.off = _regs.ebp;                break;            case 7:                ea.mem.off = _regs.ebx;                break;            }            switch ( modrm_mod )            {            case 0:                if ( modrm_rm == 6 )                    ea.mem.off = insn_fetch_type(int16_t);                break;            case 1:                ea.mem.off += insn_fetch_type(int8_t);                break;            case 2:                ea.mem.off += insn_fetch_type(int16_t);                break;            }            ea.mem.off = truncate_ea(ea.mem.off);        }        else        {            /* 32/64-bit ModR/M decode. */            if ( modrm_rm == 4 )            {                sib = insn_fetch_type(uint8_t);                sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8);                sib_base  = (sib & 7) | ((rex_prefix << 3) & 8);                if ( sib_index != 4 )                    ea.mem.off = *(long*)decode_register(sib_index, &_regs, 0);                ea.mem.off <<= (sib >> 6) & 3;                if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )                    ea.mem.off += insn_fetch_type(int32_t);                else if ( sib_base == 4 )                {                    ea.mem.seg  = x86_seg_ss;                    ea.mem.off += _regs.esp;                    if ( !twobyte && (b == 0x8f) )                        /* POP <rm> computes its EA post increment. */                        ea.mem.off += ((mode_64bit() && (op_bytes == 4))                                       ? 8 : op_bytes);                }                else if ( sib_base == 5 )                {                    ea.mem.seg  = x86_seg_ss;                    ea.mem.off += _regs.ebp;                }                else                    ea.mem.off += *(long*)decode_register(sib_base, &_regs, 0);            }            else            {                modrm_rm |= (rex_prefix & 1) << 3;                ea.mem.off = *(long *)decode_register(modrm_rm, &_regs, 0);                if ( (modrm_rm == 5) && (modrm_mod != 0) )                    ea.mem.seg = x86_seg_ss;            }            switch ( modrm_mod )            {            case 0:                if ( (modrm_rm & 7) != 5 )                    break;                ea.mem.off = insn_fetch_type(int32_t);                if ( !mode_64bit() )                    break;                /* Relative to RIP of next instruction. Argh! */                ea.mem.off += _regs.eip;                if ( (d & SrcMask) == SrcImm )                    ea.mem.off += (d & ByteOp) ? 1 :                        ((op_bytes == 8) ? 4 : op_bytes);                else if ( (d & SrcMask) == SrcImmByte )                    ea.mem.off += 1;                else if ( !twobyte && ((b & 0xfe) == 0xf6) &&                          ((modrm_reg & 7) <= 1) )                    /* Special case in Grp3: test has immediate operand. */                    ea.mem.off += (d & ByteOp) ? 1                        : ((op_bytes == 8) ? 4 : op_bytes);                else if ( twobyte && ((b & 0xf7) == 0xa4) )                    /* SHLD/SHRD with immediate byte third operand. */                    ea.mem.off++;                break;            case 1:                ea.mem.off += insn_fetch_type(int8_t);                break;            case 2:                ea.mem.off += insn_fetch_type(int32_t);                break;            }            ea.mem.off = truncate_ea(ea.mem.off);        }    }    if ( override_seg != -1 )        ea.mem.seg = override_seg;    /* Special instructions do their own operand decoding. */    if ( (d & DstMask) == ImplicitOps )        goto special_insn;    /* Decode and fetch the source operand: register, memory or immediate. */    switch ( d & SrcMask )    {    case SrcNone:        break;    case SrcReg:        src.type = OP_REG;        if ( d & ByteOp )        {            src.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));            src.val = *(uint8_t *)src.reg;            src.bytes = 1;        }        else

⌨️ 快捷键说明

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