diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 07486ddcdd..01f5526b80 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1028,9 +1028,11 @@ static inline unsigned char inb_user( (admin_io_okay(_p, 4, _d, _r) ? outl(_v, _p) : ((void)0)) /* Instruction fetch with error handling. */ -#define insn_fetch(_type, _size, _ptr) \ -({ unsigned long _rc, _x; \ - if ( (_rc = copy_from_user(&_x, (_type *)eip, sizeof(_type))) != 0 ) \ +#define insn_fetch(_type, _size, cs, eip) \ +({ unsigned long _rc, _x, _ptr = eip; \ + if ( vm86_mode(regs) ) \ + _ptr += cs << 4; \ + if ( (_rc = copy_from_user(&_x, (_type *)_ptr, sizeof(_type))) != 0 ) \ { \ propagate_page_fault(eip + sizeof(_type) - _rc, 0); \ return EXCRET_fault_fixed; \ @@ -1040,7 +1042,7 @@ static inline unsigned char inb_user( static int emulate_privileged_op(struct cpu_user_regs *regs) { struct vcpu *v = current; - unsigned long *reg, eip = regs->eip, res; + unsigned long *reg, eip = regs->eip, cs = regs->cs, res; u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0; unsigned int port, i, op_bytes = 4, data, rc; u32 l, h; @@ -1048,7 +1050,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) /* Legacy prefixes. */ for ( i = 0; i < 8; i++ ) { - switch ( opcode = insn_fetch(u8, 1, eip) ) + switch ( opcode = insn_fetch(u8, 1, cs, eip) ) { case 0x66: /* operand-size override */ op_bytes ^= 6; /* switch between 2/4 bytes */ @@ -1080,7 +1082,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) modrm_rm = (opcode & 1) << 3; /* REX.B */ /* REX.W and REX.X do not need to be decoded. */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); } #endif @@ -1162,7 +1164,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) case 0xe4: /* IN imm8,%al */ op_bytes = 1; case 0xe5: /* IN imm8,%eax */ - port = insn_fetch(u8, 1, eip); + port = insn_fetch(u8, 1, cs, eip); exec_in: if ( !guest_io_okay(port, op_bytes, v, regs) ) goto fail; @@ -1191,7 +1193,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) case 0xe6: /* OUT %al,imm8 */ op_bytes = 1; case 0xe7: /* OUT %eax,imm8 */ - port = insn_fetch(u8, 1, eip); + port = insn_fetch(u8, 1, cs, eip); exec_out: if ( !guest_io_okay(port, op_bytes, v, regs) ) goto fail; @@ -1240,7 +1242,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) goto fail; /* Privileged (ring 0) instructions. */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); switch ( opcode ) { case 0x06: /* CLTS */ @@ -1258,7 +1260,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; case 0x20: /* MOV CR?, */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); modrm_reg |= (opcode >> 3) & 7; modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); @@ -1292,7 +1294,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; case 0x21: /* MOV DR?, */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); modrm_reg |= (opcode >> 3) & 7; modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); @@ -1302,7 +1304,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; case 0x22: /* MOV ,CR? */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); modrm_reg |= (opcode >> 3) & 7; modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0); @@ -1342,7 +1344,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; case 0x23: /* MOV ,DR? */ - opcode = insn_fetch(u8, 1, eip); + opcode = insn_fetch(u8, 1, cs, eip); modrm_reg |= (opcode >> 3) & 7; modrm_rm |= (opcode >> 0) & 7; reg = decode_register(modrm_rm, regs, 0);