| 1 | /* $Id: cpu.cpp,v 1.7 2000-03-03 11:15:57 sandervl Exp $ */ | 
|---|
| 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" | 
|---|
| 22 | #include <cpuhlp.h> | 
|---|
| 23 |  | 
|---|
| 24 | #define DBG_LOCALLOG    DBG_cpu | 
|---|
| 25 | #include "dbglocal.h" | 
|---|
| 26 |  | 
|---|
| 27 | DEFAULT_DEBUG_CHANNEL(CPU) | 
|---|
| 28 |  | 
|---|
| 29 | static BYTE PF[64] = {0,}; | 
|---|
| 30 | static nrCPUs = 1; | 
|---|
| 31 |  | 
|---|
| 32 | //****************************************************************************** | 
|---|
| 33 | //****************************************************************************** | 
|---|
| 34 | void InitSystemInfo(int nrcpus) | 
|---|
| 35 | { | 
|---|
| 36 | SYSTEM_INFO si; | 
|---|
| 37 |  | 
|---|
| 38 | nrCPUs = nrcpus; | 
|---|
| 39 | GetSystemInfo(&si); | 
|---|
| 40 | } | 
|---|
| 41 | /*********************************************************************** | 
|---|
| 42 | *                      GetSystemInfo                   [KERNELL32.404] | 
|---|
| 43 | * | 
|---|
| 44 | * Gets the current system information. | 
|---|
| 45 | * | 
|---|
| 46 | * On the first call it reads cached values, so it doesn't have to determine | 
|---|
| 47 | * them repeatedly. On Linux, the /proc/cpuinfo special file is used. | 
|---|
| 48 | * | 
|---|
| 49 | * It creates a registry subhierarchy, looking like: | 
|---|
| 50 | * \HARDWARE\DESCRIPTION\System\CentralProcessor\<processornumber>\ | 
|---|
| 51 | *                                                      Identifier (CPU x86) | 
|---|
| 52 | * Note that there is a hierarchy for every processor installed, so this | 
|---|
| 53 | * supports multiprocessor systems. This is done like Win95 does it, I think. | 
|---|
| 54 | * | 
|---|
| 55 | * It also creates a cached flag array for IsProcessorFeaturePresent(). | 
|---|
| 56 | * | 
|---|
| 57 | * RETURNS | 
|---|
| 58 | *      nothing, really | 
|---|
| 59 | */ | 
|---|
| 60 | VOID WINAPI GetSystemInfo(LPSYSTEM_INFO si)     /* [out] system information */ | 
|---|
| 61 | { | 
|---|
| 62 | static int cache = 0; | 
|---|
| 63 | static SYSTEM_INFO cachedsi; | 
|---|
| 64 | HKEY   xhkey=0,hkey; | 
|---|
| 65 | HKEY   fpukey=0, xhfpukey; | 
|---|
| 66 | char buf[20]; | 
|---|
| 67 | DWORD features, signature; | 
|---|
| 68 |  | 
|---|
| 69 | if(!si) { | 
|---|
| 70 | dprintf(("GetSystemInfo -> si == NULL!!")); | 
|---|
| 71 | SetLastError(ERROR_INVALID_PARAMETER); | 
|---|
| 72 | return; | 
|---|
| 73 | } | 
|---|
| 74 | dprintf(("GetSystemInfo")); | 
|---|
| 75 | if (cache) { | 
|---|
| 76 | memcpy(si,&cachedsi,sizeof(*si)); | 
|---|
| 77 | return; | 
|---|
| 78 | } | 
|---|
| 79 | memset(PF,0,sizeof(PF)); | 
|---|
| 80 |  | 
|---|
| 81 | /* choose sensible defaults ... | 
|---|
| 82 | * FIXME: perhaps overrideable with precompiler flags? | 
|---|
| 83 | */ | 
|---|
| 84 | cachedsi.u.x.wProcessorArchitecture     = PROCESSOR_ARCHITECTURE_INTEL; | 
|---|
| 85 | cachedsi.dwPageSize                     = 4096; | 
|---|
| 86 |  | 
|---|
| 87 | /* FIXME: better values for the two entries below... */ | 
|---|
| 88 | cachedsi.lpMinimumApplicationAddress    = (void *)0x40000000; | 
|---|
| 89 | cachedsi.lpMaximumApplicationAddress    = (void *)0x7FFFFFFF; | 
|---|
| 90 | cachedsi.dwActiveProcessorMask          = 1; | 
|---|
| 91 | cachedsi.dwNumberOfProcessors           = nrCPUs; | 
|---|
| 92 | cachedsi.dwProcessorType                = PROCESSOR_INTEL_386; | 
|---|
| 93 | cachedsi.dwAllocationGranularity        = 0x10000; | 
|---|
| 94 | cachedsi.wProcessorLevel                = 3; /* 386 */ | 
|---|
| 95 | cachedsi.wProcessorRevision             = 0; | 
|---|
| 96 |  | 
|---|
| 97 | cache = 1; /* even if there is no more info, we now have a cacheentry */ | 
|---|
| 98 | memcpy(si,&cachedsi,sizeof(*si)); | 
|---|
| 99 |  | 
|---|
| 100 | /* Hmm, reasonable processor feature defaults? */ | 
|---|
| 101 |  | 
|---|
| 102 | /* Create this registry key for all systems */ | 
|---|
| 103 | if (RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey)!=ERROR_SUCCESS) { | 
|---|
| 104 | dprintf(("Unable to register CPU information\n")); | 
|---|
| 105 | } | 
|---|
| 106 |  | 
|---|
| 107 | if(SupportsCPUID()) | 
|---|
| 108 | { | 
|---|
| 109 | for(int i=0;i<cachedsi.dwNumberOfProcessors;i++) | 
|---|
| 110 | { | 
|---|
| 111 | // Create a new processor subkey | 
|---|
| 112 | sprintf(buf,"%d",i); | 
|---|
| 113 | if (xhkey) | 
|---|
| 114 | RegCloseKey(xhkey); | 
|---|
| 115 | RegCreateKeyA(hkey,buf,&xhkey); | 
|---|
| 116 |  | 
|---|
| 117 | signature = GetCPUSignature(); | 
|---|
| 118 |  | 
|---|
| 119 | switch ((signature >> 8)&0xf) { | 
|---|
| 120 | case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386; | 
|---|
| 121 | cachedsi.wProcessorLevel= 3; | 
|---|
| 122 | break; | 
|---|
| 123 | case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486; | 
|---|
| 124 | cachedsi.wProcessorLevel= 4; | 
|---|
| 125 | break; | 
|---|
| 126 | case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; | 
|---|
| 127 | cachedsi.wProcessorLevel= 5; | 
|---|
| 128 | break; | 
|---|
| 129 | case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM; | 
|---|
| 130 | cachedsi.wProcessorLevel= 5; | 
|---|
| 131 | break; | 
|---|
| 132 | default: | 
|---|
| 133 | break; | 
|---|
| 134 | } | 
|---|
| 135 | /* set the CPU type of the current processor */ | 
|---|
| 136 | sprintf(buf,"CPU %ld",cachedsi.dwProcessorType); | 
|---|
| 137 | if (xhkey) { | 
|---|
| 138 | RegSetValueExA(xhkey,"Identifier",0,REG_SZ,(LPBYTE)buf,strlen(buf)); | 
|---|
| 139 | memset(buf, 0, sizeof(buf)); | 
|---|
| 140 | GetCPUVendorString(buf); | 
|---|
| 141 | RegSetValueExA(xhkey,"VendorIdentifier",0,REG_SZ,(LPBYTE)buf,strlen(buf)); | 
|---|
| 142 | } | 
|---|
| 143 | cachedsi.wProcessorRevision = signature & 0xf; | 
|---|
| 144 |  | 
|---|
| 145 | //TODO: FPU fdiv bug | 
|---|
| 146 | #if 0 | 
|---|
| 147 | if (!lstrncmpiA(line,"fdiv_bug",strlen("fdiv_bug"))) { | 
|---|
| 148 | if (!lstrncmpiA(value,"yes",3)) | 
|---|
| 149 | PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE; | 
|---|
| 150 |  | 
|---|
| 151 | continue; | 
|---|
| 152 | } | 
|---|
| 153 | #endif | 
|---|
| 154 | features = GetCPUFeatures(); | 
|---|
| 155 | if (features & CPUID_CMPXCHG8B_INSTRUCTION) | 
|---|
| 156 | PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE; | 
|---|
| 157 | if (features & CPUID_MMX) | 
|---|
| 158 | PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE; | 
|---|
| 159 |  | 
|---|
| 160 | //Create FPU key if one is present | 
|---|
| 161 | if (features & CPUID_FPU_PRESENT) { | 
|---|
| 162 | if (i == 0) { | 
|---|
| 163 | if(RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\FloatingPointProcessor",&fpukey)!=ERROR_SUCCESS) | 
|---|
| 164 | dprintf(("Unable to register FPU information\n")); | 
|---|
| 165 | } | 
|---|
| 166 | // Create a new processor subkey | 
|---|
| 167 | if(fpukey) { | 
|---|
| 168 | sprintf(buf,"%d",i); | 
|---|
| 169 | RegCreateKeyA(fpukey,buf,&xhfpukey); | 
|---|
| 170 | } | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | } //for each cpu | 
|---|
| 174 | } | 
|---|
| 175 | memcpy(si,&cachedsi,sizeof(*si)); | 
|---|
| 176 |  | 
|---|
| 177 | if (xhkey) | 
|---|
| 178 | RegCloseKey(xhkey); | 
|---|
| 179 | if (hkey) | 
|---|
| 180 | RegCloseKey(hkey); | 
|---|
| 181 | if (xhfpukey) | 
|---|
| 182 | RegCloseKey(xhfpukey); | 
|---|
| 183 | if (fpukey) | 
|---|
| 184 | RegCloseKey(fpukey); | 
|---|
| 185 |  | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 |  | 
|---|
| 189 | /*********************************************************************** | 
|---|
| 190 | *                      IsProcessorFeaturePresent       [KERNELL32.880] | 
|---|
| 191 | * RETURNS: | 
|---|
| 192 | *      TRUE if processorfeature present | 
|---|
| 193 | *      FALSE otherwise | 
|---|
| 194 | */ | 
|---|
| 195 | BOOL WINAPI IsProcessorFeaturePresent (DWORD feature)   /* [in] feature number, see PF_ defines */ | 
|---|
| 196 | { | 
|---|
| 197 | SYSTEM_INFO si; | 
|---|
| 198 | GetSystemInfo (&si); /* To ensure the information is loaded and cached */ | 
|---|
| 199 |  | 
|---|
| 200 | if (feature < 64) | 
|---|
| 201 | return PF[feature]; | 
|---|
| 202 | else | 
|---|
| 203 | return FALSE; | 
|---|
| 204 | } | 
|---|
| 205 | //****************************************************************************** | 
|---|
| 206 | //****************************************************************************** | 
|---|