/* $Id: cpu.cpp,v 1.15 2004-02-20 10:05:39 sandervl Exp $ */ /* * Odin win32 CPU apis * * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl) * * Based on Wine Code (991031: misc\cpu.c) * * Copyright 1995,1997 Morten Welinder * Copyright 1997-1998 Marcus Meissner */ #include #include #include #include "winreg.h" #include "global.h" #include "winnt.h" #include "winerror.h" #include "winreg.h" #include "debugtools.h" #include #define DBG_LOCALLOG DBG_cpu #include "dbglocal.h" DEFAULT_DEBUG_CHANNEL(CPU) static BYTE PF[64] = {0,}; static int nrCPUs = 1; static SYSTEM_INFO cachedsi = {0}; //****************************************************************************** //****************************************************************************** void InitSystemInfo(int nrcpus) { SYSTEM_INFO si; nrCPUs = nrcpus; GetSystemInfo(&si); } /*********************************************************************** * GetSystemInfo [KERNELL32.404] * * Gets the current system information. * * On the first call it reads cached values, so it doesn't have to determine * them repeatedly. On Linux, the /proc/cpuinfo special file is used. * * It creates a registry subhierarchy, looking like: * \HARDWARE\DESCRIPTION\System\CentralProcessor\\ * Identifier (CPU x86) * Note that there is a hierarchy for every processor installed, so this * supports multiprocessor systems. This is done like Win95 does it, I think. * * It also creates a cached flag array for IsProcessorFeaturePresent(). * * RETURNS * nothing, really */ VOID WINAPI GetSystemInfo(LPSYSTEM_INFO si) /* [out] system information */ { HKEY xhkey=0,hkey; HKEY fpukey=0, xhfpukey; char buf[20]; DWORD features, signature; static int cache = 0; if(!si) { dprintf(("GetSystemInfo -> si == NULL!!")); SetLastError(ERROR_INVALID_PARAMETER); return; } if (cache) { memcpy(si,&cachedsi,sizeof(*si)); return; } memset(PF,0,sizeof(PF)); /* choose sensible defaults ... * FIXME: perhaps overrideable with precompiler flags? */ cachedsi.u.x.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL; cachedsi.dwPageSize = 4096; /* FIXME: better values for the two entries below... */ cachedsi.lpMinimumApplicationAddress = (void *)0x00400000; cachedsi.lpMaximumApplicationAddress = (void *)0x7FFFFFFF; cachedsi.dwActiveProcessorMask = 1; cachedsi.dwNumberOfProcessors = nrCPUs; cachedsi.dwProcessorType = PROCESSOR_INTEL_386; cachedsi.dwAllocationGranularity = 0x10000; cachedsi.wProcessorLevel = 3; /* 386 */ cachedsi.wProcessorRevision = 0; cache = 1; /* even if there is no more info, we now have a cacheentry */ memcpy(si,&cachedsi,sizeof(*si)); /* Hmm, reasonable processor feature defaults? */ /* Create this registry key for all systems */ if (RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey)!=ERROR_SUCCESS) { dprintf(("Unable to register CPU information\n")); } if(SupportsCPUID()) { for(int i=0;i> 8)&0xf) { case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386; break; case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486; break; case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; break; case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; break; default: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; break; } cachedsi.wProcessorRevision = signature & 0xff; cachedsi.wProcessorLevel = (signature >> 8)&0xf; /* set the CPU type of the current processor */ sprintf(buf,"CPU %ld",cachedsi.dwProcessorType); if (xhkey) { RegSetValueExA(xhkey,"Identifier",0,REG_SZ,(LPBYTE)buf,strlen(buf)); memset(buf, 0, sizeof(buf)); GetCPUVendorString(buf); RegSetValueExA(xhkey,"VendorIdentifier",0,REG_SZ,(LPBYTE)buf,strlen(buf)); #ifdef __WIN32OS2__ if(i==0) { DWORD mhz; features = GetCPUFeatures(); if(features & CPUID_TIME_STAMP_COUNTER) { LARGE_INTEGER tsc1, tsc2, freq, time1, time2; double clockticks, millisec, frequency, tmp, tmp1, mhertz; QueryPerformanceFrequency(&freq); GetTSC((LONG *)&tsc1.LowPart, &tsc1.HighPart); QueryPerformanceCounter(&time1); Sleep(32); //sleep for about 32 ms GetTSC((LONG *)&tsc2.LowPart, &tsc2.HighPart); QueryPerformanceCounter(&time2); tmp = (double)time2.LowPart + (double)time2.HighPart*4.0*1024.0*1024.0; tmp1 = (double)time1.LowPart + (double)time1.HighPart*4.0*1024.0*1024.0; millisec = tmp - tmp1; frequency= (double)freq.LowPart; frequency= frequency / 1000.0; millisec = millisec / frequency; tmp = (double)tsc2.LowPart + (double)tsc2.HighPart*4.0*1024.0*1024.0; tmp1 = (double)tsc1.LowPart + (double)tsc1.HighPart*4.0*1024.0*1024.0; clockticks = tmp - tmp1; if(millisec > 0) {//make sure we have something valid here tmp = 1000 / millisec; clockticks = clockticks * tmp; //ticks per second mhertz = clockticks / 1000000.0; mhz = (DWORD)mhertz; } else mhz = 500; } else mhz = 500; RegSetValueExA(xhkey,"~Mhz",0,REG_DWORD, (LPBYTE)&mhz, sizeof(DWORD)); } #endif } //TODO: FPU fdiv bug #if 0 if (!lstrncmpiA(line,"fdiv_bug",strlen("fdiv_bug"))) { if (!lstrncmpiA(value,"yes",3)) PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE; continue; } #endif features = GetCPUFeatures(); if (features & CPUID_CMPXCHG8B_INSTRUCTION) PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE; if (features & CPUID_MMX) PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE; //Create FPU key if one is present if (features & CPUID_FPU_PRESENT) { if (i == 0) { if(RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\FloatingPointProcessor",&fpukey)!=ERROR_SUCCESS) dprintf(("Unable to register FPU information\n")); } // Create a new processor subkey if(fpukey) { sprintf(buf,"%d",i); RegCreateKeyA(fpukey,buf,&xhfpukey); } } } //for each cpu } memcpy(si,&cachedsi,sizeof(*si)); if (xhkey) RegCloseKey(xhkey); if (hkey) RegCloseKey(hkey); if (xhfpukey) RegCloseKey(xhfpukey); if (fpukey) RegCloseKey(fpukey); } /*********************************************************************** * IsProcessorFeaturePresent [KERNELL32.880] * RETURNS: * TRUE if processorfeature present * FALSE otherwise */ BOOL WINAPI IsProcessorFeaturePresent (DWORD feature) /* [in] feature number, see PF_ defines */ { SYSTEM_INFO si; GetSystemInfo (&si); /* To ensure the information is loaded and cached */ if (feature < 64) { dprintf(("IsProcessorFeaturePresent %x -> %x", feature, PF[feature])); return PF[feature]; } else return FALSE; } //****************************************************************************** //******************************************************************************