#include "precomp.h" #include #include #include "mperror.h" #include #define LEGACY_DIVISOR 8 extern "C" WORD _cdecl is_cyrix(void); extern "C" DWORD _cdecl get_nxcpu_type(void); #ifndef _M_IX86 DWORD WINAPI CallWithSEH(EXCEPTPROC pfn, void *pv, INEXCEPTION InException) { // we don't have a native version of SEH for the alpha, // use __try and __except pfn(pv); return 0; } #endif #ifdef _M_IX86 DWORD NMINTERNAL FindTSC (LPVOID pvRefData) { _asm { mov eax,1 _emit 00Fh ;; CPUID _emit 0A2h // The ref data is 2 DWORDS, the first is the flags, // the second the family mov ecx,pvRefData mov [ecx],edx mov [ecx][4],eax } return 1; } DWORD NMINTERNAL NoCPUID (LPEXCEPTION_RECORD per,PCONTEXT pctx) { return 0; } // // GetProcessorSpeed(dwFamily) // // get the processor speed in MHz, only works on Pentium or better // machines. // // Will put 3, or 4 in dwFamily for 386/486, but no speed. // returns speed and family for 586+ // // - thanks to toddla, modified by mikeg // int NMINTERNAL GetProcessorSpeed(int *pdwFamily) { SYSTEM_INFO si; __int64 start, end, freq; int flags,family; int time; int clocks; DWORD oldclass; HANDLE hprocess; int pRef[2]; ZeroMemory(&si, sizeof(si)); GetSystemInfo(&si); //Set the family. If wProcessorLevel is not specified, dig it out of dwProcessorType //Because wProcessor level is not implemented on Win95 if (si.wProcessorLevel) { *pdwFamily=si.wProcessorLevel; }else { //Ok, we're on Win95 switch (si.dwProcessorType) { case PROCESSOR_INTEL_386: *pdwFamily=3; break; case PROCESSOR_INTEL_486: *pdwFamily=4; break; default: *pdwFamily=0; break; } } // // make sure this is a INTEL Pentium (or clone) or higher. // if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) return 0; if (si.dwProcessorType < PROCESSOR_INTEL_PENTIUM) return 0; // // see if this chip supports rdtsc before using it. // if (!CallWithSEH (FindTSC, pRef, NoCPUID)) { flags=0; } else { // The ref data is 2 DWORDS, the first is the flags, // the second the family. Pull them out and use them flags=pRef[0]; family=pRef[1]; } if (!(flags & 0x10)) return 0; //If we don't have a family, set it now //Family is bits 11:8 of eax from CPU, with eax=1 if (!(*pdwFamily)) { *pdwFamily=(family& 0x0F00) >> 8; } hprocess = GetCurrentProcess(); oldclass = GetPriorityClass(hprocess); SetPriorityClass(hprocess, REALTIME_PRIORITY_CLASS); Sleep(10); QueryPerformanceFrequency((LARGE_INTEGER*)&freq); QueryPerformanceCounter((LARGE_INTEGER*)&start); _asm { _emit 0Fh ;; RDTSC _emit 31h mov ecx,100000 x: dec ecx jnz x mov ebx,eax _emit 0Fh ;; RDTSC _emit 31h sub eax,ebx mov dword ptr clocks[0],eax } QueryPerformanceCounter((LARGE_INTEGER*)&end); SetPriorityClass(hprocess, oldclass); time = MulDiv((int)(end-start),1000000,(int)freq); return (clocks + time/2) / time; } HRESULT NMINTERNAL GetNormalizedCPUSpeed (int *pdwNormalizedSpeed, int *dwFamily) { int dwProcessorSpeed; dwProcessorSpeed=GetProcessorSpeed (dwFamily); *pdwNormalizedSpeed=dwProcessorSpeed; if (*dwFamily > 5) { //Ok, TWO things. // ONE DO NOT DO FP! // Two for the same Mhz assume a 686 is 1.3 times as fast as a 586 and a 786 is 1.6 times, etc. *pdwNormalizedSpeed=(ULONG) (((10+3*(*dwFamily-5))*dwProcessorSpeed)/10); } if (*dwFamily < 5) { //bugbug until we have 386/486 timing code, assume //486=50,386=37 if (*dwFamily > 3) { //Cyrix, (5x86)? check before making default assignment if (is_cyrix()) { if (*pdwNormalizedSpeed==0) { *dwFamily=5; *pdwNormalizedSpeed=100; return hrSuccess; } } } *pdwNormalizedSpeed= (*dwFamily*100)/LEGACY_DIVISOR; if (get_nxcpu_type ()) { //Double the perceived value on a NexGen *pdwNormalizedSpeed *=2; } } return hrSuccess; } #endif //_M_IX86 BOOL WINAPI IsFloatingPointEmulated(void) { long lRegValue; SYSTEM_INFO si; OSVERSIONINFO osi; BOOL fEmulation, bNT; // are we a Pentium ZeroMemory(&si, sizeof(si)); GetSystemInfo(&si); if (si.dwProcessorType != PROCESSOR_INTEL_PENTIUM) { return FALSE; } // Which OS: NT or 95 ? ZeroMemory(&osi, sizeof(osi)); osi.dwOSVersionInfoSize = sizeof(osi); GetVersionEx(&osi); bNT = (osi.dwPlatformId == VER_PLATFORM_WIN32_NT); // Windows NT if (bNT) { RegEntry re(TEXT("System\\CurrentControlSet\\Control\\Session Manager"), HKEY_LOCAL_MACHINE, FALSE); // try to get a definitive answer from the registry lRegValue = re.GetNumber(TEXT("ForceNpxEmulation"), -1); // registry: 0: no // 1: conditional (not definitive!) // 2: yes if (lRegValue == 2) { return TRUE; } // we could load "IsProcessorFeaturePresent from kernel32.dll, // but the version that shipped with NT 4 has a bug in it that // returns the exact opposite of what it should be. It was // fixed in NT 5. Since this API isn't the same across platforms, // we won't use it. return FALSE; } // Windows 95 - to be added later return FALSE; }