/* Assembly code stubs make this request */
#define VG_USERREQ__SIGNAL_RETURNS 0x4001
-/* CPU features */
-#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)
+/*
+ 0 - standard feature flags
+ 1 - Intel extended flags
+ 2 - Valgrind internal flags
+ 3 - AMD-specific flags
+ */
+#define VG_N_FEATURE_WORDS 4
+
+#define VG_X86_FEAT 0
+#define VG_EXT_FEAT 1
+#define VG_INT_FEAT 2
+#define VG_AMD_FEAT 3
+
+/* CPU features (generic) */
+#define VG_X86_FEAT_FPU (VG_X86_FEAT*32 + 0)
+#define VG_X86_FEAT_VME (VG_X86_FEAT*32 + 1)
+#define VG_X86_FEAT_DE (VG_X86_FEAT*32 + 2)
+#define VG_X86_FEAT_PSE (VG_X86_FEAT*32 + 3)
+#define VG_X86_FEAT_TSC (VG_X86_FEAT*32 + 4)
+#define VG_X86_FEAT_MSR (VG_X86_FEAT*32 + 5)
+#define VG_X86_FEAT_PAE (VG_X86_FEAT*32 + 6)
+#define VG_X86_FEAT_MCE (VG_X86_FEAT*32 + 7)
+#define VG_X86_FEAT_CX8 (VG_X86_FEAT*32 + 8)
+#define VG_X86_FEAT_APIC (VG_X86_FEAT*32 + 9)
+#define VG_X86_FEAT_SEP (VG_X86_FEAT*32 + 11)
+#define VG_X86_FEAT_MTRR (VG_X86_FEAT*32 + 12)
+#define VG_X86_FEAT_PGE (VG_X86_FEAT*32 + 13)
+#define VG_X86_FEAT_MCA (VG_X86_FEAT*32 + 14)
+#define VG_X86_FEAT_CMOV (VG_X86_FEAT*32 + 15)
+#define VG_X86_FEAT_PAT (VG_X86_FEAT*32 + 16)
+#define VG_X86_FEAT_PSE36 (VG_X86_FEAT*32 + 17)
+#define VG_X86_FEAT_CLFSH (VG_X86_FEAT*32 + 19)
+#define VG_X86_FEAT_DS (VG_X86_FEAT*32 + 21)
+#define VG_X86_FEAT_ACPI (VG_X86_FEAT*32 + 22)
+#define VG_X86_FEAT_MMX (VG_X86_FEAT*32 + 23)
+#define VG_X86_FEAT_FXSR (VG_X86_FEAT*32 + 24)
+#define VG_X86_FEAT_SSE (VG_X86_FEAT*32 + 25)
+#define VG_X86_FEAT_SSE2 (VG_X86_FEAT*32 + 26)
+#define VG_X86_FEAT_SS (VG_X86_FEAT*32 + 27)
+#define VG_X86_FEAT_HT (VG_X86_FEAT*32 + 28)
+#define VG_X86_FEAT_TM (VG_X86_FEAT*32 + 29)
+#define VG_X86_FEAT_IA64 (VG_X86_FEAT*32 + 30)
+#define VG_X86_FEAT_PBE (VG_X86_FEAT*32 + 31)
+
+/* Intel extended feature word */
+#define VG_X86_FEAT_SSE3 (VG_EXT_FEAT*32 + 0)
+#define VG_X86_FEAT_MON (VG_EXT_FEAT*32 + 3)
+#define VG_X86_FEAT_DSCPL (VG_EXT_FEAT*32 + 4)
+#define VG_X86_FEAT_EST (VG_EXT_FEAT*32 + 7)
+#define VG_X86_FEAT_TM2 (VG_EXT_FEAT*32 + 8)
+#define VG_X86_FEAT_CNXTID (VG_EXT_FEAT*32 + 10)
/* Used internally to mark whether CPUID is even implemented */
-#define VG_X86_FEAT_CPUID (2*32 + 0)
-
-/* The set of features we're willing to support for the client */
-#define VG_SUPPORTED_FEATURES \
- ((1 << VG_X86_FEAT_FPU) | \
- (1 << VG_X86_FEAT_TSC) | \
- (1 << VG_X86_FEAT_CMOV) | \
- (1 << VG_X86_FEAT_MMX) | \
- (1 << VG_X86_FEAT_FXSR) | \
- (1 << VG_X86_FEAT_SSE) | \
- (1 << VG_X86_FEAT_SSE2))
-
+#define VG_X86_FEAT_CPUID (VG_INT_FEAT*32 + 0)
+
+/* AMD special features */
+#define VG_AMD_FEAT_SYSCALL (VG_AMD_FEAT*32 + 11)
+#define VG_AMD_FEAT_NXP (VG_AMD_FEAT*32 + 20)
+#define VG_AMD_FEAT_MMXEXT (VG_AMD_FEAT*32 + 22)
+#define VG_AMD_FEAT_FFXSR (VG_AMD_FEAT*32 + 25)
+#define VG_AMD_FEAT_LONGMODE (VG_AMD_FEAT*32 + 29)
+#define VG_AMD_FEAT_3DNOWEXT (VG_AMD_FEAT*32 + 30)
+#define VG_AMD_FEAT_3DNOW (VG_AMD_FEAT*32 + 31)
+
/* Various environment variables we pay attention to */
/* The directory we look for all our auxillary files in */
dummy, replaced by %EDX value
RA <- %esp
- For simulating the cpuid instruction, we will
- issue a "real" cpuid instruction and then mask out
- the bits of the features we do not support currently (3dnow mostly).
- We also claim to not support most CPUID operations.
-
- Dirk Mueller <mueller@kde.org>
-
- http://www.sandpile.org/ia32/cpuid.htm
-
- references:
-
- pre-MMX pentium:
-
- <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
- <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
+ We save registers and package up the args so we can call a C helper
+ for all this.
*/
.global VG_(helper_CPUID)
VG_(helper_CPUID):
+ pushl %ebp
+ movl %esp,%ebp
pushl %eax
pushl %ebx
pushl %ecx
pushl %edx
- movl 32(%esp), %eax
-
- /* eax==0 - max valid request+processor vendor */
- cmpl $0, %eax
- jne 1f
-
- movl $1, %eax /* only support request 1 */
- movl valgrind_brand+0, %ebx
- movl valgrind_brand+4, %edx
- movl valgrind_brand+8, %ecx
- jmp 99f
-
- /* eax==1 - CPU features and model ID */
-1: cmpl $1, %eax
- jne 2f
-
- cpuid /* get host CPU's capabilities */
-
- movl $0111, %eax
- movl $0, %ebx /* clear APIC id, CLFLUSH size, Brand ID */
- movl $0, %ecx /* clear extended feature bits */
- andl $VG_SUPPORTED_FEATURES, %edx /* mask off feature bits we don't support */
- jmp 99f
-
- /* eax=0x80000000 - extended cpuid functions */
-2: cmpl $0x80000000, %eax
- jne 99f
-
- /* leave eax==0x80000000 - we don't support any other extended operations */
- movl valgrind_brand+0, %ebx /* AMD load the brand string again - */
- movl valgrind_brand+4, %edx /* Intel leaves them "reserved" */
- movl valgrind_brand+8, %ecx
-
+ pushl %esi
+ pushl %edi
+ pushf
-99: movl %edx, 20(%esp)
- movl %ecx, 24(%esp)
- movl %ebx, 28(%esp)
- movl %eax, 32(%esp)
+ lea 2*4(%ebp),%eax /* &edx */
+ pushl %eax
+ addl $4,%eax /* &ecx */
+ pushl %eax
+ addl $4,%eax /* &ebx */
+ pushl %eax
+ addl $4,%eax /* &eax */
+ pushl %eax
+ pushl (%eax) /* eax */
+
+ call VG_(helperc_CPUID)
+ addl $20,%esp
+ popf
+ popl %edi
+ popl %esi
popl %edx
popl %ecx
popl %ebx
popl %eax
+ popl %ebp
ret
-.data
-valgrind_brand:
- .ascii "ValgrindVCPU"
-.text
/* Fetch the FPU status register.
On entry:
/*--- for now. ---*/
/*------------------------------------------------------------*/
-#define VG_N_FEATURE_WORDS 3
+#define VG_CPU_VENDOR_GENERIC 0
+#define VG_CPU_VENDOR_INTEL 1
+#define VG_CPU_VENDOR_AMD 2
+
+static Int cpu_vendor = VG_CPU_VENDOR_GENERIC;
+
+static const struct cpu_vendor {
+ const Char *vendorstr;
+ Int vendorid;
+} cpu_vendors[] = {
+ { "GenuineIntel", VG_CPU_VENDOR_INTEL },
+ { "AuthenticAMD", VG_CPU_VENDOR_AMD },
+};
static Int cpuid_level = -2; /* -2 -> not initialized */
static UInt cpu_features[VG_N_FEATURE_WORDS];
static void get_cpu_features(void)
{
+ Char vendorstr[13];
+ Int i;
+
if (!has_cpuid()) {
cpuid_level = -1;
return;
}
- cpu_features[2] |= (1 << (VG_X86_FEAT_CPUID%32));
+ cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
- cpuid_level = cpuid_eax(0);
+ cpuid(0, &cpuid_level, (UInt *)&vendorstr[0], (UInt *)&vendorstr[8], (UInt *)&vendorstr[4]);
+ vendorstr[12] = '\0';
+
+ for(i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
+ if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
+ cpu_vendor = cpu_vendors[i].vendorid;
+ break;
+ }
if (cpuid_level >= 1)
- cpuid(1, NULL, NULL, &cpu_features[1], &cpu_features[0]);
+ cpuid(1, NULL, NULL, &cpu_features[VG_EXT_FEAT], &cpu_features[VG_X86_FEAT]);
+
+ switch(cpu_vendor) {
+ case VG_CPU_VENDOR_AMD:
+ /* get AMD-specific flags */
+ cpuid(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
+ break;
+
+ default:
+ break;
+ }
}
Bool VG_(cpu_has_feature)(UInt feature)
return !!(cpu_features[word] & (1 << bit));
}
+/* The set of features we're willing to support for the client
+
+ This includes supported instruction set extensions, plus any
+ extensions which don't have any user-mode visible effect (but the
+ client may find interesting).
+ */
+#define VG_X86_SUPPORTED_FEATURES \
+ ((1 << VG_X86_FEAT_FPU) | \
+ (1 << VG_X86_FEAT_VME) | \
+ (1 << VG_X86_FEAT_DE) | \
+ (1 << VG_X86_FEAT_PSE) | \
+ (1 << VG_X86_FEAT_TSC) | \
+ (0 << VG_X86_FEAT_MSR) | \
+ (1 << VG_X86_FEAT_PAE) | \
+ (1 << VG_X86_FEAT_MCE) | \
+ (1 << VG_X86_FEAT_CX8) | \
+ (1 << VG_X86_FEAT_APIC) | \
+ (0 << VG_X86_FEAT_SEP) | \
+ (1 << VG_X86_FEAT_MTRR) | \
+ (1 << VG_X86_FEAT_PGE) | \
+ (1 << VG_X86_FEAT_MCA) | \
+ (1 << VG_X86_FEAT_CMOV) | \
+ (1 << VG_X86_FEAT_PAT) | \
+ (1 << VG_X86_FEAT_PSE36) | \
+ (0 << VG_X86_FEAT_CLFSH) | \
+ (1 << VG_X86_FEAT_DS) | \
+ (1 << VG_X86_FEAT_ACPI) | \
+ (1 << VG_X86_FEAT_MMX) | \
+ (1 << VG_X86_FEAT_FXSR) | \
+ (1 << VG_X86_FEAT_SSE) | \
+ (1 << VG_X86_FEAT_SSE2) | \
+ (1 << VG_X86_FEAT_SS) | \
+ (1 << VG_X86_FEAT_HT) | \
+ (1 << VG_X86_FEAT_TM) | \
+ (0 << VG_X86_FEAT_IA64) | \
+ (1 << VG_X86_FEAT_PBE))
+
+#define VG_AMD_SUPPORTED_FEATURES \
+ ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
+ (0 << (VG_AMD_FEAT_NXP % 32)) | \
+ (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
+ (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
+ (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
+ (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
+ (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
+ /* Common bits between standard features and AMD features */ \
+ (1 << VG_X86_FEAT_FPU) | \
+ (1 << VG_X86_FEAT_VME) | \
+ (1 << VG_X86_FEAT_DE) | \
+ (1 << VG_X86_FEAT_PSE) | \
+ (1 << VG_X86_FEAT_TSC) | \
+ (0 << VG_X86_FEAT_MSR) | \
+ (1 << VG_X86_FEAT_PAE) | \
+ (1 << VG_X86_FEAT_MCE) | \
+ (1 << VG_X86_FEAT_CX8) | \
+ (1 << VG_X86_FEAT_APIC) | \
+ (1 << VG_X86_FEAT_MTRR) | \
+ (1 << VG_X86_FEAT_PGE) | \
+ (1 << VG_X86_FEAT_MCA) | \
+ (1 << VG_X86_FEAT_CMOV) | \
+ (1 << VG_X86_FEAT_PAT) | \
+ (1 << VG_X86_FEAT_PSE36) | \
+ (1 << VG_X86_FEAT_MMX) | \
+ (1 << VG_X86_FEAT_FXSR))
+
+
+/*
+ For simulating the cpuid instruction, we will
+ issue a "real" cpuid instruction and then mask out
+ the bits of the features we do not support currently (3dnow mostly).
+ We also claim to not support most CPUID operations.
+
+ Dirk Mueller <mueller@kde.org>
+
+ http://www.sandpile.org/ia32/cpuid.htm
+
+ references:
+
+ pre-MMX pentium:
+
+ <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
+ <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
+
+ Updated to be more extensible about future vendor extensions and
+ vendor-specific parts of CPUID.
+*/
+void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
+{
+ UInt eax, ebx, ecx, edx;
+
+ if (cpuid_level == -2)
+ get_cpu_features(); /* for cpu_vendor */
+
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+
+ /* Common mangling */
+ switch(op) {
+ case 1:
+ edx &= VG_X86_SUPPORTED_FEATURES;
+ break;
+
+ case 0xd8000000: {
+ /* Implement some private information at 0xd8000000 */
+ static const Char valgrind_vendor[] = "ValgrindVCPU";
+
+ eax = 0xd8000000; /* max request */
+ ebx = *(UInt *)&valgrind_vendor[0];
+ ecx = *(UInt *)&valgrind_vendor[8];
+ edx = *(UInt *)&valgrind_vendor[4];
+ }
+ break;
+ }
+
+ /* Vendor-specific mangling of the results */
+ switch(cpu_vendor) {
+ case VG_CPU_VENDOR_INTEL:
+ switch(op) {
+ case 1:
+ ecx = 0; /* mask out all extended features for now */
+ break;
+
+ case 0x80000001:
+ ebx = ecx = edx = 0;
+ break;
+ }
+ break;
+
+ case VG_CPU_VENDOR_AMD:
+ switch(op) {
+ case 0x80000001:
+ edx &= VG_AMD_SUPPORTED_FEATURES;
+ break;
+ }
+ break;
+ }
+
+ *eax_ret = eax;
+ *ebx_ret = ebx;
+ *ecx_ret = ecx;
+ *edx_ret = edx;
+}
+
+
/*------------------------------------------------------------*/
/*--- Here so it can be inlined everywhere. ---*/
/*------------------------------------------------------------*/