[PATCH] X86EMU: handle CPUID instruction
Bart Trojanowski
bart at symbio-technologies.com
Sun Feb 3 10:25:14 PST 2008
This is a repost of my original patch. It takes into account that the
code needs to run on multiple architectures.
The values returned by a non x86 system comes from a 486dx4. On x86
systems, I issue the cpuid instruction and then scrub the output to
remove features that we don't support in the emulator.
Also, the code in ops2.c is a bit cleaner at the cost of the length of
the patch. As other emulated instructions, the smarts are now in
prim_ops.c in a cpuid() function.
-Bart
Rest of the commit follows...
--
This bug is tracked here:
https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-amd/+bug/180742
After trying to switch from X to VT (or just quit) the video-amd driver
attempts to issue INT 10/0 to go to mode 3 (VGA). The emulator, running
the BIOS code, would then spit out:
c000:0282: A2 ILLEGAL EXTENDED X86 OPCODE!
The opcode was 0F A2, or CPUID; it was not implemented in the emulator.
This simple patch, against 1.3.0.0, handles the CPUID instruction in one of
two ways:
1) if ran on __i386__ then it calls the CPUID instruction directly.
2) if ran elsewhere it returns a canned set of values for function 1.
This fix allows the video-amd driver to switch back to console mode,
with the GSW BIOS.
Thanks to Symbio Technologies for funding my work, and ThinCan for
providing hardware :)
Signed-off-by: Bart Trojanowski <bart at jukie.net>
---
hw/xfree86/x86emu/ops2.c | 16 ++++++-
hw/xfree86/x86emu/prim_ops.c | 44 ++++++++++++++++++
hw/xfree86/x86emu/x86emu/prim_i386_gcc.h | 71 ++++++++++++++++++++++++++++++
hw/xfree86/x86emu/x86emu/prim_ops.h | 1 +
4 files changed, 131 insertions(+), 1 deletions(-)
create mode 100644 hw/xfree86/x86emu/x86emu/prim_i386_gcc.h
diff --git a/hw/xfree86/x86emu/ops2.c b/hw/xfree86/x86emu/ops2.c
index 8c6c535..324de8a 100644
--- a/hw/xfree86/x86emu/ops2.c
+++ b/hw/xfree86/x86emu/ops2.c
@@ -328,6 +328,20 @@ static void x86emuOp2_pop_FS(u8 X86EMU_UNUSED(op2))
}
/****************************************************************************
+REMARKS: CPUID takes EAX/ECX as inputs, writes EAX/EBX/ECX/EDX as output
+Handles opcode 0x0f,0xa2
+****************************************************************************/
+static void x86emuOp2_cpuid(u8 X86EMU_UNUSED(op2))
+{
+ START_OF_INSTR();
+ DECODE_PRINTF("CPUID\n");
+ TRACE_AND_STEP();
+ cpuid();
+ DECODE_CLEAR_SEGOVR();
+ END_OF_INSTR();
+}
+
+/****************************************************************************
REMARKS:
Handles opcode 0x0f,0xa3
****************************************************************************/
@@ -2734,7 +2748,7 @@ void (*x86emu_optab2[256])(u8) =
/* 0xa0 */ x86emuOp2_push_FS,
/* 0xa1 */ x86emuOp2_pop_FS,
-/* 0xa2 */ x86emuOp2_illegal_op,
+/* 0xa2 */ x86emuOp2_cpuid,
/* 0xa3 */ x86emuOp2_bt_R,
/* 0xa4 */ x86emuOp2_shld_IMM,
/* 0xa5 */ x86emuOp2_shld_CL,
diff --git a/hw/xfree86/x86emu/prim_ops.c b/hw/xfree86/x86emu/prim_ops.c
index 461e09e..e845d1b 100644
--- a/hw/xfree86/x86emu/prim_ops.c
+++ b/hw/xfree86/x86emu/prim_ops.c
@@ -102,6 +102,12 @@
#define PRIM_OPS_NO_REDEFINE_ASM
#include "x86emu/x86emui.h"
+#if defined(__GNUC__)
+#if defined(__i386__) || defined(__x86_64__)
+#include "x86emu/prim_i386_gcc.h"
+#endif
+#endif
+
/*------------------------- Global Variables ------------------------------*/
static u32 x86emu_parity_tab[8] =
@@ -2654,3 +2660,41 @@ DB( if (CHECK_SP_ACCESS())
return res;
}
+/****************************************************************************
+REMARKS:
+CPUID takes EAX/ECX as inputs, writes EAX/EBX/ECX/EDX as output
+****************************************************************************/
+void cpuid (void)
+{
+ u32 feature = M.x86.R_EAX;
+#ifdef prim_cpuid
+ prim_cpuid(M.x86.R_EAX, M.x86.R_EBX, M.x86.R_ECX, M.x86.R_EDX);
+#endif
+ switch (feature) {
+ case 0:
+ M.x86.R_EAX = 1; // maximum function number we support
+#ifndef prim_cpuid
+ M.x86.R_EBX = 0x756e6547;
+ M.x86.R_ECX = 0x6c65746e;
+ M.x86.R_EDX = 0x49656e69;
+#endif
+ break;
+ case 1:
+#ifndef prim_cpuid
+ M.x86.R_EAX = 0x00000480; // 486dx4
+ M.x86.R_EBX = 0x00000000;
+ M.x86.R_ECX = 0x00000000;
+ M.x86.R_EDX = 0x00000002; // VME
+#else
+ M.x86.R_EDX &= 0x00000012; // TSC and VME
+#endif
+ break;
+ default:
+ M.x86.R_EAX = 0; // don't support extended features
+ M.x86.R_EBX = 0;
+ M.x86.R_ECX = 0;
+ M.x86.R_EDX = 0;
+ break;
+ }
+}
+
diff --git a/hw/xfree86/x86emu/x86emu/prim_i386_gcc.h b/hw/xfree86/x86emu/x86emu/prim_i386_gcc.h
new file mode 100644
index 0000000..408caf7
--- /dev/null
+++ b/hw/xfree86/x86emu/x86emu/prim_i386_gcc.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+*
+* Inline helpers for x86emu
+*
+* Copyright (C) 2008 Bart Trojanowski, Symbio Technologies, LLC
+*
+* ========================================================================
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee,
+* provided that the above copyright notice appear in all copies and that
+* both that copyright notice and this permission notice appear in
+* supporting documentation, and that the name of the authors not be used
+* in advertising or publicity pertaining to distribution of the software
+* without specific, written prior permission. The authors makes no
+* representations about the suitability of this software for any purpose.
+* It is provided "as is" without express or implied warranty.
+*
+* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*
+* ========================================================================
+*
+* Language: GNU C
+* Environment: GCC on i386 or x86-64
+* Developer: Bart Trojanowski
+*
+* Description: This file defines a few x86 macros that can be used by the
+* emulator to execute native instructions.
+*
+* For PIC vs non-PIC code refer to:
+* http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well
+*
+****************************************************************************/
+#ifndef __X86EMU_PRIM_I386_GCC_H
+#define __X86EMU_PRIM_I386_GCC_H
+
+#if !defined(__GNUC__) || !(defined(__i386__) || defined(__x86_64__))
+#error This file is intended to be used by gcc on i386 or x86-64 system
+#endif
+
+#ifdef __PIC__
+
+#define prim_cpuid(a,b,c,d) \
+ __asm__ __volatile__ ("pushl %%ebx \n\t" \
+ "cpuid \n\t" \
+ "movl %%ebx, %1 \n\t" \
+ "popl %%ebx \n\t" \
+ : "=a" (a), "=r" (b), \
+ "=c" (c), "=d" (d) \
+ : "a" (a), "c" (c) \
+ : "cc")
+
+#else // __PIC__
+
+#define prim_cpuid(a,b,c,d) \
+ __asm__ __volatile__ ("cpuid" \
+ : "=a" (a), "=b" (b), \
+ "=c" (c), "=d" (d) \
+ : "a" (a), "c" (c) \
+ : "cc")
+
+#endif // __PIC__
+
+
+#endif // __X86EMU_PRIM_I386_GCC_H
diff --git a/hw/xfree86/x86emu/x86emu/prim_ops.h b/hw/xfree86/x86emu/x86emu/prim_ops.h
index bea8357..6ac2a29 100644
--- a/hw/xfree86/x86emu/x86emu/prim_ops.h
+++ b/hw/xfree86/x86emu/x86emu/prim_ops.h
@@ -133,6 +133,7 @@ void push_word (u16 w);
void push_long (u32 w);
u16 pop_word (void);
u32 pop_long (void);
+void cpuid (void);
#ifdef __cplusplus
} /* End of "C" linkage for C++ */
--
1.5.3.7.1150.g149d432
More information about the xorg
mailing list