[10475] | 1 | /* $Id: cpu.cpp,v 1.15 2004-02-20 10:05:39 sandervl Exp $ */
|
---|
[1815] | 2 | /*
|
---|
| 3 | * Odin win32 CPU apis
|
---|
| 4 | *
|
---|
| 5 | * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
|
---|
| 6 | *
|
---|
| 7 | * Based on Wine Code (991031: misc\cpu.c)
|
---|
| 8 | *
|
---|
| 9 | * Copyright 1995,1997 Morten Welinder
|
---|
| 10 | * Copyright 1997-1998 Marcus Meissner
|
---|
| 11 | */
|
---|
| 12 |
|
---|
| 13 | #include <os2win.h>
|
---|
| 14 | #include <ctype.h>
|
---|
| 15 | #include <string.h>
|
---|
| 16 | #include "winreg.h"
|
---|
| 17 | #include "global.h"
|
---|
| 18 | #include "winnt.h"
|
---|
| 19 | #include "winerror.h"
|
---|
| 20 | #include "winreg.h"
|
---|
| 21 | #include "debugtools.h"
|
---|
[2613] | 22 | #include <cpuhlp.h>
|
---|
[1815] | 23 |
|
---|
[2802] | 24 | #define DBG_LOCALLOG DBG_cpu
|
---|
| 25 | #include "dbglocal.h"
|
---|
| 26 |
|
---|
[1815] | 27 | DEFAULT_DEBUG_CHANNEL(CPU)
|
---|
| 28 |
|
---|
[3461] | 29 | static BYTE PF[64] = {0,};
|
---|
[21916] | 30 | static int nrCPUs = 1;
|
---|
[3461] | 31 | static SYSTEM_INFO cachedsi = {0};
|
---|
[1838] | 32 |
|
---|
[1815] | 33 | //******************************************************************************
|
---|
| 34 | //******************************************************************************
|
---|
[1820] | 35 | void InitSystemInfo(int nrcpus)
|
---|
[1815] | 36 | {
|
---|
| 37 | SYSTEM_INFO si;
|
---|
| 38 |
|
---|
[1820] | 39 | nrCPUs = nrcpus;
|
---|
[1815] | 40 | GetSystemInfo(&si);
|
---|
| 41 | }
|
---|
| 42 | /***********************************************************************
|
---|
| 43 | * GetSystemInfo [KERNELL32.404]
|
---|
| 44 | *
|
---|
| 45 | * Gets the current system information.
|
---|
| 46 | *
|
---|
| 47 | * On the first call it reads cached values, so it doesn't have to determine
|
---|
| 48 | * them repeatedly. On Linux, the /proc/cpuinfo special file is used.
|
---|
| 49 | *
|
---|
| 50 | * It creates a registry subhierarchy, looking like:
|
---|
| 51 | * \HARDWARE\DESCRIPTION\System\CentralProcessor\<processornumber>\
|
---|
| 52 | * Identifier (CPU x86)
|
---|
| 53 | * Note that there is a hierarchy for every processor installed, so this
|
---|
| 54 | * supports multiprocessor systems. This is done like Win95 does it, I think.
|
---|
[21916] | 55 | *
|
---|
[1815] | 56 | * It also creates a cached flag array for IsProcessorFeaturePresent().
|
---|
| 57 | *
|
---|
| 58 | * RETURNS
|
---|
| 59 | * nothing, really
|
---|
| 60 | */
|
---|
| 61 | VOID WINAPI GetSystemInfo(LPSYSTEM_INFO si) /* [out] system information */
|
---|
| 62 | {
|
---|
[3461] | 63 | HKEY xhkey=0,hkey;
|
---|
| 64 | HKEY fpukey=0, xhfpukey;
|
---|
| 65 | char buf[20];
|
---|
| 66 | DWORD features, signature;
|
---|
[1815] | 67 | static int cache = 0;
|
---|
| 68 |
|
---|
| 69 | if(!si) {
|
---|
| 70 | dprintf(("GetSystemInfo -> si == NULL!!"));
|
---|
| 71 | SetLastError(ERROR_INVALID_PARAMETER);
|
---|
| 72 | return;
|
---|
| 73 | }
|
---|
| 74 | if (cache) {
|
---|
| 75 | memcpy(si,&cachedsi,sizeof(*si));
|
---|
| 76 | return;
|
---|
| 77 | }
|
---|
| 78 | memset(PF,0,sizeof(PF));
|
---|
| 79 |
|
---|
| 80 | /* choose sensible defaults ...
|
---|
| 81 | * FIXME: perhaps overrideable with precompiler flags?
|
---|
| 82 | */
|
---|
| 83 | cachedsi.u.x.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
|
---|
| 84 | cachedsi.dwPageSize = 4096;
|
---|
| 85 |
|
---|
| 86 | /* FIXME: better values for the two entries below... */
|
---|
[4074] | 87 | cachedsi.lpMinimumApplicationAddress = (void *)0x00400000;
|
---|
[1815] | 88 | cachedsi.lpMaximumApplicationAddress = (void *)0x7FFFFFFF;
|
---|
| 89 | cachedsi.dwActiveProcessorMask = 1;
|
---|
[1820] | 90 | cachedsi.dwNumberOfProcessors = nrCPUs;
|
---|
[1815] | 91 | cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
|
---|
| 92 | cachedsi.dwAllocationGranularity = 0x10000;
|
---|
| 93 | cachedsi.wProcessorLevel = 3; /* 386 */
|
---|
| 94 | cachedsi.wProcessorRevision = 0;
|
---|
| 95 |
|
---|
| 96 | cache = 1; /* even if there is no more info, we now have a cacheentry */
|
---|
| 97 | memcpy(si,&cachedsi,sizeof(*si));
|
---|
| 98 |
|
---|
| 99 | /* Hmm, reasonable processor feature defaults? */
|
---|
| 100 |
|
---|
| 101 | /* Create this registry key for all systems */
|
---|
[2984] | 102 | if (RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey)!=ERROR_SUCCESS) {
|
---|
[1815] | 103 | dprintf(("Unable to register CPU information\n"));
|
---|
| 104 | }
|
---|
| 105 |
|
---|
[21916] | 106 | if(SupportsCPUID())
|
---|
[1815] | 107 | {
|
---|
[21916] | 108 | for(int i=0;i<cachedsi.dwNumberOfProcessors;i++)
|
---|
[1815] | 109 | {
|
---|
| 110 | // Create a new processor subkey
|
---|
| 111 | sprintf(buf,"%d",i);
|
---|
| 112 | if (xhkey)
|
---|
[2984] | 113 | RegCloseKey(xhkey);
|
---|
| 114 | RegCreateKeyA(hkey,buf,&xhkey);
|
---|
[1815] | 115 |
|
---|
| 116 | signature = GetCPUSignature();
|
---|
| 117 |
|
---|
| 118 | switch ((signature >> 8)&0xf) {
|
---|
| 119 | case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
|
---|
| 120 | break;
|
---|
| 121 | case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
|
---|
| 122 | break;
|
---|
| 123 | case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
|
---|
| 124 | break;
|
---|
| 125 | case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
|
---|
| 126 | break;
|
---|
| 127 | default:
|
---|
[10475] | 128 | cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
|
---|
[1815] | 129 | break;
|
---|
| 130 | }
|
---|
[3746] | 131 | cachedsi.wProcessorRevision = signature & 0xff;
|
---|
| 132 | cachedsi.wProcessorLevel = (signature >> 8)&0xf;
|
---|
| 133 |
|
---|
[1815] | 134 | /* set the CPU type of the current processor */
|
---|
| 135 | sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
|
---|
| 136 | if (xhkey) {
|
---|
[2984] | 137 | RegSetValueExA(xhkey,"Identifier",0,REG_SZ,(LPBYTE)buf,strlen(buf));
|
---|
[1815] | 138 | memset(buf, 0, sizeof(buf));
|
---|
| 139 | GetCPUVendorString(buf);
|
---|
[2984] | 140 | RegSetValueExA(xhkey,"VendorIdentifier",0,REG_SZ,(LPBYTE)buf,strlen(buf));
|
---|
[4407] | 141 | #ifdef __WIN32OS2__
|
---|
| 142 | if(i==0) {
|
---|
| 143 | DWORD mhz;
|
---|
| 144 | features = GetCPUFeatures();
|
---|
| 145 | if(features & CPUID_TIME_STAMP_COUNTER) {
|
---|
| 146 | LARGE_INTEGER tsc1, tsc2, freq, time1, time2;
|
---|
| 147 | double clockticks, millisec, frequency, tmp, tmp1, mhertz;
|
---|
| 148 |
|
---|
| 149 | QueryPerformanceFrequency(&freq);
|
---|
| 150 |
|
---|
| 151 | GetTSC((LONG *)&tsc1.LowPart, &tsc1.HighPart);
|
---|
| 152 | QueryPerformanceCounter(&time1);
|
---|
| 153 |
|
---|
| 154 | Sleep(32); //sleep for about 32 ms
|
---|
[21916] | 155 |
|
---|
[4407] | 156 | GetTSC((LONG *)&tsc2.LowPart, &tsc2.HighPart);
|
---|
| 157 | QueryPerformanceCounter(&time2);
|
---|
| 158 | tmp = (double)time2.LowPart + (double)time2.HighPart*4.0*1024.0*1024.0;
|
---|
| 159 | tmp1 = (double)time1.LowPart + (double)time1.HighPart*4.0*1024.0*1024.0;
|
---|
| 160 | millisec = tmp - tmp1;
|
---|
[9880] | 161 |
|
---|
[4407] | 162 | frequency= (double)freq.LowPart;
|
---|
| 163 | frequency= frequency / 1000.0;
|
---|
| 164 | millisec = millisec / frequency;
|
---|
| 165 |
|
---|
| 166 | tmp = (double)tsc2.LowPart + (double)tsc2.HighPart*4.0*1024.0*1024.0;
|
---|
| 167 | tmp1 = (double)tsc1.LowPart + (double)tsc1.HighPart*4.0*1024.0*1024.0;
|
---|
| 168 | clockticks = tmp - tmp1;
|
---|
[21916] | 169 | if(millisec > 0)
|
---|
[9880] | 170 | {//make sure we have something valid here
|
---|
| 171 | tmp = 1000 / millisec;
|
---|
| 172 | clockticks = clockticks * tmp; //ticks per second
|
---|
| 173 | mhertz = clockticks / 1000000.0;
|
---|
| 174 | mhz = (DWORD)mhertz;
|
---|
| 175 | }
|
---|
| 176 | else mhz = 500;
|
---|
[4407] | 177 | }
|
---|
[9880] | 178 | else mhz = 500;
|
---|
[4407] | 179 | RegSetValueExA(xhkey,"~Mhz",0,REG_DWORD, (LPBYTE)&mhz, sizeof(DWORD));
|
---|
| 180 | }
|
---|
| 181 | #endif
|
---|
[1815] | 182 | }
|
---|
| 183 | //TODO: FPU fdiv bug
|
---|
| 184 | #if 0
|
---|
| 185 | if (!lstrncmpiA(line,"fdiv_bug",strlen("fdiv_bug"))) {
|
---|
| 186 | if (!lstrncmpiA(value,"yes",3))
|
---|
| 187 | PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
|
---|
| 188 |
|
---|
| 189 | continue;
|
---|
| 190 | }
|
---|
| 191 | #endif
|
---|
| 192 | features = GetCPUFeatures();
|
---|
| 193 | if (features & CPUID_CMPXCHG8B_INSTRUCTION)
|
---|
| 194 | PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
|
---|
| 195 | if (features & CPUID_MMX)
|
---|
[21343] | 196 | PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
|
---|
[1815] | 197 |
|
---|
| 198 | //Create FPU key if one is present
|
---|
| 199 | if (features & CPUID_FPU_PRESENT) {
|
---|
[1820] | 200 | if (i == 0) {
|
---|
[21916] | 201 | if(RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\FloatingPointProcessor",&fpukey)!=ERROR_SUCCESS)
|
---|
[1820] | 202 | dprintf(("Unable to register FPU information\n"));
|
---|
[1815] | 203 | }
|
---|
[1820] | 204 | // Create a new processor subkey
|
---|
| 205 | if(fpukey) {
|
---|
| 206 | sprintf(buf,"%d",i);
|
---|
[2984] | 207 | RegCreateKeyA(fpukey,buf,&xhfpukey);
|
---|
[1820] | 208 | }
|
---|
[1815] | 209 | }
|
---|
[21916] | 210 |
|
---|
[1815] | 211 | } //for each cpu
|
---|
| 212 | }
|
---|
| 213 | memcpy(si,&cachedsi,sizeof(*si));
|
---|
| 214 |
|
---|
| 215 | if (xhkey)
|
---|
[2984] | 216 | RegCloseKey(xhkey);
|
---|
[1815] | 217 | if (hkey)
|
---|
[2984] | 218 | RegCloseKey(hkey);
|
---|
[1820] | 219 | if (xhfpukey)
|
---|
[2984] | 220 | RegCloseKey(xhfpukey);
|
---|
[1820] | 221 | if (fpukey)
|
---|
[2984] | 222 | RegCloseKey(fpukey);
|
---|
[1820] | 223 |
|
---|
[1815] | 224 | }
|
---|
| 225 |
|
---|
| 226 |
|
---|
| 227 | /***********************************************************************
|
---|
| 228 | * IsProcessorFeaturePresent [KERNELL32.880]
|
---|
| 229 | * RETURNS:
|
---|
| 230 | * TRUE if processorfeature present
|
---|
| 231 | * FALSE otherwise
|
---|
| 232 | */
|
---|
| 233 | BOOL WINAPI IsProcessorFeaturePresent (DWORD feature) /* [in] feature number, see PF_ defines */
|
---|
| 234 | {
|
---|
| 235 | SYSTEM_INFO si;
|
---|
| 236 | GetSystemInfo (&si); /* To ensure the information is loaded and cached */
|
---|
| 237 |
|
---|
[6129] | 238 | if (feature < 64) {
|
---|
| 239 | dprintf(("IsProcessorFeaturePresent %x -> %x", feature, PF[feature]));
|
---|
[1815] | 240 | return PF[feature];
|
---|
[6129] | 241 | }
|
---|
[1815] | 242 | else
|
---|
| 243 | return FALSE;
|
---|
| 244 | }
|
---|
| 245 | //******************************************************************************
|
---|
| 246 | //******************************************************************************
|
---|