cpu autodetection for FreeBSD

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Wine lacks code to detect the CPU for FreeBSD, which causes problems
with many installers.  I wrote a patch some time ago which solved it for
me, but I didn't submit due to not really knowing if it was right.  In
particular I wasn't sure if PF_XMMI_INSTRUCTIONS_AVAILABLE meant SSE or
SSE2 (the commented OS check is for sse1).  It also hasn't been really
tested on any system but my Athlon.

Anyway, if someone would like to review and possibly commit it, that
would be great.

I'm not subscribed to the list, so CC me on replies.  I don't use wine
because it hangs whenever I try to run anything I'm interested in (bug
1215, where did the description go?)

-- 
Eric Anholt                                eta@lclark.edu          
http://people.freebsd.org/~anholt/         anholt@FreeBSD.org

--- misc/cpu.c.orig	Tue Jan  7 12:36:21 2003
+++ misc/cpu.c	Mon Feb 10 20:43:14 2003
@@ -37,6 +37,49 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(reg);
 
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#include <stdlib.h>
+
+#define AUTH	0x68747541	/* "Auth" */
+#define ENTI	0x69746e65	/* "enti" */
+#define CAMD	0x444d4163	/* "cAMD" */
+
+/* Calls cpuid with an eax of 'ax' and returns the 16 bytes in *p
+ * We are compiled with -fPIC, so we can't clobber ebx.
+ */
+static void
+do_cpuid(int ax, int *p)
+{
+	__asm __volatile("pushl %%ebx\n\t"
+			"cpuid\n\t"
+			"movl %%ebx, %%esi\n\t"
+			"popl %%ebx"
+			 : "=a" (p[0]), "=S" (p[1]), "=c" (p[2]), "=d" (p[3])
+			 :  "0" (ax));
+}
+
+/* From xf86info havecpuid.c 1.11 */
+static int
+have_cpuid()
+{
+	unsigned int f1, f2;
+	__asm__ volatile("pushfl\n\t"
+			"pushfl\n\t"
+			"popl %0\n\t"
+			"movl %0,%1\n\t"
+			"xorl %2,%0\n\t"
+			"pushl %0\n\t"
+			"popfl\n\t"
+			"pushfl\n\t"
+			"popl %0\n\t"
+			"popfl\n\t"
+			: "=&r" (f1), "=&r" (f2)
+			: "ir" (0x00200000));
+	return ((f1^f2) & 0x00200000) != 0;
+}
+#endif
+
 static BYTE PF[64] = {0,};
 
 static void create_registry_keys( const SYSTEM_INFO *info )
@@ -268,7 +311,61 @@
 	fclose (f);
 	}
 	memcpy(si,&cachedsi,sizeof(*si));
-#else  /* linux */
+#elif defined(__FreeBSD__)
+	{
+	unsigned int regs[4], regs2[4];
+	int ret, len, num;
+	if (!have_cpuid())
+		regs[0] = 0;			/* No cpuid support -- skip the rest */
+	else
+		do_cpuid(0x00000000, regs);	/* get standard cpuid level and vendor name */
+	if (regs[0]>=0x00000001) {		/* Check for supported cpuid version */
+		do_cpuid(0x00000001, regs2);	/* get cpu features */
+		switch ((regs2[0] >> 8)&0xf) {	/* cpu family */
+		case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
+			cachedsi.wProcessorLevel = 3;
+			break;
+		case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
+			cachedsi.wProcessorLevel = 4;
+			break;
+		case 5:
+		case 6: /* PPro/2/3 has same info as P1 */
+			cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
+			cachedsi.wProcessorLevel = 5;
+			break;
+		default:
+			FIXME("unknown cpu family %d, please report! (-> setting to 386)\n", \
+				(regs2[0] >> 8)&0xf);
+			break;
+		}
+		PF[PF_FLOATING_POINT_EMULATED]     = !(regs2[3] & 1);
+		PF[PF_RDTSC_INSTRUCTION_AVAILABLE] = (regs2[3] & (1 << 4 )) >> 4;
+		PF[PF_COMPARE_EXCHANGE_DOUBLE]     = (regs2[3] & (1 << 8 )) >> 8;
+		PF[PF_MMX_INSTRUCTIONS_AVAILABLE]  = (regs2[3] & (1 << 23)) >> 23;
+		/* Check for OS support of SSE -- Is this used, and should it be sse1 or sse2? */
+		/*len = sizeof(num);
+		ret = sysctlbyname("hw.instruction_sse", &num, &len, NULL, 0);
+		if (!ret)
+			PF[PF_XMMI_INSTRUCTIONS_AVAILABLE] = num;*/
+		
+		if (regs[1] == AUTH &&
+		    regs[3] == ENTI &&
+		    regs[2] == CAMD) {
+			do_cpuid(0x80000000, regs);		/* get vendor cpuid level */
+			if (regs[0]>=0x80000001) {
+				do_cpuid(0x80000001, regs2);	/* get vendor features */
+				PF[PF_AMD3D_INSTRUCTIONS_AVAILABLE] = 
+				    (regs2[3] & (1 << 31 )) >> 31;
+			}
+		}
+	}
+	len = sizeof(num);
+	ret = sysctlbyname("hw.ncpu", &num, &len, NULL, 0);
+	if (!ret)
+		cachedsi.dwNumberOfProcessors = num;
+	}
+	memcpy(si,&cachedsi,sizeof(*si));
+#else  /* linux || __FreeBSD__*/
 	FIXME("not yet supported on this system\n");
 #endif  /* !linux */
         TRACE("<- CPU arch %d, res'd %d, pagesize %ld, minappaddr %p, maxappaddr %p,"

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux