|
From: Jeremy F. <je...@go...> - 2004-01-23 23:09:35
|
CVS commit by fitzhardinge:
Fix bug 73219. This adds a general mechanism for querying the host CPU's
capabilities, and uses it to see if it has SSE/SSE2/fxsave support before
trying to use fxsave at startup.
M +35 -0 coregrind/vg_include.h 1.171
M +8 -8 coregrind/vg_main.c 1.139
M +88 -0 coregrind/vg_to_ucode.c 1.125
M +2 -2 include/vg_skin.h.base 1.10
--- valgrind/coregrind/vg_include.h #1.170:1.171
@@ -1137,4 +1137,39 @@ extern Bool VG_(is_chained_jumpsite)
------------------------------------------------------------------ */
+#define VG_X86_FEAT_FPU (0*32 + 0)
+#define VG_X86_FEAT_VME (0*32 + 1)
+#define VG_X86_FEAT_DE (0*32 + 2)
+#define VG_X86_FEAT_PSE (0*32 + 3)
+#define VG_X86_FEAT_TSC (0*32 + 4)
+#define VG_X86_FEAT_MSR (0*32 + 5)
+#define VG_X86_FEAT_PAE (0*32 + 6)
+#define VG_X86_FEAT_MCE (0*32 + 7)
+#define VG_X86_FEAT_CX8 (0*32 + 8)
+#define VG_X86_FEAT_APIC (0*32 + 9)
+#define VG_X86_FEAT_SEP (0*32 + 11)
+#define VG_X86_FEAT_MTRR (0*32 + 12)
+#define VG_X86_FEAT_PGE (0*32 + 13)
+#define VG_X86_FEAT_MCA (0*32 + 14)
+#define VG_X86_FEAT_CMOV (0*32 + 15)
+#define VG_X86_FEAT_PAT (0*32 + 16)
+#define VG_X86_FEAT_PSE36 (0*32 + 17)
+#define VG_X86_FEAT_CLFSH (0*32 + 19)
+#define VG_X86_FEAT_DS (0*32 + 21)
+#define VG_X86_FEAT_ACPI (0*32 + 22)
+#define VG_X86_FEAT_MMX (0*32 + 23)
+#define VG_X86_FEAT_FXSR (0*32 + 24)
+#define VG_X86_FEAT_SSE (0*32 + 25)
+#define VG_X86_FEAT_SSE2 (0*32 + 26)
+#define VG_X86_FEAT_SS (0*32 + 27)
+#define VG_X86_FEAT_HT (0*32 + 28)
+#define VG_X86_FEAT_TM (0*32 + 29)
+#define VG_X86_FEAT_PBE (0*32 + 31)
+
+#define VG_X86_FEAT_EST (1*32 + 7)
+#define VG_X86_FEAT_TM2 (1*32 + 8)
+#define VG_X86_FEAT_CNXTID (1*32 + 10)
+
+Bool VG_(cpu_has_feature)(UInt feat);
+
extern Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 );
--- valgrind/coregrind/vg_main.c #1.138:1.139
@@ -503,12 +503,7 @@ Int VG_(exitcode) = 0;
Bool VG_(logging_to_filedes) = True;
-/* Is this a SSE/SSE2-capable CPU? If so, we had better save/restore
- the SSE state all over the place. This is set up very early, in
- vg_startup.S. We have to determine it early since we can't even
- correctly snapshot the startup machine state without it. */
-/* Initially True. Safer to err on the side of SSEness and get SIGILL
- than to not notice for some reason that we have SSE and get weird
- errors later on. */
-Bool VG_(have_ssestate) = True;
+/* This is set early to inidicate whether this CPU has the
+ SSE/fxsave/fxrestor features. */
+Bool VG_(have_ssestate);
@@ -1395,4 +1390,9 @@ void VG_(main) ( const KickstartParams *
VG_(m_state_static)[60/4] = kp->client_eip;
+ /* I assume that if we have SSE2 we also have SSE */
+ VG_(have_ssestate) =
+ VG_(cpu_has_feature)(VG_X86_FEAT_FXSR) &&
+ VG_(cpu_has_feature)(VG_X86_FEAT_SSE);
+
/* set up an initial FPU state (doesn't really matter what it is,
so long as it's somewhat valid) */
--- valgrind/coregrind/vg_to_ucode.c #1.124:1.125
@@ -41,4 +41,92 @@
/*------------------------------------------------------------*/
+/*--- CPU feature set stuff ---*/
+/*--- This is a little out of place here, but it will do ---*/
+/*--- for now. ---*/
+/*------------------------------------------------------------*/
+
+#define VG_N_FEATURE_WORDS 2
+
+static Int cpuid_level = -2; /* -2 -> not initialized */
+static UInt cpu_features[VG_N_FEATURE_WORDS];
+
+/* Standard macro to see if a specific flag is changeable */
+static inline Bool flag_is_changeable(UInt flag)
+{
+ UInt f1, f2;
+
+ asm("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" (flag));
+
+ return ((f1^f2) & flag) != 0;
+}
+
+
+/* Probe for the CPUID instruction */
+static Bool has_cpuid(void)
+{
+ return flag_is_changeable(EFlagID);
+}
+
+static inline UInt cpuid_eax(UInt eax)
+{
+ asm("cpuid" : "=a" (eax) : "0" (eax) : "bx", "cx", "dx");
+ return eax;
+}
+
+static inline void cpuid(UInt eax,
+ UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
+{
+ UInt ebx, ecx, edx;
+
+ asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "0" (eax));
+
+ if (eax_ret)
+ *eax_ret = eax;
+ if (ebx_ret)
+ *ebx_ret = ebx;
+ if (ecx_ret)
+ *ecx_ret = ecx;
+ if (edx_ret)
+ *edx_ret = edx;
+}
+
+static void get_cpu_features(void)
+{
+ if (!has_cpuid()) {
+ cpuid_level = -1;
+ return;
+ }
+
+ cpuid_level = cpuid_eax(0);
+
+ if (cpuid_level >= 1)
+ cpuid(1, NULL, NULL, &cpu_features[1], &cpu_features[0]);
+}
+
+Bool VG_(cpu_has_feature)(UInt feature)
+{
+ UInt word = feature / 32;
+ UInt bit = feature % 32;
+
+ if (cpuid_level == -2)
+ get_cpu_features();
+
+ vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
+
+ return !!(cpu_features[word] & (1 << bit));
+}
+
+/*------------------------------------------------------------*/
/*--- Here so it can be inlined everywhere. ---*/
/*------------------------------------------------------------*/
--- valgrind/include/vg_skin.h.base #1.9:1.10
@@ -1,4 +1,3 @@
-
-/*--------------------------------------------------------------------*/
+/*-*- c -*- ----------------------------------------------------------*/
/*--- The only header your skin will ever need to #include... ---*/
/*--- vg_skin.h ---*/
@@ -955,4 +954,5 @@
#define EFlagD (1 << 10) /* direction */
#define EFlagO (1 << 11) /* overflow */
+#define EFlagID (1 << 21) /* changable if CPUID exists */
/* Liveness of general purpose registers, useful for code generation.
|