From 3b69578cd2a138b8fa1260a0dd1fa943cba113cd Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Thu, 26 Jul 2012 16:25:53 -0700 Subject: [PATCH] x86emu: Fix more mis-decoding of the data prefix cc2c73ddcb4370a7c3ad439cda4da825156c26c9's three-cent titanium tax doesn't go too far enough. Fix the rest of the call and jmp instructions to handle the data prefix correctly. Reference: Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2A: Instruction Set Reference, A-M http://www.intel.com/Assets/PDF/manual/253666.pdf Imported from: http://cgit.freedesktop.org/xorg/xserver/commit/hw/xfree86/x86emu?id=bb18f277156c08be028a6e12d8987fb1593e9168 Signed-off-by: Stefan Reinauer Change-Id: I83e6245d9748ee86722cfb7d8ac65258c35c013c Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson Reviewed-on: http://review.coreboot.org/1366 Tested-by: build bot (Jenkins) Reviewed-by: Anton Kochkov Reviewed-by: Patrick Georgi --- src/devices/oprom/x86emu/ops.c | 67 ++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/src/devices/oprom/x86emu/ops.c b/src/devices/oprom/x86emu/ops.c index 6bfc71c08c..536b4041b2 100644 --- a/src/devices/oprom/x86emu/ops.c +++ b/src/devices/oprom/x86emu/ops.c @@ -2294,15 +2294,20 @@ Handles opcode 0x9a ****************************************************************************/ static void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1)) { - u16 farseg, faroff; + u32 farseg, faroff; START_OF_INSTR(); - DECODE_PRINTF("CALL\t"); - faroff = fetch_word_imm(); - farseg = fetch_word_imm(); - DECODE_PRINTF2("%04x:", farseg); - DECODE_PRINTF2("%04x\n", faroff); - CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR "); + DECODE_PRINTF("CALL\t"); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + faroff = fetch_long_imm(); + farseg = fetch_word_imm(); + } else { + faroff = fetch_word_imm(); + farseg = fetch_word_imm(); + } + DECODE_PRINTF2("%04x:", farseg); + DECODE_PRINTF2("%04x\n", faroff); + CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR "); /* XXX * @@ -2313,8 +2318,12 @@ static void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1)) TRACE_AND_STEP(); push_word(M.x86.R_CS); M.x86.R_CS = farseg; - push_word(M.x86.R_IP); - M.x86.R_IP = faroff; + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + push_long(M.x86.R_EIP); + } else { + push_word(M.x86.R_IP); + } + M.x86.R_EIP = faroff & 0xffff; DECODE_CLEAR_SEGOVR(); END_OF_INSTR(); } @@ -4258,17 +4267,30 @@ Handles opcode 0xe8 ****************************************************************************/ static void x86emuOp_call_near_IMM(u8 X86EMU_UNUSED(op1)) { - s16 ip; + s16 ip16 = 0; /* Initialize to keep GCC silent */ + s32 ip32 = 0; START_OF_INSTR(); - DECODE_PRINTF("CALL\t"); - ip = (s16) fetch_word_imm(); - ip += (s16) M.x86.R_IP; /* CHECK SIGN */ - DECODE_PRINTF2("%04x\n", ip); - CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip, ""); + DECODE_PRINTF("CALL\t"); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + ip32 = (s32) fetch_long_imm(); + ip32 += (s16) M.x86.R_IP; /* CHECK SIGN */ + DECODE_PRINTF2("%04x\n", (u16)ip32); + CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip32, ""); + } else { + ip16 = (s16) fetch_word_imm(); + ip16 += (s16) M.x86.R_IP; /* CHECK SIGN */ + DECODE_PRINTF2("%04x\n", ip16); + CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip16, ""); + } TRACE_AND_STEP(); - push_word(M.x86.R_IP); - M.x86.R_IP = ip; + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + push_long(M.x86.R_EIP); + M.x86.R_EIP = ip32 & 0xffff; + } else { + push_word(M.x86.R_IP); + M.x86.R_EIP = ip16; + } DECODE_CLEAR_SEGOVR(); END_OF_INSTR(); } @@ -4299,17 +4321,22 @@ Handles opcode 0xea ****************************************************************************/ static void x86emuOp_jump_far_IMM(u8 X86EMU_UNUSED(op1)) { - u16 cs, ip; + u16 cs; + u32 ip; START_OF_INSTR(); DECODE_PRINTF("JMP\tFAR "); - ip = fetch_word_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + ip = fetch_long_imm(); + } else { + ip = fetch_word_imm(); + } cs = fetch_word_imm(); DECODE_PRINTF2("%04x:", cs); DECODE_PRINTF2("%04x\n", ip); JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, cs, ip, " FAR "); TRACE_AND_STEP(); - M.x86.R_IP = ip; + M.x86.R_EIP = ip & 0xffff; M.x86.R_CS = cs; DECODE_CLEAR_SEGOVR(); END_OF_INSTR();