I have recently rewritten the Mesa CPU detection code and
would like someone else to give it a try.
Basically, the highlights are:
- added _mesa_x86_has_cpuid
- added _mesa_x86_cpuid
- added _mesa_x86_cpuid_eax
- added _mesa_x86_cpuid_ebx
- added _mesa_x86_cpuid_ecx
- added _mesa_x86_cpuid_edx
- removed _mesa_identify_x86_cpu_features
- differentiated extended cpu features (in ..x86_features.h)
from the std ones
- changed the X86_FEATURE semantics a little bit
with these tools, I am trying to parse the cpu feature while
making distinction between the normal and extended cpu
feature sets - no need to query the cpu vendor string, while
making the code highly readable for people not familiar with
the assembly langugage.
Please consider applying...
-petrs
Bernhard Kaindl wrote:
Hi,
I'd like to report a finding on my Satellite 1110-z16 with
Mobile Celeron 1500 and Radeon LY under SuSE 8.1 and Mandrake 9
using the installed XFree86-4.2 based X11/Mesa.Both show a problem with many 3D Linux apps arborting with SIGILL,
MESA_DEBUG showed that the apps were thinking that the Celeron
supported 3DNow(message 3dnow supported was printed) which it at
least does not when checking /proc/cpuinfo.After I disabled the use of 3dnow by exporting MESA_NO_3DNOW,
everything works but it's a not good needing to export it and it's
only a workaround.So it looks like as if the Mesa CPUID asm gets the 3dnow feature
bit set, so the feature is enabled and depending what the app does
it gets the sigill or not(glxgears and fgfs do not but show no
rendering in a part of the window if I move another window into the
middle of the 3d window.Both distributions use Free 4.2 code, but I've started
downloading the 4.3.99 rpms do test with it.Just guessing(maybe fixed already, just could not get the newest
XF86 4.3/Mesa Source over the slow modem I'm using atm yet, but
working on it):I've checked the 2.4.19 x86 feature/CPUID code in
arch/i386/kernel/setup.c and found a place where it
does something to the 3dnow flag.Maybe the CPUID regs set on stepping 7 of the Mobile
Celeron 1500 are a bit different and the kernel handles
this by the special 3dnow lines I've seen.Bernd
Index: common_x86.c
===================================================================
RCS file: /cvsroot/mesa3d/Mesa/src/X86/common_x86.c,v
retrieving revision 1.20
diff -u -r1.20 common_x86.c
--- common_x86.c 13 Nov 2002 15:03:31 -0000 1.20
+++ common_x86.c 31 Dec 2002 03:02:45 -0000
@@ -52,8 +52,14 @@
/* No reason for this to be public.
*/
-extern int _mesa_identify_x86_cpu_features( void );
+extern int _mesa_identify_x86_cpu_features(void);
+extern GLuint _mesa_x86_has_cpuid(void);
+extern void _mesa_x86_cpuid(GLuint op, GLuint *reg_eax, GLuint *reg_ebx, GLuint
+*reg_ecx, GLuint *reg_edx);
+extern GLuint _mesa_x86_cpuid_eax(GLuint op);
+extern GLuint _mesa_x86_cpuid_ebx(GLuint op);
+extern GLuint _mesa_x86_cpuid_ecx(GLuint op);
+extern GLuint _mesa_x86_cpuid_edx(GLuint op);
static void message( const char *msg )
{
@@ -240,8 +246,84 @@
{
(void) message; /* silence warning */
#ifdef USE_X86_ASM
- _mesa_x86_cpu_features = _mesa_identify_x86_cpu_features();
+ _mesa_x86_cpu_features = 0;
+ if (!_mesa_x86_has_cpuid()) {
+ message("CPUID not detected");
+ }
+ else {
+ GLuint cpu_features;
+ GLuint cpu_ext_features;
+ GLuint cpu_ext_info;
+ char cpu_vendor[13];
+ GLuint result;
+
+ /* get vendor name */
+ _mesa_x86_cpuid(0, &result, (GLuint *)(cpu_vendor + 0), (GLuint *)(cpu_vendor
++ 8), (GLuint *)(cpu_vendor + 4));
+ cpu_vendor[12] = '\0';
+
+ message("cpu vendor: ");
+ message(cpu_vendor);
+ message("\n");
+
+ /* get cpu features */
+ cpu_features = _mesa_x86_cpuid_edx(1);
+
+ if (cpu_features & X86_CPU_FPU)
+ _mesa_x86_cpu_features |= X86_FEATURE_FPU;
+ if (cpu_features & X86_CPU_CMOV)
+ _mesa_x86_cpu_features |= X86_FEATURE_CMOV;
+
+#ifdef USE_MMX_ASM
+ if (cpu_features & X86_CPU_MMX)
+ _mesa_x86_cpu_features |= X86_FEATURE_MMX;
+#endif
+
+#ifdef USE_SSE_ASM
+ if (cpu_features & X86_CPU_XMM)
+ _mesa_x86_cpu_features |= X86_FEATURE_XMM;
+ if (cpu_features & X86_CPU_XMM2)
+ _mesa_x86_cpu_features |= X86_FEATURE_XMM2;
+#endif
+
+ /* query extended cpu features */
+ if ((cpu_ext_info = _mesa_x86_cpuid_eax(0x80000000)) > 0x80000000) {
+ if (cpu_ext_info >= 0x80000001) {
+
+ cpu_ext_features = _mesa_x86_cpuid_edx(0x80000001);
+
+ if (cpu_features & X86_CPU_MMX) {
+
+#ifdef USE_3DNOW_ASM
+ if (cpu_ext_features & X86_CPUEXT_3DNOW)
+ _mesa_x86_cpu_features |= X86_FEATURE_3DNOW;
+ if (cpu_ext_features & X86_CPUEXT_3DNOW_EXT)
+ _mesa_x86_cpu_features |= X86_FEATURE_3DNOWEXT;
+#endif
+
+#ifdef USE_MMX_ASM
+ if (cpu_ext_features & X86_CPUEXT_MMX_EXT)
+ _mesa_x86_cpu_features |= X86_FEATURE_MMXEXT;
+#endif
+ }
+ }
+
+ /* query cpu name */
+ if (cpu_ext_info >= 0x80000002) {
+ GLuint ofs;
+ char cpu_name[49];
+ for (ofs = 0; ofs < 3; ofs++)
+ _mesa_x86_cpuid(0x80000002+ofs, (GLuint *)(cpu_name + (16*ofs)+0),
+(GLuint *)(cpu_name + (16*ofs)+4), (GLuint *)(cpu_name + (16*ofs)+8), (GLuint
+*)(cpu_name + (16*ofs)+12));
+ cpu_name[48] = '\0'; /* the name should be NULL terminated, but just to
+be sure */
+
+ message("cpu name: ");
+ message(cpu_name);
+ message("\n");
+ }
+ }
+
+ }
+
if ( getenv( "MESA_NO_ASM" ) ) {
_mesa_x86_cpu_features = 0;
}
Index: common_x86_asm.S
===================================================================
RCS file: /cvsroot/mesa3d/Mesa/src/X86/common_x86_asm.S,v
retrieving revision 1.13
diff -u -r1.13 common_x86_asm.S
--- common_x86_asm.S 9 Nov 2002 17:43:58 -0000 1.13
+++ common_x86_asm.S 31 Dec 2002 03:02:45 -0000
@@ -43,36 +43,11 @@
#include "matypes.h"
#include "common_x86_features.h"
-
-/* Intel vendor string
- */
-#define GENU 0x756e6547 /* "Genu" */
-#define INEI 0x49656e69 /* "ineI" */
-#define NTEL 0x6c65746e /* "ntel" */
-
-/* AMD vendor string
- */
-#define AUTH 0x68747541 /* "Auth" */
-#define ENTI 0x69746e65 /* "enti" */
-#define CAMD 0x444d4163 /* "cAMD" */
-
-
- SEG_DATA
-
-/* We might want to print out some useful messages.
- */
-GLNAME( found_intel ): STRING( "Genuine Intel processor found\n\0" )
-GLNAME( found_amd ): STRING( "Authentic AMD processor found\n\0" )
-
-
SEG_TEXT
ALIGNTEXT4
-GLOBL GLNAME( _mesa_identify_x86_cpu_features )
-GLNAME( _mesa_identify_x86_cpu_features ):
-
- PUSH_L ( EBX )
- PUSH_L ( ESI )
+GLOBL GLNAME( _mesa_x86_has_cpuid )
+GLNAME( _mesa_x86_has_cpuid ):
/* Test for the CPUID command. If the ID Flag bit in EFLAGS
* (bit 21) is writable, the CPUID command is present.
@@ -89,94 +64,113 @@
/* Verify the ID Flag bit has been written.
*/
CMP_L ( ECX, EAX )
- JZ ( LLBL (cpuid_done) )
+ SETNE ( AL )
+ XOR_L ( CONST(0xff), EAX )
- /* Get the CPU vendor info.
- */
- XOR_L ( EAX, EAX )
- CPUID
+ RET
- /* Test for Intel processors. We must look for the
- * "GenuineIntel" string in EBX, ECX and EDX.
- */
- CMP_L ( CONST(GENU), EBX )
- JNE ( LLBL(cpuid_amd) )
- CMP_L ( CONST(INEI), EDX )
- JNE ( LLBL(cpuid_amd) )
- CMP_L ( CONST(NTEL), ECX )
- JNE ( LLBL(cpuid_amd) )
- /* We have an Intel processor, so we can get the feature
- * information with an CPUID input value of 1.
- */
- MOV_L ( CONST(0x1), EAX )
- CPUID
- MOV_L ( EDX, EAX )
+ALIGNTEXT4
+GLOBL GLNAME( _mesa_x86_cpuid )
+GLNAME( _mesa_x86_cpuid ):
- /* Mask out highest bit, which is used by AMD for 3dnow
- * Newer Intel have this bit set, but do not support 3dnow
- */
- AND_L ( CONST(0X7FFFFFFF), EAX)
- JMP ( LLBL(cpuid_done) )
+ MOV_L ( REGOFF(4, ESP), EAX ) /* cpuid op */
-LLBL(cpuid_amd):
+ PUSH_L ( EDI )
+ PUSH_L ( EBX )
+ PUSH_L ( ECX )
+ PUSH_L ( EDX )
- /* Test for AMD processors. We must look for the
- * "AuthenticAMD" string in EBX, ECX and EDX.
- */
- CMP_L ( CONST(AUTH), EBX )
- JNE ( LLBL(cpuid_other) )
- CMP_L ( CONST(ENTI), EDX )
- JNE ( LLBL(cpuid_other) )
- CMP_L ( CONST(CAMD), ECX )
- JNE ( LLBL(cpuid_other) )
-
- /* We have an AMD processor, so we can get the feature
- * information after we verify that the extended functions are
- * supported.
- */
- /* The features we need are almost all in the extended set. The
- * exception is SSE enable, which is in the standard set (0x1).
- */
- MOV_L ( CONST(0x1), EAX )
CPUID
- TEST_L ( EAX, EAX )
- JZ ( LLBL (cpuid_failed) )
- MOV_L ( EDX, ESI )
- MOV_L ( CONST(0x80000000), EAX )
+ MOV_L ( REGOFF(24, ESP), EDI ) /* *eax */
+ MOV_L ( EAX, REGIND(EDI) )
+ MOV_L ( REGOFF(28, ESP), EDI ) /* *ebx */
+ MOV_L ( EBX, REGIND(EDI) )
+ MOV_L ( REGOFF(32, ESP), EDI ) /* *ecx */
+ MOV_L ( ECX, REGIND(EDI) )
+ MOV_L ( REGOFF(36, ESP), EDI ) /* *edx */
+ MOV_L ( EDX, REGIND(EDI) )
+
+ POP_L ( EDX )
+ POP_L ( ECX )
+ POP_L ( EBX )
+ POP_L ( EDI )
+ RET
+
+ALIGNTEXT4
+GLOBL GLNAME( _mesa_x86_cpuid_eax )
+GLNAME( _mesa_x86_cpuid_eax ):
+
+ MOV_L ( REGOFF(4, ESP), EAX ) /* cpuid op */
+
+ PUSH_L ( EBX )
+ PUSH_L ( ECX )
+ PUSH_L ( EDX )
+
CPUID
- TEST_L ( EAX, EAX )
- JZ ( LLBL (cpuid_failed) )
- MOV_L ( CONST(0x80000001), EAX )
+ POP_L ( EDX )
+ POP_L ( ECX )
+ POP_L ( EBX )
+ RET
+
+ALIGNTEXT4
+GLOBL GLNAME( _mesa_x86_cpuid_ebx )
+GLNAME( _mesa_x86_cpuid_ebx ):
+
+ MOV_L ( REGOFF(4, ESP), EAX ) /* cpuid op */
+
+ PUSH_L ( EBX )
+ PUSH_L ( ECX )
+ PUSH_L ( EDX )
+
CPUID
- MOV_L ( EDX, EAX )
-
- AND_L ( CONST(0x02000000), ESI ) /* OR in the SSE bit */
- OR_L ( ESI, EAX )
-
- JMP ( LLBL (cpuid_done) )
+ MOV_L ( EBX, EAX ) /* return EBX */
-LLBL(cpuid_other):
+ POP_L ( EDX )
+ POP_L ( ECX )
+ POP_L ( EBX )
- /* Test for other processors here when required.
- */
+ RET
-LLBL(cpuid_failed):
+ALIGNTEXT4
+GLOBL GLNAME( _mesa_x86_cpuid_ecx )
+GLNAME( _mesa_x86_cpuid_ecx ):
- /* If we can't determine the feature information, we must
- * return zero to indicate that no platform-specific
- * optimizations can be used.
- */
- MOV_L ( CONST(0), EAX )
+ MOV_L ( REGOFF(4, ESP), EAX ) /* cpuid op */
+
+ PUSH_L ( EBX )
+ PUSH_L ( ECX )
+ PUSH_L ( EDX )
-LLBL (cpuid_done):
+ CPUID
+ MOV_L ( ECX, EAX ) /* return ECX */
- POP_L ( ESI )
+ POP_L ( EDX )
+ POP_L ( ECX )
POP_L ( EBX )
+
RET
+ALIGNTEXT4
+GLOBL GLNAME( _mesa_x86_cpuid_edx )
+GLNAME( _mesa_x86_cpuid_edx ):
+
+ MOV_L ( REGOFF(4, ESP), EAX ) /* cpuid op */
+
+ PUSH_L ( EBX )
+ PUSH_L ( ECX )
+ PUSH_L ( EDX )
+
+ CPUID
+ MOV_L ( EDX, EAX ) /* return EDX */
+
+ POP_L ( EDX )
+ POP_L ( ECX )
+ POP_L ( EBX )
+
+ RET
#ifdef USE_SSE_ASM
/* Execute an SSE instruction to see if the operating system correctly
Index: common_x86_features.h
===================================================================
RCS file: /cvsroot/mesa3d/Mesa/src/X86/common_x86_features.h,v
retrieving revision 1.5
diff -u -r1.5 common_x86_features.h
--- common_x86_features.h 29 Oct 2002 20:28:57 -0000 1.5
+++ common_x86_features.h 31 Dec 2002 03:02:46 -0000
@@ -37,38 +37,25 @@
/* Capabilities of CPUs
*/
-#define X86_FEATURE_FPU 0x00000001
-#define X86_FEATURE_VME 0x00000002
-#define X86_FEATURE_DE 0x00000004
-#define X86_FEATURE_PSE 0x00000008
-#define X86_FEATURE_TSC 0x00000010
-#define X86_FEATURE_MSR 0x00000020
-#define X86_FEATURE_PAE 0x00000040
-#define X86_FEATURE_MCE 0x00000080
-#define X86_FEATURE_CX8 0x00000100
-#define X86_FEATURE_APIC 0x00000200
-#define X86_FEATURE_10 0x00000400
-#define X86_FEATURE_SEP 0x00000800
-#define X86_FEATURE_MTRR 0x00001000
-#define X86_FEATURE_PGE 0x00002000
-#define X86_FEATURE_MCA 0x00004000
-#define X86_FEATURE_CMOV 0x00008000
-#define X86_FEATURE_PAT 0x00010000
-#define X86_FEATURE_PSE36 0x00020000
-#define X86_FEATURE_18 0x00040000
-#define X86_FEATURE_19 0x00080000
-#define X86_FEATURE_20 0x00100000
-#define X86_FEATURE_21 0x00200000
-#define X86_FEATURE_MMXEXT 0x00400000
-#define X86_FEATURE_MMX 0x00800000
-#define X86_FEATURE_FXSR 0x01000000
-#define X86_FEATURE_XMM 0x02000000
-#define X86_FEATURE_XMM2 0x04000000
-#define X86_FEATURE_27 0x08000000
-#define X86_FEATURE_28 0x10000000
-#define X86_FEATURE_29 0x20000000
-#define X86_FEATURE_3DNOWEXT 0x40000000
-#define X86_FEATURE_3DNOW 0x80000000
+#define X86_FEATURE_FPU (1<<0)
+#define X86_FEATURE_CMOV (1<<1)
+#define X86_FEATURE_MMXEXT (1<<2)
+#define X86_FEATURE_MMX (1<<3)
+#define X86_FEATURE_FXSR (1<<4)
+#define X86_FEATURE_XMM (1<<5)
+#define X86_FEATURE_XMM2 (1<<6)
+#define X86_FEATURE_3DNOWEXT (1<<7)
+#define X86_FEATURE_3DNOW (1<<8)
+
+#define X86_CPU_FPU (1<<0)
+#define X86_CPU_CMOV (1<<15)
+#define X86_CPU_MMX (1<<23)
+#define X86_CPU_XMM (1<<25)
+#define X86_CPU_XMM2 (1<<26)
+
+#define X86_CPUEXT_MMX_EXT (1<<22)
+#define X86_CPUEXT_3DNOW_EXT (1<<30)
+#define X86_CPUEXT_3DNOW (1<<31)
#define cpu_has_mmx (_mesa_x86_cpu_features & X86_FEATURE_MMX)
#define cpu_has_mmxext (_mesa_x86_cpu_features & X86_FEATURE_MMXEXT)
