[Xorg-driver-geode] [RFC PATCH] X86EMU: handle CPUID instruction

Bart Trojanowski bart at symbio-technologies.com
Sat Feb 2 19:10:16 PST 2008


Please consider this patch as a work in progress.

I have updated the patch to handle the CPUID on a non x86 system.  Thank
you to the CC'ed for setting me straight on that one.

Values returned by function 1 (EAX==1) for non x86 systems still needs a
bit of cleanup.  Currently I am returning values from the GeodeLX, but I
would like to return the values from a 486DX2, which Martin Eric
(Q-FUNK) will get for me tomorrow.

Also, Stephane Marchesin (marcheu) suggested that I mask out the MTRR
support if I do go out to fetch the CPUID from the hardware.

If the above two changes are made, would this approach be accepted?

-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 |   62 +++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 61 insertions(+), 1 deletions(-)

diff --git a/hw/xfree86/x86emu/ops2.c b/hw/xfree86/x86emu/ops2.c
index 68e73ab..f91b3d7 100644
--- a/hw/xfree86/x86emu/ops2.c
+++ b/hw/xfree86/x86emu/ops2.c
@@ -333,6 +333,66 @@ 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();
+#ifdef __i386__
+    // see this link for reference...
+    // http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well
+#ifdef __PIC__
+    __asm__ __volatile__ ("pushl %%ebx      \n\t"
+                          "cpuid            \n\t"
+                          "movl %%ebx, %1   \n\t"
+                          "popl %%ebx       \n\t"
+                          : "=a" (M.x86.R_EAX), "=r" (M.x86.R_EBX),
+                            "=c" (M.x86.R_ECX), "=d" (M.x86.R_EDX)
+                          : "a" (M.x86.R_EAX), "c" (M.x86.R_ECX)
+                          : "cc");
+#else
+    __asm__ __volatile__ ("cpuid"
+                          : "=a" (M.x86.R_EAX), "=b" (M.x86.R_EBX),
+                            "=c" (M.x86.R_ECX), "=d" (M.x86.R_EDX)
+                          : "a" (M.x86.R_EAX), "c" (M.x86.R_ECX)
+                          : "cc");
+#endif
+#else // not __i386__
+    switch (M.x86.R_EAX) {
+    case 0:
+        M.x86.R_EAX = 1;		// maximum function number we support
+        M.x86.R_EBX = 0x68747541;
+        M.x86.R_ECX = 0x444d4163;
+        M.x86.R_EDX = 0x69746e65;
+        break;
+    case 1:
+        M.x86.R_EAX = 0x000005a2;	// copied from GeodeLX
+        M.x86.R_EBX = 0x00000400;
+        M.x86.R_ECX = 0x00000000;
+        M.x86.R_EDX = 0x0088a93d;
+        break;
+    case 0x80000000:
+        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;
+    default:
+        DECODE_PRINTF("ILLEGAL CPUID FUNCTION\n");
+        TRACE_REGS();
+        printk("%04x:%04x: ILLEGAL CPUID FUNCTION!\n",
+                M.x86.R_CS, M.x86.R_IP-3, M.x86.R_EAX);
+        HALT_SYS();
+    }
+#endif
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
 REMARKS:
 Handles opcode 0x0f,0xa3
 ****************************************************************************/
@@ -2739,7 +2799,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,
-- 
1.5.3.7.1150.g149d432


More information about the Xorg-driver-geode mailing list