919 lines
28 KiB
C
919 lines
28 KiB
C
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cpuid.c
|
|
|
|
Abstract:
|
|
|
|
Originally written to test the fix to an OS bug but indended to be
|
|
expanded as time allows to dump out as much useful stuff as we can.
|
|
|
|
Author:
|
|
|
|
Peter L Johnston (peterj) July 14, 1999.
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <winbase.h>
|
|
|
|
#if defined(_X86_)
|
|
|
|
typedef enum {
|
|
CPU_NONE,
|
|
CPU_INTEL,
|
|
CPU_AMD,
|
|
CPU_CYRIX,
|
|
CPU_UNKNOWN
|
|
} CPU_VENDORS;
|
|
|
|
|
|
PUCHAR FeatureBitDescription[] = {
|
|
/* 0 */ "FPU 387 (Floating Point) instructions",
|
|
/* 1 */ "VME Virtual 8086 Mode Enhancements",
|
|
/* 2 */ "DE Debugging Extensions",
|
|
/* 3 */ "PSE Page Size Extensions (4MB pages)",
|
|
/* 4 */ "TSC Time Stamp Counter",
|
|
/* 5 */ "MSR Model Specific Registers (RDMSR/WRMSR)",
|
|
/* 6 */ "PAE Physical Address Extension (> 32 bit physical addressing)",
|
|
/* 7 */ "MCE Machine Check Exception",
|
|
/* 8 */ "CX8 CMPXCHG8B (compare and exchange 8 byte)",
|
|
/* 9 */ "APIC Advanced Programmable Interrupt Controller",
|
|
/* 10 */ "Reserved",
|
|
/* 11 */ "SEP Fast System Call (SYSENTER/SYSEXIT)",
|
|
/* 12 */ "MTRR Memory Type Range Registers",
|
|
/* 13 */ "PGE PTE Global Flag",
|
|
/* 14 */ "MCA Machine Check Architecture",
|
|
/* 15 */ "CMOV Conditional Move and Compare",
|
|
/* 16 */ "PAT Page Attribute Table",
|
|
/* 17 */ "PSE36 4MB pages can have 36 bit physical addresses",
|
|
/* 18 */ "PN 96 bit Processor Number",
|
|
/* 19 */ "CLFLSH Cache Line Flush",
|
|
/* 20 */ "Reserved",
|
|
/* 21 */ "DTS Debug Trace Store",
|
|
/* 22 */ "ACPI ACPI Thermal Throttle Registers",
|
|
/* 23 */ "MMX Multi Media eXtensions",
|
|
/* 24 */ "FXSR Fast Save/Restore (FXSAVE/FXRSTOR)",
|
|
/* 25 */ "XMM Streaming Simd Extensions",
|
|
/* 26 */ "WNI Willamette New Instructions",
|
|
/* 27 */ "SLFSNP Self Snoop",
|
|
/* 28 */ "JT Jackson Technology (SMT)",
|
|
/* 29 */ "ATHROT Automatic Thermal Throttle",
|
|
/* 30 */ "IA64 64 Bit Intel Architecture",
|
|
/* 31 */ "Reserved"
|
|
};
|
|
|
|
|
|
PUCHAR AMDExtendedFeatureBitDescription[] = {
|
|
/* 0 */ "FPU 387 (Floating Point) instructions",
|
|
/* 1 */ "VME Virtual 8086 Mode Enhancements",
|
|
/* 2 */ "DE Debugging Extensions",
|
|
/* 3 */ "PSE Page Size Extensions (4MB pages)",
|
|
/* 4 */ "TSC Time Stamp Counter",
|
|
/* 5 */ "MSR Model Specific Registers (RDMSR/WRMSR)",
|
|
/* 6 */ "PAE Physical Address Extension (> 32 bit physical addressing)",
|
|
/* 7 */ "MCE Machine Check Exception",
|
|
/* 8 */ "CX8 CMPXCHG8B (compare and exchange 8 byte)",
|
|
/* 9 */ "APIC Advanced Programmable Interrupt Controller",
|
|
/* 10 */ "Reserved",
|
|
/* 11 */ " SYSCALL and SYSRET Instructions",
|
|
/* 12 */ "MTRR Memory Type Range Registers",
|
|
/* 13 */ "PGE PTE Global Flag",
|
|
/* 14 */ "MCA Machine Check Architecture",
|
|
/* 15 */ "CMOV Conditional Move and Compare",
|
|
/* 16 */ "PAT Page Attribute Table",
|
|
/* 17 */ "PSE36 4MB pages can have 36 bit physical addresses",
|
|
/* 18 */ "Reserved",
|
|
/* 19 */ "Reserved",
|
|
/* 20 */ "Reserved",
|
|
/* 21 */ "Reserved",
|
|
/* 22 */ " AMD MMX Instruction Extensions",
|
|
/* 23 */ "MMX Multi Media eXtensions",
|
|
/* 24 */ "FXSR Fast Save/Restore (FXSAVE/FXRSTOR)",
|
|
/* 25 */ "Reserved",
|
|
/* 26 */ "Reserved",
|
|
/* 27 */ "Reserved",
|
|
/* 28 */ "Reserved",
|
|
/* 29 */ "Reserved",
|
|
/* 30 */ " AMD 3DNow! Instruction Extensions",
|
|
/* 31 */ " 3DNow! Instructions",
|
|
};
|
|
|
|
PUCHAR BrandIndex[] = {
|
|
"Intel Celeron",
|
|
"Intel Pentium III",
|
|
"Intel Pentium III XEON",
|
|
"Reserved for future"
|
|
"Reserved for future"
|
|
"Reserved for future"
|
|
"Reserved for future"
|
|
"Reserved for future"
|
|
"Intel Pentium 4"
|
|
};
|
|
|
|
VOID
|
|
ExecuteCpuidFunction(
|
|
IN ULONG Function,
|
|
OUT PULONG Results
|
|
);
|
|
|
|
BOOLEAN
|
|
IsCpuidPresent(
|
|
VOID
|
|
);
|
|
|
|
PUCHAR
|
|
AMD_Associativity(
|
|
ULONG Descriptor
|
|
)
|
|
{
|
|
switch (Descriptor) {
|
|
case 0x0: return"L2 Off";
|
|
case 0x1: return"Direct";
|
|
case 0x2: return" 2 way";
|
|
case 0x4: return" 4 way";
|
|
case 0x6: return" 8 way";
|
|
case 0x8: return"16 way";
|
|
case 0xff: return" Full";
|
|
default:
|
|
return"Reserved";
|
|
}
|
|
}
|
|
VOID
|
|
AMD_DI_TLB(
|
|
ULONG Format,
|
|
ULONG TLBDesc
|
|
)
|
|
{
|
|
UCHAR Which = 'D';
|
|
ULONG AssocIndex;
|
|
ULONG Entries;
|
|
|
|
if ((TLBDesc >> 16) == 0) {
|
|
|
|
//
|
|
// Unified.
|
|
//
|
|
|
|
TLBDesc <<= 16;
|
|
Which = ' ';
|
|
}
|
|
do {
|
|
if (Format == 1) {
|
|
AssocIndex = TLBDesc >> 24;
|
|
Entries = (TLBDesc >> 16) & 0xff;
|
|
} else {
|
|
AssocIndex = TLBDesc >> 28;
|
|
Entries = (TLBDesc >> 16) & 0xfff;
|
|
}
|
|
printf(" %8s %4d entry %cTLB",
|
|
AMD_Associativity(AssocIndex),
|
|
Entries,
|
|
Which
|
|
);
|
|
|
|
//
|
|
// Repeat for lower half of descriptor.
|
|
//
|
|
|
|
TLBDesc <<= 16;
|
|
Which = 'I';
|
|
} while (TLBDesc);
|
|
printf("\n");
|
|
}
|
|
VOID
|
|
AMD_Cache(
|
|
ULONG Format,
|
|
ULONG CacheDesc
|
|
)
|
|
{
|
|
ULONG Size;
|
|
ULONG AssocIndex;
|
|
ULONG LinesPerTag;
|
|
ULONG LineSize;
|
|
|
|
if (Format == 1) {
|
|
Size = CacheDesc >> 24;
|
|
AssocIndex = (CacheDesc >> 16) & 0xff;
|
|
LinesPerTag = (CacheDesc >> 8) & 0xff;
|
|
LineSize = CacheDesc & 0xff;
|
|
} else {
|
|
Size = CacheDesc >> 16;
|
|
AssocIndex = (CacheDesc >> 12) & 0xf;
|
|
LinesPerTag = (CacheDesc >> 8) & 0xf;
|
|
LineSize = CacheDesc & 0xff;
|
|
}
|
|
printf(" %8s %5dKB (%d L/T)%3d bytes per line.\n",
|
|
AMD_Associativity(AssocIndex),
|
|
Size,
|
|
LinesPerTag,
|
|
LineSize
|
|
);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(_IA64_)
|
|
|
|
ULONGLONG
|
|
ia64CPUID(
|
|
ULONGLONG Index
|
|
);
|
|
|
|
#endif
|
|
|
|
__cdecl
|
|
main(
|
|
LONG Argc,
|
|
PUCHAR *Argv
|
|
)
|
|
{
|
|
ULONG Processor;
|
|
ULONG Function;
|
|
ULONG MaxFunction;
|
|
ULONG Temp;
|
|
ULONG Temp2, Bit;
|
|
HANDLE ProcessHandle;
|
|
HANDLE ThreadHandle;
|
|
|
|
#if defined(_X86_)
|
|
|
|
ULONG Results[5];
|
|
ULONG Family = 0;
|
|
ULONG Model = 0;
|
|
ULONG Stepping = 0;
|
|
ULONG Generation = 0;
|
|
BOOLEAN CpuidPresent;
|
|
CPU_VENDORS Vendor = CPU_NONE;
|
|
ULONG ThreadAffinity;
|
|
ULONG SystemAffinity;
|
|
ULONG ProcessAffinity;
|
|
|
|
#endif
|
|
|
|
#if defined(_IA64_)
|
|
|
|
ULONGLONG Result;
|
|
ULONGLONG ThreadAffinity;
|
|
ULONGLONG SystemAffinity;
|
|
ULONGLONG ProcessAffinity;
|
|
ULONGLONG VendorInformation[3];
|
|
|
|
#endif
|
|
|
|
//
|
|
// Make sure this process is set to run on any processor in
|
|
// the system.
|
|
//
|
|
|
|
ProcessHandle = GetCurrentProcess();
|
|
ThreadHandle = GetCurrentThread();
|
|
|
|
if (!GetProcessAffinityMask(ProcessHandle,
|
|
&ProcessAffinity,
|
|
&SystemAffinity)) {
|
|
printf("Fatal error: Unable to determine process affinity.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (ProcessAffinity != SystemAffinity) {
|
|
|
|
if (!SetProcessAffinityMask(ProcessHandle,
|
|
SystemAffinity)) {
|
|
printf("Warning: Unable to run on all processors\n");
|
|
printf(" System Affinity %08x\n", SystemAffinity);
|
|
printf(" - Process Affinity %08x\n", ProcessAffinity);
|
|
printf(" Will Try %08x\n",
|
|
SystemAffinity & ProcessAffinity);
|
|
SystemAffinity &= ProcessAffinity;
|
|
}
|
|
ProcessAffinity = SystemAffinity;
|
|
}
|
|
|
|
#if defined(_X86_)
|
|
|
|
//
|
|
// Cpuid returns 4 DWORDs of data. In some cases this is string
|
|
// data in which case it needs to be NULL terminated.
|
|
//
|
|
|
|
Results[4] = 0;
|
|
|
|
#endif
|
|
|
|
//
|
|
// For each CPU in the system, determine the availability of
|
|
// the CPUID instruction and dump out anything useful it might
|
|
// have to say.
|
|
//
|
|
|
|
for (ThreadAffinity = 1, Processor = 0;
|
|
ThreadAffinity;
|
|
ThreadAffinity <<= 1, Processor++) {
|
|
if (!(ThreadAffinity & ProcessAffinity)) {
|
|
|
|
//
|
|
// Can't test this processor.
|
|
//
|
|
|
|
if (ThreadAffinity > ProcessAffinity) {
|
|
|
|
//
|
|
// Tested all the processors there are, we're done.
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Set affinity so this thread can only run on the processor
|
|
// being tested.
|
|
//
|
|
|
|
if (!SetThreadAffinityMask(ThreadHandle,
|
|
ThreadAffinity)) {
|
|
|
|
printf(
|
|
"** Could not set affinity %08x for processor %d, skipping.\n",
|
|
ThreadAffinity,
|
|
Processor);
|
|
continue;
|
|
}
|
|
|
|
#if defined(_X86_)
|
|
|
|
CpuidPresent = IsCpuidPresent();
|
|
if (CpuidPresent) {
|
|
printf("++ Processor %d\n", Processor);
|
|
} else {
|
|
printf("-- No CPUID support, processor %d\n", Processor);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// CPUID is present, examine basic functions.
|
|
//
|
|
|
|
ExecuteCpuidFunction(0, Results);
|
|
|
|
MaxFunction = Results[0];
|
|
|
|
|
|
//
|
|
// For reasons unclear to anyone, the Vendor ID string comes
|
|
// back in the order EBX, EDX, ECX,... so switch the last two
|
|
// results before printing it.
|
|
//
|
|
|
|
Temp = Results[3];
|
|
Results[3] = Results[2];
|
|
Results[2] = Temp;
|
|
|
|
if (strcmp((PVOID)&Results[1], "GenuineIntel") == 0) {
|
|
Vendor = CPU_INTEL;
|
|
} else if (strcmp((PVOID)&Results[1], "AuthenticAMD") == 0) {
|
|
Vendor = CPU_AMD;
|
|
} else if (strcmp((PVOID)&Results[1], "CyrixInstead") == 0) {
|
|
Vendor = CPU_CYRIX;
|
|
} else {
|
|
Vendor = CPU_UNKNOWN;
|
|
}
|
|
|
|
printf(" Vendor ID '%s', Maximum Supported Function %d.\n",
|
|
(PUCHAR)(&Results[1]),
|
|
MaxFunction);
|
|
|
|
for (Function = 0; Function <= MaxFunction; Function++) {
|
|
ExecuteCpuidFunction(Function, Results);
|
|
printf(" F %d raw = %08x %08x %08x %08x\n",
|
|
Function,
|
|
Results[0],
|
|
Results[1],
|
|
Results[2],
|
|
Results[3]);
|
|
//
|
|
// Do some interpretation on the ones we know how to
|
|
// deal with.
|
|
//
|
|
|
|
switch(Function) {
|
|
case 0:
|
|
|
|
//
|
|
// Already handled as the main header (gave max func
|
|
// and Vendor ID.
|
|
//
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
//
|
|
// EAX = Type, Family, Model, Stepping.
|
|
// EBX = Family != 0xf ?
|
|
// Yes = Reserved,
|
|
// No = 0xAABBCCDD where
|
|
// AA = APIC ID
|
|
// BB = LP per PP
|
|
// CC = CLFLUSH line size (8 = 64 bytes)
|
|
// DD = Brand Index
|
|
// ECX = Reserved
|
|
// EDX = Feature Bits
|
|
//
|
|
|
|
//
|
|
// Family Model Stepping
|
|
//
|
|
|
|
Temp = Results[0];
|
|
Family = (Temp >> 8) & 0xf;
|
|
Model = (Temp >> 4) & 0xf;
|
|
Stepping = Temp & 0xf;
|
|
printf(" Type = %d, Family = %d, Model = %d, Stepping = %d\n",
|
|
(Temp >> 12) & 0x3, Family, Model, Stepping);
|
|
|
|
//
|
|
// Willamette stuff
|
|
//
|
|
|
|
if ((Temp & 0xf00) == 0xf00) {
|
|
Temp = Results[1] & 0xff;
|
|
if (Temp) {
|
|
|
|
//
|
|
// Indexes are a DISGUSTING way to get this info!!
|
|
//
|
|
|
|
printf(" Brand Index %02x %s processor\n",
|
|
Temp,
|
|
Temp < (sizeof(BrandIndex) / sizeof(PUCHAR)) ?
|
|
BrandIndex[Temp-1] :
|
|
BrandIndex[(sizeof(BrandIndex) / sizeof(PUCHAR)) -1]);
|
|
}
|
|
Temp = (Results[1] >> 8) & 0xff;
|
|
printf(" CLFLUSH line size (%x) = %d bytes\n",
|
|
Temp,
|
|
Temp << 3); // ?? plj - nobasis
|
|
Temp = Results[1] >> 16;
|
|
printf(" LP per PP %d\n", Temp & 0xff);
|
|
printf(" APIC Id %02x\n", Temp >> 8);
|
|
}
|
|
|
|
//
|
|
// Feature bits.
|
|
//
|
|
|
|
Temp = Results[3];
|
|
if (Temp) {
|
|
printf(" Features\n");
|
|
for (Bit = 0, Temp2 = 1;
|
|
Temp;
|
|
Bit++, Temp2 <<= 1) {
|
|
|
|
if ((Temp2 & Temp) == 0) {
|
|
|
|
//
|
|
// Feature bit not set.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
Temp ^= Temp2;
|
|
printf(" %08x %s\n",
|
|
Temp2,
|
|
FeatureBitDescription[Bit]);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
|
|
//
|
|
// Get number of times we have to do function 2 again.
|
|
// (Then replace iteration count with a NULL descr).
|
|
//
|
|
|
|
Temp = Results[0] & 0xff;
|
|
|
|
if (Temp == 0) {
|
|
|
|
//
|
|
// If the count is 0, this processor doesn't do
|
|
// function 2, get out.
|
|
//
|
|
|
|
break;
|
|
}
|
|
Results[0] &= 0xffffff00;
|
|
|
|
do {
|
|
ULONG i;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
Temp2 = Results[i];
|
|
|
|
if (Temp2 & 0x80000000) {
|
|
|
|
//
|
|
// Not valid, skip.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
while (Temp2) {
|
|
|
|
UCHAR Descriptor = (UCHAR)(Temp2 & 0xff);
|
|
ULONG K, Way, Line, Level;
|
|
PUCHAR IorD = "";
|
|
|
|
Temp2 >>= 8;
|
|
|
|
if (((Descriptor > 0x40) && (Descriptor <= 0x47)) ||
|
|
((Descriptor > 0x78) && (Descriptor <= 0x7c)) ||
|
|
((Descriptor > 0x80) && (Descriptor <= 0x87))) {
|
|
|
|
//
|
|
// It's an L2 Descriptor. (The following
|
|
// is peterj's wacky formula,... not
|
|
// guaranteed forever but the nice people
|
|
// at Intel better pray I'm dead before
|
|
// they break it or I'll hunt them down).
|
|
//
|
|
|
|
Level = 2;
|
|
Way = Descriptor >= 0x79 ? 8 : 4;
|
|
K = 0x40 << (Descriptor & 0x7);
|
|
Line = 32;
|
|
if ((Descriptor & 0xf8) == 0x78) {
|
|
Line = 128;
|
|
}
|
|
} else if ((Descriptor >= 0x50) &&
|
|
(Descriptor <= 0x5d)) {
|
|
if (Descriptor & 0x8) {
|
|
IorD = "D";
|
|
K = 0x40 << (Descriptor - 0x5b);
|
|
} else {
|
|
IorD = "I";
|
|
K = 0x40 << (Descriptor - 0x50);
|
|
}
|
|
printf(" %02xH %sTLB %d entry\n",
|
|
Descriptor,
|
|
IorD,
|
|
K);
|
|
continue;
|
|
} else {
|
|
PUCHAR s = NULL;
|
|
switch (Descriptor) {
|
|
case 0x00:
|
|
continue;
|
|
case 0x01:
|
|
s = "ITLB 4KB pages, 4 way, 32 entry";
|
|
break;
|
|
case 0x02:
|
|
s = "ITLB 4MB pages, fully assoc, 2 entry";
|
|
break;
|
|
case 0x03:
|
|
s = "DTLB 4KB pages, 4 way, 64 entry";
|
|
break;
|
|
case 0x04:
|
|
s = "DTLB 4MB pages, 4 way, 8 entry";
|
|
break;
|
|
case 0x06:
|
|
s = "I-Cache 8KB, 4 way, 32B line";
|
|
break;
|
|
case 0x08:
|
|
s = "I-Cache 16KB, 4 way, 32B line";
|
|
break;
|
|
case 0x0a:
|
|
s = "D-Cache 8KB, 2 way, 32B line";
|
|
break;
|
|
case 0x0c:
|
|
s = "D-Cache 16KB, 2 or 4 way, 32B line";
|
|
break;
|
|
case 0x22:
|
|
K = 512; Level = 3; Way = 4; Line = 128;
|
|
break;
|
|
case 0x23:
|
|
K = 1024; Level = 3; Way = 8; Line = 128;
|
|
break;
|
|
case 0x25:
|
|
K = 2048; Level = 3; Way = 8; Line = 128;
|
|
break;
|
|
case 0x29:
|
|
K = 4096; Level = 3; Way = 8; Line = 128;
|
|
break;
|
|
case 0x40:
|
|
s = "No L3 Cache";
|
|
break;
|
|
case 0x66:
|
|
K = 8; Level = 1; Way = 4; Line = 64; IorD = "D";
|
|
break;
|
|
case 0x67:
|
|
K = 16; Level = 1; Way = 4; Line = 64; IorD = "D";
|
|
break;
|
|
case 0x68:
|
|
K = 32; Level = 1; Way = 4; Line = 64; IorD = "D";
|
|
break;
|
|
case 0x70:
|
|
K = 12; Level = 1; Way = 8; Line = 64; IorD = "I";
|
|
break;
|
|
case 0x71:
|
|
K = 16; Level = 1; Way = 8; Line = 64; IorD = "I";
|
|
break;
|
|
case 0x72:
|
|
K = 32; Level = 1; Way = 8; Line = 64; IorD = "I";
|
|
break;
|
|
case 0x80:
|
|
s = "No L2 Cache";
|
|
break;
|
|
default:
|
|
s = "Unknown Descriptor";
|
|
}
|
|
if (s) {
|
|
printf(" %02xH %s.\n", Descriptor, s);
|
|
continue;
|
|
}
|
|
}
|
|
printf(" %02xH L%d %sCache %dKB, %d way, %dB line\n",
|
|
Descriptor,
|
|
Level,
|
|
IorD,
|
|
K,
|
|
Way,
|
|
Line);
|
|
} // while more bytes in this register
|
|
} // for each register
|
|
|
|
//
|
|
// If more iterations,...
|
|
//
|
|
|
|
if (--Temp == 0) {
|
|
break;
|
|
}
|
|
|
|
ExecuteCpuidFunction(2, Results);
|
|
printf(" F %d raw = %08x %08x %08x %08x\n",
|
|
2,
|
|
Results[0],
|
|
Results[1],
|
|
Results[2],
|
|
Results[3]);
|
|
} while (TRUE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Examine extended functions.
|
|
//
|
|
|
|
ExecuteCpuidFunction(0x80000000, Results);
|
|
|
|
MaxFunction = Results[0];
|
|
|
|
//
|
|
// Ok, function numbers > MaxFunction (the basic one) by
|
|
// definition return undefined results. But, we are told
|
|
// that if extended functions are not supported, the return
|
|
// value for 0x80000000 will never have the top bit set.
|
|
//
|
|
|
|
if ((MaxFunction & 0x80000000) == 0) {
|
|
printf(" This processor does not support Extended CPUID functions.\n");
|
|
continue;
|
|
}
|
|
|
|
printf(" Maximum Supported Extended Function 0x%x.\n",
|
|
MaxFunction);
|
|
|
|
for (Function = 0x80000000; Function <= MaxFunction; Function++) {
|
|
ExecuteCpuidFunction(Function, Results);
|
|
printf(" F 0x%08x raw = %08x %08x %08x %08x\n",
|
|
Function,
|
|
Results[0],
|
|
Results[1],
|
|
Results[2],
|
|
Results[3]);
|
|
switch (Function) {
|
|
case 0x80000000:
|
|
break;
|
|
|
|
case 0x80000001:
|
|
|
|
if (Vendor == CPU_AMD) {
|
|
//
|
|
// EAX = Generation, Model, Stepping.
|
|
// EBX = Reserved
|
|
// ECX = Reserved
|
|
// EDX = Feature Bits
|
|
//
|
|
|
|
//
|
|
// Generation Model Stepping
|
|
//
|
|
|
|
Temp = Results[0];
|
|
Generation = (Temp >> 8) & 0xf;
|
|
Model = (Temp >> 4) & 0xf;
|
|
Stepping = Temp & 0xf;
|
|
printf(" Generation = %d, Model = %d, Stepping = %d\n",
|
|
Generation, Model, Stepping);
|
|
|
|
//
|
|
// Feature bits.
|
|
//
|
|
|
|
Temp = Results[3];
|
|
if (Temp) {
|
|
printf(" Features\n");
|
|
for (Bit = 0, Temp2 = 1;
|
|
Temp;
|
|
Bit++, Temp2 <<= 1) {
|
|
|
|
if ((Temp2 & Temp) == 0) {
|
|
|
|
//
|
|
// Feature bit not set.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
Temp ^= Temp2;
|
|
printf(" %08x %s\n",
|
|
Temp2,
|
|
AMDExtendedFeatureBitDescription[Bit]);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x80000002:
|
|
|
|
Temp2 = 1;
|
|
|
|
case 0x80000003:
|
|
|
|
Temp2++;
|
|
|
|
case 0x80000004:
|
|
|
|
Temp2++;
|
|
|
|
printf(" Processor Name[%2d-%2d] = '%s'\n",
|
|
49 - (Temp2 * 16),
|
|
64 - (Temp2 * 16),
|
|
Results);
|
|
Temp2 = 0;
|
|
break;
|
|
|
|
case 0x80000005:
|
|
|
|
if (Vendor == CPU_AMD) {
|
|
|
|
if (Family == 6) {
|
|
|
|
//
|
|
// Athlon.
|
|
//
|
|
|
|
printf(" Large Page TLBs :");
|
|
AMD_DI_TLB(1, Results[0]);
|
|
|
|
} else if (Family > 6) {
|
|
printf(" Family %d is a new AMD family which this program doesn't know about.\n");
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Common to K5, K6 and Athlon
|
|
//
|
|
|
|
printf(" 4KB Page TLBs :");
|
|
AMD_DI_TLB(1, Results[1]);
|
|
printf(" L1 D-Cache :");
|
|
AMD_Cache(1, Results[2]);
|
|
printf(" L1 I-Cache :");
|
|
AMD_Cache(1, Results[3]);
|
|
}
|
|
break;
|
|
|
|
case 0x80000006:
|
|
|
|
if (Vendor == CPU_AMD) {
|
|
|
|
if (Family == 6) {
|
|
|
|
//
|
|
// Athlon.
|
|
//
|
|
|
|
if (Results[0]) {
|
|
printf(" Large Page L2 TLB :");
|
|
AMD_DI_TLB(2, Results[0]);
|
|
}
|
|
if (Results[1]) {
|
|
printf(" 4KB Page L2 TLB :");
|
|
AMD_DI_TLB(2, Results[1]);
|
|
}
|
|
if ((Model == 3) && (Stepping == 0)) {
|
|
Results[2] &= 0xffff;
|
|
Results[2] |= 0x400000;
|
|
}
|
|
} else if (Family > 6) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Common to K5, K6 and Athlon
|
|
//
|
|
|
|
printf(" L2 Cache :");
|
|
AMD_Cache(2, Results[2]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(_IA64_)
|
|
|
|
printf("++ Processor %d\n", Processor);
|
|
|
|
//
|
|
// On IA64, cpuid is implemented as a set of 64 bit registers.
|
|
// Registers
|
|
// 0 and 1 contain the Vendor Information.
|
|
// 2 contains 0.
|
|
// 3 most significant 24 bits are reserved, the low 5 bytes
|
|
// contain-
|
|
// 39-32 archrev
|
|
// 31-24 family
|
|
// 23-16 model
|
|
// 15-08 revision
|
|
// 07-00 number index of largest implemented register
|
|
// 4 features
|
|
//
|
|
|
|
//
|
|
// Until we have read register 3, set 3 as the maximum number.
|
|
//
|
|
|
|
MaxFunction = 3;
|
|
|
|
for (Function = 0; Function <= MaxFunction; Function++) {
|
|
|
|
Result = ia64CPUID(Function);
|
|
|
|
printf(" F %d raw = %016I64x\n",
|
|
Function,
|
|
Result);
|
|
|
|
//
|
|
// Do some interpretation on the ones we know how to
|
|
// deal with.
|
|
//
|
|
|
|
switch(Function) {
|
|
case 0:
|
|
VendorInformation[0] = Result;
|
|
break;
|
|
case 1:
|
|
VendorInformation[1] = Result;
|
|
VendorInformation[2] = 0;
|
|
printf(" \"%s\"\n", (PUCHAR)VendorInformation);
|
|
break;
|
|
case 3:
|
|
printf(" Architecture Revision = %d, Family = %d, Model = %d, Revision = %d\n",
|
|
(Result >> 32) & 0xff,
|
|
(Result >> 24) & 0xff,
|
|
(Result >> 16) & 0xff,
|
|
(Result >> 8) & 0xff);
|
|
MaxFunction = (ULONG)Result & 0xff;
|
|
printf(" Maximum Supported Function %d.\n",
|
|
MaxFunction);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|