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