#include #include #define TCL_OK 0 #define TCL_ERROR 1 // // From tclWin32Dll.c // /* *------------------------------------------------------------------------ * * TclWinCPUID -- * * Get CPU ID information on an Intel box under Windows * * Results: * Returns TCL_OK if successful, TCL_ERROR if CPUID is not supported or * fails. * * Side effects: * If successful, stores EAX, EBX, ECX and EDX registers after the CPUID * instruction in the four integers designated by 'regsPtr' * *---------------------------------------------------------------------- */ int TclWinCPUID( unsigned int index, /* Which CPUID value to retrieve. */ unsigned int *regsPtr) /* Registers after the CPUID. */ { #ifdef HAVE_NO_SEH EXCEPTION_REGISTRATION registration; #endif int status = TCL_ERROR; #if defined(__GNUC__) && !defined(_WIN64) /* * Execute the CPUID instruction with the given index, and store results * off 'regPtr'. */ __asm__ __volatile__( /* * Construct an EXCEPTION_REGISTRATION to protect the CPUID * instruction (early 486's don't have CPUID) */ "leal %[registration], %%edx" "\n\t" "movl %%fs:0, %%eax" "\n\t" "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ "leal 1f, %%eax" "\n\t" "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ "movl %[error], 0x10(%%edx)" "\n\t" /* status */ /* * Link the EXCEPTION_REGISTRATION on the chain */ "movl %%edx, %%fs:0" "\n\t" /* * Do the CPUID instruction, and save the results in the 'regsPtr' * area. */ "movl %[rptr], %%edi" "\n\t" "movl %[index], %%eax" "\n\t" "cpuid" "\n\t" "movl %%eax, 0x0(%%edi)" "\n\t" "movl %%ebx, 0x4(%%edi)" "\n\t" "movl %%ecx, 0x8(%%edi)" "\n\t" "movl %%edx, 0xc(%%edi)" "\n\t" /* * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION and * store a TCL_OK status. */ "movl %%fs:0, %%edx" "\n\t" "movl %[ok], %%eax" "\n\t" "movl %%eax, 0x10(%%edx)" "\n\t" "jmp 2f" "\n" /* * Come here on an exception. Get the EXCEPTION_REGISTRATION that we * previously put on the chain. */ "1:" "\t" "movl %%fs:0, %%edx" "\n\t" "movl 0x8(%%edx), %%edx" "\n\t" /* * Come here however we exited. Restore context from the * EXCEPTION_REGISTRATION in case the stack is unbalanced. */ "2:" "\t" "movl 0xc(%%edx), %%esp" "\n\t" "movl 0x8(%%edx), %%ebp" "\n\t" "movl 0x0(%%edx), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" : /* No outputs */ : [index] "m" (index), [rptr] "m" (regsPtr), [registration] "m" (registration), [ok] "i" (TCL_OK), [error] "i" (TCL_ERROR) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); status = registration.status; #elif defined(_MSC_VER) && !defined(_WIN64) /* * Define a structure in the stack frame to hold the registers. */ _try { _asm { push ebx push ecx push edx mov eax, regs.dw0 cpuid mov regs.dw0, eax mov regs.dw1, ebx mov regs.dw2, ecx mov regs.dw3, edx pop edx pop ecx pop ebx } /* * Copy regs back out to the caller. */ regsPtr[0] = regs.dw0; regsPtr[1] = regs.dw1; regsPtr[2] = regs.dw2; regsPtr[3] = regs.dw3; status = TCL_OK; } __except(EXCEPTION_EXECUTE_HANDLER) { /* do nothing */ } #elif defined(__BORLANDC__) // Code from // http://groups.google.com/group/borland.public.cppbuilder.language/browse_thread/thread/b497c052f5554d96/6ae833b0f70b8e84?q=cpuid+OR+cpu-id+group:borland.public.cppbuilder*#6ae833b0f70b8e84 __asm { PUSH EBX // Save affected register PUSH EDI MOV EDI,regsPtr // destination MOV EAX,index DW 0xA20F // CPUID Command} STOSD // CPUID[1] MOV EAX,EBX STOSD // CPUID[2] MOV EAX,ECX STOSD // CPUID[3] MOV EAX,EDX STOSD // CPUID[4] POP EDI // Restore registers POP EBX } status = TCL_OK; #else /* * Don't know how to do assembly code for this compiler and/or * architecture. */ #endif return status; } // Adapted from tclWinTime.c int main(void) { unsigned int regs[5], tmp, res; LARGE_INTEGER frequ; // Show the counter's frequency if (! QueryPerformanceFrequency(&frequ)) { printf("No performance counter.\n"); } else { printf("Performance counter's frequency: %lu Hz.\n", frequ.QuadPart); } // Info for code '0' if (TclWinCPUID(0, regs) != TCL_OK) { printf("TclWinCPUID with code '0' failed.\n"); return 1; } // Show info: Have to re-arrange the content of 'regs' regs[4] = 0; // delimit string // swap regs[2] & regs[3] tmp = regs[2]; regs[2] = regs[3]; regs[3] = tmp; printf("Results of CPUID(0): %s\n", ®s[1]); res = (strcmp((const char *)®s[1], "GenuineIntel") == 0); printf("'performance counter available' (test part 1) (1 == ok)? %d\n", res); // Info for code '1' if (TclWinCPUID(1, regs) != TCL_OK) { printf("TclWinCPUID with code '1' failed.\n"); return 1; } // Apply the test from NativeGetTime (2nd part) /* Pentium 4 */ res = (regs[0]&0x00000F00) == 0x00000F00 /* Extended family Hyperthread */ || ((regs[0] & 0x00F00000) && (regs[3] & 0x10000000)); printf("Results of CPUID(1)\n"); printf("'performance counter available' (test part 2) (1 == ok)? %d\n", res); printf("Detailed results\n"); printf("regs[0] = 0x%08X, regs[1] = 0x%08X, regs[3] = 0x%08X\n", regs[0], regs[1], regs[3]); return 0; }