summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Reinauer <reinauer@chromium.org>2012-07-26 16:25:53 -0700
committerPatrick Georgi <patrick@georgi-clan.de>2012-08-02 14:42:40 +0200
commit3b69578cd2a138b8fa1260a0dd1fa943cba113cd (patch)
tree3fb1fe7104fd737736c5589f8cd83fccea948afb
parentb25374cec558cacadafb9e10d8816508c5a8ecc4 (diff)
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 <reinauer@google.com> Change-Id: I83e6245d9748ee86722cfb7d8ac65258c35c013c Reviewed-by: Julien Cristau <jcristau@debian.org> Signed-off-by: Adam Jackson <ajax@redhat.com> Reviewed-on: http://review.coreboot.org/1366 Tested-by: build bot (Jenkins) Reviewed-by: Anton Kochkov <anton.kochkov@gmail.com> Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
-rw-r--r--src/devices/oprom/x86emu/ops.c67
1 files 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();