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