1 | /* $Id: cpu.cpp,v 1.10 2000-08-23 18:03:33 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 | static SYSTEM_INFO cachedsi = {0};
|
---|
32 |
|
---|
33 | //******************************************************************************
|
---|
34 | //******************************************************************************
|
---|
35 | void InitSystemInfo(int nrcpus)
|
---|
36 | {
|
---|
37 | SYSTEM_INFO si;
|
---|
38 |
|
---|
39 | nrCPUs = nrcpus;
|
---|
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.
|
---|
55 | *
|
---|
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 | {
|
---|
63 | HKEY xhkey=0,hkey;
|
---|
64 | HKEY fpukey=0, xhfpukey;
|
---|
65 | char buf[20];
|
---|
66 | DWORD features, signature;
|
---|
67 | static int cache = 0;
|
---|
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 *)0x00400000;
|
---|
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 | break;
|
---|
122 | case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
|
---|
123 | break;
|
---|
124 | case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
|
---|
125 | break;
|
---|
126 | case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
|
---|
127 | break;
|
---|
128 | default:
|
---|
129 | break;
|
---|
130 | }
|
---|
131 | cachedsi.wProcessorRevision = signature & 0xff;
|
---|
132 | cachedsi.wProcessorLevel = (signature >> 8)&0xf;
|
---|
133 |
|
---|
134 | /* set the CPU type of the current processor */
|
---|
135 | sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
|
---|
136 | if (xhkey) {
|
---|
137 | RegSetValueExA(xhkey,"Identifier",0,REG_SZ,(LPBYTE)buf,strlen(buf));
|
---|
138 | memset(buf, 0, sizeof(buf));
|
---|
139 | GetCPUVendorString(buf);
|
---|
140 | RegSetValueExA(xhkey,"VendorIdentifier",0,REG_SZ,(LPBYTE)buf,strlen(buf));
|
---|
141 | }
|
---|
142 |
|
---|
143 | //TODO: FPU fdiv bug
|
---|
144 | #if 0
|
---|
145 | if (!lstrncmpiA(line,"fdiv_bug",strlen("fdiv_bug"))) {
|
---|
146 | if (!lstrncmpiA(value,"yes",3))
|
---|
147 | PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
|
---|
148 |
|
---|
149 | continue;
|
---|
150 | }
|
---|
151 | #endif
|
---|
152 | features = GetCPUFeatures();
|
---|
153 | if (features & CPUID_CMPXCHG8B_INSTRUCTION)
|
---|
154 | PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
|
---|
155 | if (features & CPUID_MMX)
|
---|
156 | PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
|
---|
157 |
|
---|
158 | //Create FPU key if one is present
|
---|
159 | if (features & CPUID_FPU_PRESENT) {
|
---|
160 | if (i == 0) {
|
---|
161 | if(RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\FloatingPointProcessor",&fpukey)!=ERROR_SUCCESS)
|
---|
162 | dprintf(("Unable to register FPU information\n"));
|
---|
163 | }
|
---|
164 | // Create a new processor subkey
|
---|
165 | if(fpukey) {
|
---|
166 | sprintf(buf,"%d",i);
|
---|
167 | RegCreateKeyA(fpukey,buf,&xhfpukey);
|
---|
168 | }
|
---|
169 | }
|
---|
170 |
|
---|
171 | } //for each cpu
|
---|
172 | }
|
---|
173 | memcpy(si,&cachedsi,sizeof(*si));
|
---|
174 |
|
---|
175 | if (xhkey)
|
---|
176 | RegCloseKey(xhkey);
|
---|
177 | if (hkey)
|
---|
178 | RegCloseKey(hkey);
|
---|
179 | if (xhfpukey)
|
---|
180 | RegCloseKey(xhfpukey);
|
---|
181 | if (fpukey)
|
---|
182 | RegCloseKey(fpukey);
|
---|
183 |
|
---|
184 | }
|
---|
185 |
|
---|
186 |
|
---|
187 | /***********************************************************************
|
---|
188 | * IsProcessorFeaturePresent [KERNELL32.880]
|
---|
189 | * RETURNS:
|
---|
190 | * TRUE if processorfeature present
|
---|
191 | * FALSE otherwise
|
---|
192 | */
|
---|
193 | BOOL WINAPI IsProcessorFeaturePresent (DWORD feature) /* [in] feature number, see PF_ defines */
|
---|
194 | {
|
---|
195 | SYSTEM_INFO si;
|
---|
196 | GetSystemInfo (&si); /* To ensure the information is loaded and cached */
|
---|
197 |
|
---|
198 | if (feature < 64)
|
---|
199 | return PF[feature];
|
---|
200 | else
|
---|
201 | return FALSE;
|
---|
202 | }
|
---|
203 | //******************************************************************************
|
---|
204 | //******************************************************************************
|
---|