x86_emulate.c
来自「linux 内核源代码」· C语言 代码 · 共 1,663 行 · 第 1/3 页
C
1,663 行
break; } goto test; case 2: /* not */ dst.val = ~dst.val; break; case 3: /* neg */ emulate_1op("neg", dst, _eflags); break; default: goto cannot_emulate; } break; case 0xfe ... 0xff: /* Grp4/Grp5 */ switch (modrm_reg) { case 0: /* inc */ emulate_1op("inc", dst, _eflags); break; case 1: /* dec */ emulate_1op("dec", dst, _eflags); break; case 4: /* jmp abs */ if (b == 0xff) _eip = dst.val; else goto cannot_emulate; break; case 6: /* push */ /* 64-bit mode: PUSH always pushes a 64-bit operand. */ if (mode == X86EMUL_MODE_PROT64) { dst.bytes = 8; if ((rc = ops->read_std((unsigned long)dst.ptr, &dst.val, 8, ctxt->vcpu)) != 0) goto done; } register_address_increment(_regs[VCPU_REGS_RSP], -dst.bytes); if ((rc = ops->write_emulated( register_address(ctxt->ss_base, _regs[VCPU_REGS_RSP]), &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; no_wb = 1; break; default: goto cannot_emulate; } break; }writeback: if (!no_wb) { switch (dst.type) { case OP_REG: /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ switch (dst.bytes) { case 1: *(u8 *)dst.ptr = (u8)dst.val; break; case 2: *(u16 *)dst.ptr = (u16)dst.val; break; case 4: *dst.ptr = (u32)dst.val; break; /* 64b: zero-ext */ case 8: *dst.ptr = dst.val; break; } break; case OP_MEM: if (lock_prefix) rc = ops->cmpxchg_emulated((unsigned long)dst. ptr, &dst.orig_val, &dst.val, dst.bytes, ctxt->vcpu); else rc = ops->write_emulated((unsigned long)dst.ptr, &dst.val, dst.bytes, ctxt->vcpu); if (rc != 0) goto done; default: break; } } /* Commit shadow register state. */ memcpy(ctxt->vcpu->regs, _regs, sizeof _regs); ctxt->eflags = _eflags; ctxt->vcpu->rip = _eip;done: return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;special_insn: if (twobyte) goto twobyte_special_insn; switch(b) { case 0x50 ... 0x57: /* push reg */ if (op_bytes == 2) src.val = (u16) _regs[b & 0x7]; else src.val = (u32) _regs[b & 0x7]; dst.type = OP_MEM; dst.bytes = op_bytes; dst.val = src.val; register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); dst.ptr = (void *) register_address( ctxt->ss_base, _regs[VCPU_REGS_RSP]); break; case 0x58 ... 0x5f: /* pop reg */ dst.ptr = (unsigned long *)&_regs[b & 0x7]; pop_instruction: if ((rc = ops->read_std(register_address(ctxt->ss_base, _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); no_wb = 1; /* Disable writeback. */ break; case 0x6a: /* push imm8 */ src.val = 0L; src.val = insn_fetch(s8, 1, _eip); push: dst.type = OP_MEM; dst.bytes = op_bytes; dst.val = src.val; register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); dst.ptr = (void *) register_address(ctxt->ss_base, _regs[VCPU_REGS_RSP]); break; case 0x6c: /* insb */ case 0x6d: /* insw/insd */ if (kvm_emulate_pio_string(ctxt->vcpu, NULL, 1, /* in */ (d & ByteOp) ? 1 : op_bytes, /* size */ rep_prefix ? address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ (_eflags & EFLG_DF), /* down */ register_address(ctxt->es_base, _regs[VCPU_REGS_RDI]), /* address */ rep_prefix, _regs[VCPU_REGS_RDX] /* port */ ) == 0) return -1; return 0; case 0x6e: /* outsb */ case 0x6f: /* outsw/outsd */ if (kvm_emulate_pio_string(ctxt->vcpu, NULL, 0, /* in */ (d & ByteOp) ? 1 : op_bytes, /* size */ rep_prefix ? address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ (_eflags & EFLG_DF), /* down */ register_address(override_base ? *override_base : ctxt->ds_base, _regs[VCPU_REGS_RSI]), /* address */ rep_prefix, _regs[VCPU_REGS_RDX] /* port */ ) == 0) return -1; return 0; case 0x70 ... 0x7f: /* jcc (short) */ { int rel = insn_fetch(s8, 1, _eip); if (test_cc(b, _eflags)) JMP_REL(rel); break; } case 0x9c: /* pushf */ src.val = (unsigned long) _eflags; goto push; case 0x9d: /* popf */ dst.ptr = (unsigned long *) &_eflags; goto pop_instruction; case 0xc3: /* ret */ dst.ptr = &_eip; goto pop_instruction; case 0xf4: /* hlt */ ctxt->vcpu->halt_request = 1; goto done; } if (rep_prefix) { if (_regs[VCPU_REGS_RCX] == 0) { ctxt->vcpu->rip = _eip; goto done; } _regs[VCPU_REGS_RCX]--; _eip = ctxt->vcpu->rip; } switch (b) { case 0xa4 ... 0xa5: /* movs */ dst.type = OP_MEM; dst.bytes = (d & ByteOp) ? 1 : op_bytes; dst.ptr = (unsigned long *)register_address(ctxt->es_base, _regs[VCPU_REGS_RDI]); if ((rc = ops->read_emulated(register_address( override_base ? *override_base : ctxt->ds_base, _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSI], (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); register_address_increment(_regs[VCPU_REGS_RDI], (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); break; case 0xa6 ... 0xa7: /* cmps */ DPRINTF("Urk! I don't handle CMPS.\n"); goto cannot_emulate; case 0xaa ... 0xab: /* stos */ dst.type = OP_MEM; dst.bytes = (d & ByteOp) ? 1 : op_bytes; dst.ptr = (unsigned long *)cr2; dst.val = _regs[VCPU_REGS_RAX]; register_address_increment(_regs[VCPU_REGS_RDI], (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); break; case 0xac ... 0xad: /* lods */ dst.type = OP_REG; dst.bytes = (d & ByteOp) ? 1 : op_bytes; dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt->vcpu)) != 0) goto done; register_address_increment(_regs[VCPU_REGS_RSI], (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); break; case 0xae ... 0xaf: /* scas */ DPRINTF("Urk! I don't handle SCAS.\n"); goto cannot_emulate; case 0xe8: /* call (near) */ { long int rel; switch (op_bytes) { case 2: rel = insn_fetch(s16, 2, _eip); break; case 4: rel = insn_fetch(s32, 4, _eip); break; case 8: rel = insn_fetch(s64, 8, _eip); break; default: DPRINTF("Call: Invalid op_bytes\n"); goto cannot_emulate; } src.val = (unsigned long) _eip; JMP_REL(rel); op_bytes = ad_bytes; goto push; } case 0xe9: /* jmp rel */ case 0xeb: /* jmp rel short */ JMP_REL(src.val); no_wb = 1; /* Disable writeback. */ break; } goto writeback;twobyte_insn: switch (b) { case 0x01: /* lgdt, lidt, lmsw */ /* Disable writeback. */ no_wb = 1; switch (modrm_reg) { u16 size; unsigned long address; case 2: /* lgdt */ rc = read_descriptor(ctxt, ops, src.ptr, &size, &address, op_bytes); if (rc) goto done; realmode_lgdt(ctxt->vcpu, size, address); break; case 3: /* lidt */ rc = read_descriptor(ctxt, ops, src.ptr, &size, &address, op_bytes); if (rc) goto done; realmode_lidt(ctxt->vcpu, size, address); break; case 4: /* smsw */ if (modrm_mod != 3) goto cannot_emulate; *(u16 *)&_regs[modrm_rm] = realmode_get_cr(ctxt->vcpu, 0); break; case 6: /* lmsw */ if (modrm_mod != 3) goto cannot_emulate; realmode_lmsw(ctxt->vcpu, (u16)modrm_val, &_eflags); break; case 7: /* invlpg*/ emulate_invlpg(ctxt->vcpu, cr2); break; default: goto cannot_emulate; } break; case 0x21: /* mov from dr to reg */ no_wb = 1; if (modrm_mod != 3) goto cannot_emulate; rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]); break; case 0x23: /* mov from reg to dr */ no_wb = 1; if (modrm_mod != 3) goto cannot_emulate; rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]); break; case 0x40 ... 0x4f: /* cmov */ dst.val = dst.orig_val = src.val; no_wb = 1; /* * First, assume we're decoding an even cmov opcode * (lsb == 0). */ switch ((b & 15) >> 1) { case 0: /* cmovo */ no_wb = (_eflags & EFLG_OF) ? 0 : 1; break; case 1: /* cmovb/cmovc/cmovnae */ no_wb = (_eflags & EFLG_CF) ? 0 : 1; break; case 2: /* cmovz/cmove */ no_wb = (_eflags & EFLG_ZF) ? 0 : 1; break; case 3: /* cmovbe/cmovna */ no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1; break; case 4: /* cmovs */ no_wb = (_eflags & EFLG_SF) ? 0 : 1; break; case 5: /* cmovp/cmovpe */ no_wb = (_eflags & EFLG_PF) ? 0 : 1; break; case 7: /* cmovle/cmovng */ no_wb = (_eflags & EFLG_ZF) ? 0 : 1; /* fall through */ case 6: /* cmovl/cmovnge */ no_wb &= (!(_eflags & EFLG_SF) != !(_eflags & EFLG_OF)) ? 0 : 1; break; } /* Odd cmov opcodes (lsb == 1) have inverted sense. */ no_wb ^= b & 1; break; case 0xa3: bt: /* bt */ src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("bt", src, dst, _eflags); break; case 0xab: bts: /* bts */ src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("bts", src, dst, _eflags); break; case 0xb0 ... 0xb1: /* cmpxchg */ /* * Save real source value, then compare EAX against * destination. */ src.orig_val = src.val; src.val = _regs[VCPU_REGS_RAX]; emulate_2op_SrcV("cmp", src, dst, _eflags); if (_eflags & EFLG_ZF) { /* Success: write back to memory. */ dst.val = src.orig_val; } else { /* Failure: write the value we saw to EAX. */ dst.type = OP_REG; dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; } break; case 0xb3: btr: /* btr */ src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("btr", src, dst, _eflags); break; case 0xb6 ... 0xb7: /* movzx */ dst.bytes = op_bytes; dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val; break; case 0xba: /* Grp8 */ switch (modrm_reg & 3) { case 0: goto bt; case 1: goto bts; case 2: goto btr; case 3: goto btc; } break; case 0xbb: btc: /* btc */ src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("btc", src, dst, _eflags); break; case 0xbe ... 0xbf: /* movsx */ dst.bytes = op_bytes; dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val; break; case 0xc3: /* movnti */ dst.bytes = op_bytes; dst.val = (op_bytes == 4) ? (u32) src.val : (u64) src.val; break; } goto writeback;twobyte_special_insn: /* Disable writeback. */ no_wb = 1; switch (b) { case 0x06: emulate_clts(ctxt->vcpu); break; case 0x08: /* invd */ break; case 0x09: /* wbinvd */ break; case 0x0d: /* GrpP (prefetch) */ case 0x18: /* Grp16 (prefetch/nop) */ break; case 0x20: /* mov cr, reg */ if (modrm_mod != 3) goto cannot_emulate; _regs[modrm_rm] = realmode_get_cr(ctxt->vcpu, modrm_reg); break; case 0x22: /* mov reg, cr */ if (modrm_mod != 3) goto cannot_emulate; realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); break; case 0x30: /* wrmsr */ msr_data = (u32)_regs[VCPU_REGS_RAX] | ((u64)_regs[VCPU_REGS_RDX] << 32); rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data); if (rc) { kvm_x86_ops->inject_gp(ctxt->vcpu, 0); _eip = ctxt->vcpu->rip; } rc = X86EMUL_CONTINUE; break; case 0x32: /* rdmsr */ rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data); if (rc) { kvm_x86_ops->inject_gp(ctxt->vcpu, 0); _eip = ctxt->vcpu->rip; } else { _regs[VCPU_REGS_RAX] = (u32)msr_data; _regs[VCPU_REGS_RDX] = msr_data >> 32; } rc = X86EMUL_CONTINUE; break; case 0x80 ... 0x8f: /* jnz rel, etc*/ { long int rel; switch (op_bytes) { case 2: rel = insn_fetch(s16, 2, _eip); break; case 4: rel = insn_fetch(s32, 4, _eip); break; case 8: rel = insn_fetch(s64, 8, _eip); break; default: DPRINTF("jnz: Invalid op_bytes\n"); goto cannot_emulate; } if (test_cc(b, _eflags)) JMP_REL(rel); break; } case 0xc7: /* Grp9 (cmpxchg8b) */ { u64 old, new; if ((rc = ops->read_emulated(cr2, &old, 8, ctxt->vcpu)) != 0) goto done; if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) { _regs[VCPU_REGS_RAX] = (u32) (old >> 0); _regs[VCPU_REGS_RDX] = (u32) (old >> 32); _eflags &= ~EFLG_ZF; } else { new = ((u64)_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX]; if ((rc = ops->cmpxchg_emulated(cr2, &old, &new, 8, ctxt->vcpu)) != 0) goto done; _eflags |= EFLG_ZF; } break; } } goto writeback;cannot_emulate: DPRINTF("Cannot emulate %02x\n", b); return -1;}#ifdef __XEN__#include <asm/mm.h>#include <asm/uaccess.h>intx86_emulate_read_std(unsigned long addr, unsigned long *val, unsigned int bytes, struct x86_emulate_ctxt *ctxt){ unsigned int rc; *val = 0; if ((rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0) { propagate_page_fault(addr + bytes - rc, 0); /* read fault */ return X86EMUL_PROPAGATE_FAULT; } return X86EMUL_CONTINUE;}intx86_emulate_write_std(unsigned long addr, unsigned long val, unsigned int bytes, struct x86_emulate_ctxt *ctxt){ unsigned int rc; if ((rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0) { propagate_page_fault(addr + bytes - rc, PGERR_write_access); return X86EMUL_PROPAGATE_FAULT; } return X86EMUL_CONTINUE;}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?