diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcommon/llprocessor.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcommon/llprocessor.cpp')
-rw-r--r-- | linden/indra/llcommon/llprocessor.cpp | 2151 |
1 files changed, 2151 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llprocessor.cpp b/linden/indra/llcommon/llprocessor.cpp new file mode 100644 index 0000000..b811678 --- /dev/null +++ b/linden/indra/llcommon/llprocessor.cpp | |||
@@ -0,0 +1,2151 @@ | |||
1 | /** | ||
2 | * @file llprocessor.cpp | ||
3 | * @brief Code to figure out the processor. Originally by Benjamin Jurke. | ||
4 | * | ||
5 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | // Filename: Processor.cpp | ||
29 | // ======================= | ||
30 | // Author: Benjamin Jurke | ||
31 | // File history: 27.02.2002 - File created. Support for Intel and AMD processors | ||
32 | // 05.03.2002 - Fixed the CPUID bug: On Pre-Pentium CPUs the CPUID | ||
33 | // command is not available | ||
34 | // - The CProcessor::WriteInfoTextFile function do not | ||
35 | // longer use Win32 file functions (-> os independend) | ||
36 | // - Optional include of the windows.h header which is | ||
37 | // still need for CProcessor::GetCPUFrequency. | ||
38 | // 06.03.2002 - My birthday (18th :-)) | ||
39 | // - Replaced the '\r\n' line endings in function | ||
40 | // CProcessor::CPUInfoToText by '\n' | ||
41 | // - Replaced unsigned __int64 by signed __int64 for | ||
42 | // solving some compiler conversion problems | ||
43 | // - Fixed a bug at family=6, model=6 (Celeron -> P2) | ||
44 | ////////////////////////////////////////////////////////////////////////////////// | ||
45 | |||
46 | #include "linden_common.h" | ||
47 | |||
48 | #include "processor.h" | ||
49 | |||
50 | #include <stdio.h> | ||
51 | #include <string.h> | ||
52 | #include <memory.h> | ||
53 | |||
54 | #if LL_WINDOWS | ||
55 | # define WIN32_LEAN_AND_MEAN | ||
56 | # include <winsock2.h> | ||
57 | # include <windows.h> | ||
58 | #endif | ||
59 | |||
60 | #if !LL_DARWIN | ||
61 | |||
62 | #ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE | ||
63 | // We need the QueryPerformanceCounter and Sleep functions | ||
64 | #define FORCEINLINE __forceinline | ||
65 | #else | ||
66 | #define FORCEINLINE | ||
67 | #endif | ||
68 | |||
69 | |||
70 | // Some macros we often need | ||
71 | //////////////////////////// | ||
72 | #define CheckBit(var, bit) ((var & (1 << bit)) ? true : false) | ||
73 | |||
74 | #ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE | ||
75 | // Delays for the specified amount of milliseconds | ||
76 | static void _Delay(unsigned int ms) | ||
77 | { | ||
78 | LARGE_INTEGER freq, c1, c2; | ||
79 | __int64 x; | ||
80 | |||
81 | // Get High-Res Timer frequency | ||
82 | if (!QueryPerformanceFrequency(&freq)) | ||
83 | return; | ||
84 | |||
85 | // Convert ms to High-Res Timer value | ||
86 | x = freq.QuadPart/1000*ms; | ||
87 | |||
88 | // Get first snapshot of High-Res Timer value | ||
89 | QueryPerformanceCounter(&c1); | ||
90 | do | ||
91 | { | ||
92 | // Get second snapshot | ||
93 | QueryPerformanceCounter(&c2); | ||
94 | }while(c2.QuadPart-c1.QuadPart < x); | ||
95 | // Loop while (second-first < x) | ||
96 | } | ||
97 | #endif | ||
98 | |||
99 | // CProcessor::CProcessor | ||
100 | // ====================== | ||
101 | // Class constructor: | ||
102 | ///////////////////////// | ||
103 | CProcessor::CProcessor() | ||
104 | { | ||
105 | uqwFrequency = 0; | ||
106 | memset(&CPUInfo, 0, sizeof(CPUInfo)); | ||
107 | } | ||
108 | |||
109 | // unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) | ||
110 | // ========================================================================= | ||
111 | // Function to measure the current CPU frequency | ||
112 | //////////////////////////////////////////////////////////////////////////// | ||
113 | F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) | ||
114 | { | ||
115 | #ifndef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE | ||
116 | return 0; | ||
117 | #else | ||
118 | // If there are invalid measure time parameters, zero msecs for example, | ||
119 | // we've to exit the function | ||
120 | if (uiMeasureMSecs < 1) | ||
121 | { | ||
122 | // If theres already a measured frequency available, we return it | ||
123 | if (uqwFrequency > 0) | ||
124 | return uqwFrequency; | ||
125 | else | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | // Now we check if the CPUID command is available | ||
130 | if (!CheckCPUIDPresence()) | ||
131 | return 0; | ||
132 | |||
133 | // First we get the CPUID standard level 0x00000001 | ||
134 | unsigned long reg; | ||
135 | __asm | ||
136 | { | ||
137 | mov eax, 1 | ||
138 | cpuid | ||
139 | mov reg, edx | ||
140 | } | ||
141 | |||
142 | // Then we check, if the RDTSC (Real Date Time Stamp Counter) is available. | ||
143 | // This function is necessary for our measure process. | ||
144 | if (!(reg & (1 << 4))) | ||
145 | return 0; | ||
146 | |||
147 | // After that we declare some vars and check the frequency of the high | ||
148 | // resolution timer for the measure process. | ||
149 | // If there's no high-res timer, we exit. | ||
150 | __int64 starttime, endtime, timedif, freq, start, end, dif; | ||
151 | if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq)) | ||
152 | return 0; | ||
153 | |||
154 | // Now we can init the measure process. We set the process and thread priority | ||
155 | // to the highest available level (Realtime priority). Also we focus the | ||
156 | // first processor in the multiprocessor system. | ||
157 | HANDLE hProcess = GetCurrentProcess(); | ||
158 | HANDLE hThread = GetCurrentThread(); | ||
159 | unsigned long dwCurPriorityClass = GetPriorityClass(hProcess); | ||
160 | int iCurThreadPriority = GetThreadPriority(hThread); | ||
161 | unsigned long dwProcessMask, dwSystemMask, dwNewMask = 1; | ||
162 | GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask); | ||
163 | |||
164 | SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); | ||
165 | SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); | ||
166 | SetProcessAffinityMask(hProcess, dwNewMask); | ||
167 | |||
168 | // Now we call a CPUID to ensure, that all other prior called functions are | ||
169 | // completed now (serialization) | ||
170 | __asm cpuid | ||
171 | |||
172 | // We ask the high-res timer for the start time | ||
173 | QueryPerformanceCounter((LARGE_INTEGER *) &starttime); | ||
174 | |||
175 | // Then we get the current cpu clock and store it | ||
176 | __asm | ||
177 | { | ||
178 | rdtsc | ||
179 | mov dword ptr [start+4], edx | ||
180 | mov dword ptr [start], eax | ||
181 | } | ||
182 | |||
183 | // Now we wart for some msecs | ||
184 | _Delay(uiMeasureMSecs); | ||
185 | // Sleep(uiMeasureMSecs); | ||
186 | |||
187 | // We ask for the end time | ||
188 | QueryPerformanceCounter((LARGE_INTEGER *) &endtime); | ||
189 | |||
190 | // And also for the end cpu clock | ||
191 | __asm | ||
192 | { | ||
193 | rdtsc | ||
194 | mov dword ptr [end+4], edx | ||
195 | mov dword ptr [end], eax | ||
196 | } | ||
197 | |||
198 | // Now we can restore the default process and thread priorities | ||
199 | SetProcessAffinityMask(hProcess, dwProcessMask); | ||
200 | SetThreadPriority(hThread, iCurThreadPriority); | ||
201 | SetPriorityClass(hProcess, dwCurPriorityClass); | ||
202 | |||
203 | // Then we calculate the time and clock differences | ||
204 | dif = end - start; | ||
205 | timedif = endtime - starttime; | ||
206 | |||
207 | // And finally the frequency is the clock difference divided by the time | ||
208 | // difference. | ||
209 | uqwFrequency = (F64)dif / (((F64)timedif) / freq); | ||
210 | |||
211 | // At last we just return the frequency that is also stored in the call | ||
212 | // member var uqwFrequency | ||
213 | return uqwFrequency; | ||
214 | #endif | ||
215 | } | ||
216 | |||
217 | // bool CProcessor::AnalyzeIntelProcessor() | ||
218 | // ======================================== | ||
219 | // Private class function for analyzing an Intel processor | ||
220 | ////////////////////////////////////////////////////////// | ||
221 | bool CProcessor::AnalyzeIntelProcessor() | ||
222 | { | ||
223 | #if LL_WINDOWS | ||
224 | unsigned long eaxreg, ebxreg, edxreg; | ||
225 | |||
226 | // First we check if the CPUID command is available | ||
227 | if (!CheckCPUIDPresence()) | ||
228 | return false; | ||
229 | |||
230 | // Now we get the CPUID standard level 0x00000001 | ||
231 | __asm | ||
232 | { | ||
233 | mov eax, 1 | ||
234 | cpuid | ||
235 | mov eaxreg, eax | ||
236 | mov ebxreg, ebx | ||
237 | mov edxreg, edx | ||
238 | } | ||
239 | |||
240 | // Then get the cpu model, family, type, stepping and brand id by masking | ||
241 | // the eax and ebx register | ||
242 | CPUInfo.uiStepping = eaxreg & 0xF; | ||
243 | CPUInfo.uiModel = (eaxreg >> 4) & 0xF; | ||
244 | CPUInfo.uiFamily = (eaxreg >> 8) & 0xF; | ||
245 | CPUInfo.uiType = (eaxreg >> 12) & 0x3; | ||
246 | CPUInfo.uiBrandID = ebxreg & 0xF; | ||
247 | |||
248 | // Now we can translate the type number to a more understandable string format | ||
249 | switch (CPUInfo.uiType) | ||
250 | { | ||
251 | case 0: // Type = 0: Original OEM processor | ||
252 | strcpy(CPUInfo.strType, "Original OEM"); /* Flawfinder: ignore */ | ||
253 | strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */ | ||
254 | strcat(strCPUName, " "); /* Flawfinder: ignore */ | ||
255 | break; | ||
256 | case 1: // Type = 1: Overdrive processor | ||
257 | strcpy(CPUInfo.strType, "Overdrive"); /* Flawfinder: ignore */ | ||
258 | strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */ | ||
259 | strcat(strCPUName, " "); /* Flawfinder: ignore */ | ||
260 | break; | ||
261 | case 2: // Type = 2: Dual-capable processor | ||
262 | strcpy(CPUInfo.strType, "Dual-capable"); /* Flawfinder: ignore */ | ||
263 | strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */ | ||
264 | strcat(strCPUName, " "); /* Flawfinder: ignore */ | ||
265 | break; | ||
266 | case 3: // Type = 3: Reserved for future use | ||
267 | strcpy(CPUInfo.strType, "Reserved"); /* Flawfinder: ignore */ | ||
268 | break; | ||
269 | default: // This should be never called, cause we just mask 2 bits --> [0..3] | ||
270 | strcpy(CPUInfo.strType, "Unknown"); /* Flawfinder: ignore */ | ||
271 | break; | ||
272 | } | ||
273 | |||
274 | // Then we translate the brand id: | ||
275 | switch (CPUInfo.uiBrandID) | ||
276 | { | ||
277 | case 0: // Brand id = 0: Brand id not supported on this processor | ||
278 | strcpy(CPUInfo.strBrandID, "Not supported"); /* Flawfinder: ignore */ | ||
279 | break; | ||
280 | case 1: // Brand id = 1: Intel Celeron (0.18 micron) processor | ||
281 | strcpy(CPUInfo.strBrandID, "0.18 micron Intel Celeron"); /* Flawfinder: ignore */ | ||
282 | break; | ||
283 | case 2: // Brand id = 2: Intel Pentium III (0.18 micron) processor | ||
284 | strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III"); /* Flawfinder: ignore */ | ||
285 | break; | ||
286 | case 3: // Brand id = 3: Model dependent | ||
287 | if (CPUInfo.uiModel == 6) // If the cpu model is Celeron (well, I'm NOT SURE!!!) | ||
288 | strcpy(CPUInfo.strBrandID, "0.13 micron Intel Celeron"); /* Flawfinder: ignore */ | ||
289 | else | ||
290 | strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III Xeon"); /* Flawfinder: ignore */ | ||
291 | break; | ||
292 | case 4: // Brand id = 4: Intel Pentium III Tualatin (0.13 micron) processor | ||
293 | strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium III"); /* Flawfinder: ignore */ | ||
294 | break; | ||
295 | case 6: // Brand id = 6: Intel Pentium III mobile (0.13 micron) processor | ||
296 | strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium III mobile"); /* Flawfinder: ignore */ | ||
297 | break; | ||
298 | case 7: // Brand id = 7: Intel Celeron mobile (0.13 micron) processor | ||
299 | strcpy(CPUInfo.strBrandID, "0.13 micron Intel Celeron mobile"); /* Flawfinder: ignore */ | ||
300 | break; | ||
301 | case 8: // Brand id = 8: Intel Pentium 4 Willamette (0.18 micron) processor | ||
302 | strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium 4"); /* Flawfinder: ignore */ | ||
303 | break; | ||
304 | case 9: // Brand id = 9: Intel Pentium 4 Northwood (0.13 micron) processor | ||
305 | strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium 4"); /* Flawfinder: ignore */ | ||
306 | break; | ||
307 | case 0xA: // Brand id = 0xA: Intel Pentium 4 Northwood (0.13 micron processor) | ||
308 | strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium 4"); /* Flawfinder: ignore */ | ||
309 | break; // No idea, where the difference to id=9 is | ||
310 | case 0xB: // Brand id = 0xB: Intel Pentium 4 Northwood Xeon (0.13 micron processor) | ||
311 | strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium 4 Xeon"); /* Flawfinder: ignore */ | ||
312 | break; | ||
313 | case 0xE: // Brand id = 0xE: Intel Pentium 4 Willamette Xeon (0.18 micron processor) | ||
314 | strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium 4 Xeon"); /* Flawfinder: ignore */ | ||
315 | break; | ||
316 | default: // Should be never called, but sure is sure | ||
317 | strcpy(CPUInfo.strBrandID, "Unknown"); /* Flawfinder: ignore */ | ||
318 | break; | ||
319 | } | ||
320 | |||
321 | // Then we translate the cpu family | ||
322 | switch (CPUInfo.uiFamily) | ||
323 | { | ||
324 | case 3: // Family = 3: i386 (80386) processor family | ||
325 | strcpy(CPUInfo.strFamily, "Intel i386"); /* Flawfinder: ignore */ | ||
326 | break; | ||
327 | case 4: // Family = 4: i486 (80486) processor family | ||
328 | strcpy(CPUInfo.strFamily, "Intel i486"); /* Flawfinder: ignore */ | ||
329 | break; | ||
330 | case 5: // Family = 5: Pentium (80586) processor family | ||
331 | strcpy(CPUInfo.strFamily, "Intel Pentium"); /* Flawfinder: ignore */ | ||
332 | break; | ||
333 | case 6: // Family = 6: Pentium Pro (80686) processor family | ||
334 | strcpy(CPUInfo.strFamily, "Intel Pentium Pro"); /* Flawfinder: ignore */ | ||
335 | break; | ||
336 | case 15: // Family = 15: Extended family specific | ||
337 | // Masking the extended family | ||
338 | CPUInfo.uiExtendedFamily = (eaxreg >> 20) & 0xFF; | ||
339 | switch (CPUInfo.uiExtendedFamily) | ||
340 | { | ||
341 | case 0: // Family = 15, Ext. Family = 0: Pentium 4 (80786 ??) processor family | ||
342 | strcpy(CPUInfo.strFamily, "Intel Pentium 4"); /* Flawfinder: ignore */ | ||
343 | break; | ||
344 | case 1: // Family = 15, Ext. Family = 1: McKinley (64-bit) processor family | ||
345 | strcpy(CPUInfo.strFamily, "Intel McKinley (IA-64)"); /* Flawfinder: ignore */ | ||
346 | break; | ||
347 | default: // Sure is sure | ||
348 | strcpy(CPUInfo.strFamily, "Unknown Intel Pentium 4+"); /* Flawfinder: ignore */ | ||
349 | break; | ||
350 | } | ||
351 | break; | ||
352 | default: // Failsave | ||
353 | strcpy(CPUInfo.strFamily, "Unknown"); /* Flawfinder: ignore */ | ||
354 | break; | ||
355 | } | ||
356 | |||
357 | // Now we come to the big deal, the exact model name | ||
358 | switch (CPUInfo.uiFamily) | ||
359 | { | ||
360 | case 3: // i386 (80386) processor family | ||
361 | strcpy(CPUInfo.strModel, "Unknown Intel i386"); /* Flawfinder: ignore */ | ||
362 | strncat(strCPUName, "Intel i386", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
363 | break; | ||
364 | case 4: // i486 (80486) processor family | ||
365 | switch (CPUInfo.uiModel) | ||
366 | { | ||
367 | case 0: // Model = 0: i486 DX-25/33 processor model | ||
368 | strcpy(CPUInfo.strModel, "Intel i486 DX-25/33"); /* Flawfinder: ignore */ | ||
369 | strncat(strCPUName, "Intel i486 DX-25/33", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
370 | break; | ||
371 | case 1: // Model = 1: i486 DX-50 processor model | ||
372 | strcpy(CPUInfo.strModel, "Intel i486 DX-50"); /* Flawfinder: ignore */ | ||
373 | strncat(strCPUName, "Intel i486 DX-50", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
374 | break; | ||
375 | case 2: // Model = 2: i486 SX processor model | ||
376 | strcpy(CPUInfo.strModel, "Intel i486 SX"); /* Flawfinder: ignore */ | ||
377 | strncat(strCPUName, "Intel i486 SX", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
378 | break; | ||
379 | case 3: // Model = 3: i486 DX2 (with i487 numeric coprocessor) processor model | ||
380 | strcpy(CPUInfo.strModel, "Intel i486 487/DX2"); /* Flawfinder: ignore */ | ||
381 | strncat(strCPUName, "Intel i486 DX2 with i487 numeric coprocessor", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
382 | break; | ||
383 | case 4: // Model = 4: i486 SL processor model (never heard ?!?) | ||
384 | strcpy(CPUInfo.strModel, "Intel i486 SL"); /* Flawfinder: ignore */ | ||
385 | strncat(strCPUName, "Intel i486 SL", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
386 | break; | ||
387 | case 5: // Model = 5: i486 SX2 processor model | ||
388 | strcpy(CPUInfo.strModel, "Intel i486 SX2"); /* Flawfinder: ignore */ | ||
389 | strncat(strCPUName, "Intel i486 SX2", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
390 | break; | ||
391 | case 7: // Model = 7: i486 write-back enhanced DX2 processor model | ||
392 | strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX2"); /* Flawfinder: ignore */ | ||
393 | strncat(strCPUName, "Intel i486 write-back enhanced DX2", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
394 | break; | ||
395 | case 8: // Model = 8: i486 DX4 processor model | ||
396 | strcpy(CPUInfo.strModel, "Intel i486 DX4"); /* Flawfinder: ignore */ | ||
397 | strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
398 | break; | ||
399 | case 9: // Model = 9: i486 write-back enhanced DX4 processor model | ||
400 | strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX4"); /* Flawfinder: ignore */ | ||
401 | strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
402 | break; | ||
403 | default: // ... | ||
404 | strcpy(CPUInfo.strModel, "Unknown Intel i486"); /* Flawfinder: ignore */ | ||
405 | strncat(strCPUName, "Intel i486 (Unknown model)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
406 | break; | ||
407 | } | ||
408 | break; | ||
409 | case 5: // Pentium (80586) processor family | ||
410 | switch (CPUInfo.uiModel) | ||
411 | { | ||
412 | case 0: // Model = 0: Pentium (P5 A-Step) processor model | ||
413 | strcpy(CPUInfo.strModel, "Intel Pentium (P5 A-Step)"); /* Flawfinder: ignore */ | ||
414 | strncat(strCPUName, "Intel Pentium (P5 A-Step core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
415 | break; // Famous for the DIV bug, as far as I know | ||
416 | case 1: // Model = 1: Pentium 60/66 processor model | ||
417 | strcpy(CPUInfo.strModel, "Intel Pentium 60/66 (P5)"); /* Flawfinder: ignore */ | ||
418 | strncat(strCPUName, "Intel Pentium 60/66 (P5 core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
419 | break; | ||
420 | case 2: // Model = 2: Pentium 75-200 (P54C) processor model | ||
421 | strcpy(CPUInfo.strModel, "Intel Pentium 75-200 (P54C)"); /* Flawfinder: ignore */ | ||
422 | strncat(strCPUName, "Intel Pentium 75-200 (P54C core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
423 | break; | ||
424 | case 3: // Model = 3: Pentium overdrive for 486 systems processor model | ||
425 | strcpy(CPUInfo.strModel, "Intel Pentium for 486 system (P24T Overdrive)"); /* Flawfinder: ignore */ | ||
426 | strncat(strCPUName, "Intel Pentium for 486 (P24T overdrive core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
427 | break; | ||
428 | case 4: // Model = 4: Pentium MMX processor model | ||
429 | strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C)"); /*Flawfinder: ignore*/ | ||
430 | strncat(strCPUName, "Intel Pentium MMX (P55C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
431 | break; | ||
432 | case 7: // Model = 7: Pentium processor model (don't know difference to Model=2) | ||
433 | strcpy(CPUInfo.strModel, "Intel Pentium (P54C)"); /*Flawfinder: ignore*/ | ||
434 | strncat(strCPUName, "Intel Pentium (P54C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
435 | break; | ||
436 | case 8: // Model = 8: Pentium MMX (0.25 micron) processor model | ||
437 | strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C), 0.25 micron"); /*Flawfinder: ignore*/ | ||
438 | strncat(strCPUName, "Intel Pentium MMX (P55C core), 0.25 micron", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
439 | break; | ||
440 | default: // ... | ||
441 | strcpy(CPUInfo.strModel, "Unknown Intel Pentium"); /*Flawfinder: ignore*/ | ||
442 | strncat(strCPUName, "Intel Pentium (Unknown P5-model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
443 | break; | ||
444 | } | ||
445 | break; | ||
446 | case 6: // Pentium Pro (80686) processor family | ||
447 | switch (CPUInfo.uiModel) | ||
448 | { | ||
449 | case 0: // Model = 0: Pentium Pro (P6 A-Step) processor model | ||
450 | strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6 A-Step)"); /*Flawfinder: ignore*/ | ||
451 | strncat(strCPUName, "Intel Pentium Pro (P6 A-Step core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
452 | break; | ||
453 | case 1: // Model = 1: Pentium Pro | ||
454 | strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6)"); /*Flawfinder: ignore*/ | ||
455 | strncat(strCPUName, "Intel Pentium Pro (P6 core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
456 | break; | ||
457 | case 3: // Model = 3: Pentium II (66 MHz FSB, I think) processor model | ||
458 | strcpy(CPUInfo.strModel, "Intel Pentium II Model 3, 0.28 micron"); /*Flawfinder: ignore*/ | ||
459 | strncat(strCPUName, "Intel Pentium II (Model 3 core, 0.28 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
460 | break; | ||
461 | case 5: // Model = 5: Pentium II/Xeon/Celeron (0.25 micron) processor model | ||
462 | strcpy(CPUInfo.strModel, "Intel Pentium II Model 5/Xeon/Celeron, 0.25 micron"); /*Flawfinder: ignore*/ | ||
463 | strncat(strCPUName, "Intel Pentium II/Xeon/Celeron (Model 5 core, 0.25 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
464 | break; | ||
465 | case 6: // Model = 6: Pentium II with internal L2 cache | ||
466 | strcpy(CPUInfo.strModel, "Intel Pentium II - internal L2 cache"); /*Flawfinder: ignore*/ | ||
467 | strncat(strCPUName, "Intel Pentium II with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
468 | break; | ||
469 | case 7: // Model = 7: Pentium III/Xeon (extern L2 cache) processor model | ||
470 | strcpy(CPUInfo.strModel, "Intel Pentium III/Pentium III Xeon - external L2 cache, 0.25 micron"); /*Flawfinder: ignore*/ | ||
471 | strncat(strCPUName, "Intel Pentium III/Pentium III Xeon (0.25 micron process) with external L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
472 | break; | ||
473 | case 8: // Model = 8: Pentium III/Xeon/Celeron (256 KB on-die L2 cache) processor model | ||
474 | strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/ | ||
475 | // We want to know it exactly: | ||
476 | switch (CPUInfo.uiBrandID) | ||
477 | { | ||
478 | case 1: // Model = 8, Brand id = 1: Celeron (on-die L2 cache) processor model | ||
479 | strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
480 | break; | ||
481 | case 2: // Model = 8, Brand id = 2: Pentium III (on-die L2 cache) processor model (my current cpu :-)) | ||
482 | strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
483 | break; | ||
484 | case 3: // Model = 8, Brand id = 3: Pentium III Xeon (on-die L2 cache) processor model | ||
485 | strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
486 | break; | ||
487 | default: // ...² | ||
488 | strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
489 | break; | ||
490 | } | ||
491 | break; | ||
492 | case 0xA: // Model = 0xA: Pentium III/Xeon/Celeron (1 or 2 MB on-die L2 cache) processor model | ||
493 | strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/ | ||
494 | // Exact detection: | ||
495 | switch (CPUInfo.uiBrandID) | ||
496 | { | ||
497 | case 1: // Model = 0xA, Brand id = 1: Celeron (1 or 2 MB on-die L2 cache (does it exist??)) processor model | ||
498 | strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
499 | break; | ||
500 | case 2: // Model = 0xA, Brand id = 2: Pentium III (1 or 2 MB on-die L2 cache (never seen...)) processor model | ||
501 | strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
502 | break; | ||
503 | case 3: // Model = 0xA, Brand id = 3: Pentium III Xeon (1 or 2 MB on-die L2 cache) processor model | ||
504 | strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
505 | break; | ||
506 | default: // Getting bored of this............ | ||
507 | strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
508 | break; | ||
509 | } | ||
510 | break; | ||
511 | case 0xB: // Model = 0xB: Pentium III/Xeon/Celeron (Tualatin core, on-die cache) processor model | ||
512 | strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.13 micron"); /*Flawfinder: ignore*/ | ||
513 | // Omniscient: ;-) | ||
514 | switch (CPUInfo.uiBrandID) | ||
515 | { | ||
516 | case 3: // Model = 0xB, Brand id = 3: Celeron (Tualatin core) processor model | ||
517 | strncat(strCPUName, "Intel Celeron (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
518 | break; | ||
519 | case 4: // Model = 0xB, Brand id = 4: Pentium III (Tualatin core) processor model | ||
520 | strncat(strCPUName, "Intel Pentium III (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
521 | break; | ||
522 | case 7: // Model = 0xB, Brand id = 7: Celeron mobile (Tualatin core) processor model | ||
523 | strncat(strCPUName, "Intel Celeron mobile (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
524 | break; | ||
525 | default: // *bored* | ||
526 | strncat(strCPUName, "Intel Pentium III Tualatin core (unknown model, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
527 | break; | ||
528 | } | ||
529 | break; | ||
530 | default: // *more bored* | ||
531 | strcpy(CPUInfo.strModel, "Unknown Intel Pentium Pro"); /*Flawfinder: ignore*/ | ||
532 | strncat(strCPUName, "Intel Pentium Pro (Unknown model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
533 | break; | ||
534 | } | ||
535 | break; | ||
536 | case 15: // Extended processor family | ||
537 | // Masking the extended model | ||
538 | CPUInfo.uiExtendedModel = (eaxreg >> 16) & 0xFF; | ||
539 | switch (CPUInfo.uiModel) | ||
540 | { | ||
541 | case 0: // Model = 0: Pentium 4 Willamette (A-Step) core | ||
542 | if ((CPUInfo.uiBrandID) == 8) // Brand id = 8: P4 Willamette | ||
543 | { | ||
544 | strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette (A-Step)"); /*Flawfinder: ignore*/ | ||
545 | strncat(strCPUName, "Intel Pentium 4 Willamette (A-Step)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ | ||
546 | } | ||
547 | else // else Xeon | ||
548 | { | ||
549 | strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon (A-Step)"); /* Flawfinder: ignore */ | ||
550 | strncat(strCPUName, "Intel Pentium 4 Willamette Xeon (A-Step)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ | ||
551 | } | ||
552 | break; | ||
553 | case 1: // Model = 1: Pentium 4 Willamette core | ||
554 | if ((CPUInfo.uiBrandID) == 8) // Brand id = 8: P4 Willamette | ||
555 | { | ||
556 | strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette"); /* Flawfinder: ignore */ | ||
557 | strncat(strCPUName, "Intel Pentium 4 Willamette", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ | ||
558 | } | ||
559 | else // else Xeon | ||
560 | { | ||
561 | strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon"); /* Flawfinder: ignore */ | ||
562 | strncat(strCPUName, "Intel Pentium 4 Willamette Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ | ||
563 | } | ||
564 | break; | ||
565 | case 2: // Model = 2: Pentium 4 Northwood core | ||
566 | if (((CPUInfo.uiBrandID) == 9) || ((CPUInfo.uiBrandID) == 0xA)) // P4 Willamette | ||
567 | { | ||
568 | strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood"); /* Flawfinder: ignore */ | ||
569 | strncat(strCPUName, "Intel Pentium 4 Northwood", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ | ||
570 | } | ||
571 | else // Xeon | ||
572 | { | ||
573 | strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood Xeon"); /* Flawfinder: ignore */ | ||
574 | strncat(strCPUName, "Intel Pentium 4 Northwood Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ | ||
575 | } | ||
576 | break; | ||
577 | default: // Silly stupid never used failsave option | ||
578 | strcpy(CPUInfo.strModel, "Unknown Intel Pentium 4"); /* Flawfinder: ignore */ | ||
579 | strncat(strCPUName, "Intel Pentium 4 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ | ||
580 | break; | ||
581 | } | ||
582 | break; | ||
583 | default: // *grmpf* | ||
584 | strcpy(CPUInfo.strModel, "Unknown Intel model"); /* Flawfinder: ignore */ | ||
585 | strncat(strCPUName, "Intel (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ | ||
586 | break; | ||
587 | } | ||
588 | |||
589 | // After the long processor model block we now come to the processors serial | ||
590 | // number. | ||
591 | // First of all we check if the processor supports the serial number | ||
592 | if (CPUInfo.MaxSupportedLevel >= 3) | ||
593 | { | ||
594 | // If it supports the serial number CPUID level 0x00000003 we read the data | ||
595 | unsigned long sig1, sig2, sig3; | ||
596 | __asm | ||
597 | { | ||
598 | mov eax, 1 | ||
599 | cpuid | ||
600 | mov sig1, eax | ||
601 | mov eax, 3 | ||
602 | cpuid | ||
603 | mov sig2, ecx | ||
604 | mov sig3, edx | ||
605 | } | ||
606 | // Then we convert the data to a readable string | ||
607 | snprintf( | ||
608 | CPUInfo.strProcessorSerial, | ||
609 | sizeof(CPUInfo.strProcessorSerial), | ||
610 | "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX", | ||
611 | sig1 >> 16, | ||
612 | sig1 & 0xFFFF, | ||
613 | sig3 >> 16, | ||
614 | sig3 & 0xFFFF, | ||
615 | sig2 >> 16, sig2 & 0xFFFF); /* Flawfinder: ignore */ | ||
616 | } | ||
617 | else | ||
618 | { | ||
619 | // If there's no serial number support we just put "No serial number" | ||
620 | snprintf( | ||
621 | CPUInfo.strProcessorSerial, | ||
622 | sizeof(CPUInfo.strProcessorSerial), | ||
623 | "No Processor Serial Number"); /* Flawfinder: ignore */ | ||
624 | } | ||
625 | |||
626 | // Now we get the standard processor extensions | ||
627 | GetStandardProcessorExtensions(); | ||
628 | |||
629 | // And finally the processor configuration (caches, TLBs, ...) and translate | ||
630 | // the data to readable strings | ||
631 | GetStandardProcessorConfiguration(); | ||
632 | TranslateProcessorConfiguration(); | ||
633 | |||
634 | // At last... | ||
635 | return true; | ||
636 | #else | ||
637 | return FALSE; | ||
638 | #endif | ||
639 | } | ||
640 | |||
641 | // bool CProcessor::AnalyzeAMDProcessor() | ||
642 | // ====================================== | ||
643 | // Private class function for analyzing an AMD processor | ||
644 | //////////////////////////////////////////////////////// | ||
645 | bool CProcessor::AnalyzeAMDProcessor() | ||
646 | { | ||
647 | #if LL_WINDOWS | ||
648 | unsigned long eaxreg, ebxreg, ecxreg, edxreg; | ||
649 | |||
650 | // First of all we check if the CPUID command is available | ||
651 | if (!CheckCPUIDPresence()) | ||
652 | return 0; | ||
653 | |||
654 | // Now we get the CPUID standard level 0x00000001 | ||
655 | __asm | ||
656 | { | ||
657 | mov eax, 1 | ||
658 | cpuid | ||
659 | mov eaxreg, eax | ||
660 | mov ebxreg, ebx | ||
661 | mov edxreg, edx | ||
662 | } | ||
663 | |||
664 | // Then we mask the model, family, stepping and type (AMD does not support brand id) | ||
665 | CPUInfo.uiStepping = eaxreg & 0xF; | ||
666 | CPUInfo.uiModel = (eaxreg >> 4) & 0xF; | ||
667 | CPUInfo.uiFamily = (eaxreg >> 8) & 0xF; | ||
668 | CPUInfo.uiType = (eaxreg >> 12) & 0x3; | ||
669 | |||
670 | // After that, we translate the processor type (see CProcessor::AnalyzeIntelProcessor() | ||
671 | // for further comments on this) | ||
672 | switch (CPUInfo.uiType) | ||
673 | { | ||
674 | case 0: | ||
675 | strcpy(CPUInfo.strType, "Original OEM"); /* Flawfinder: ignore */ | ||
676 | strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */ | ||
677 | strcat(strCPUName, " "); /*Flawfinder: ignore*/ | ||
678 | break; | ||
679 | case 1: | ||
680 | strcpy(CPUInfo.strType, "Overdrive"); /* Flawfinder: ignore */ | ||
681 | strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */ | ||
682 | strcat(strCPUName, " "); /*Flawfinder: ignore*/ | ||
683 | break; | ||
684 | case 2: | ||
685 | strcpy(CPUInfo.strType, "Dual-capable"); /* Flawfinder: ignore */ | ||
686 | strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */ | ||
687 | strcat(strCPUName, " "); /*Flawfinder: ignore*/ | ||
688 | break; | ||
689 | case 3: | ||
690 | strcpy(CPUInfo.strType, "Reserved"); /* Flawfinder: ignore */ | ||
691 | break; | ||
692 | default: | ||
693 | strcpy(CPUInfo.strType, "Unknown"); /* Flawfinder: ignore */ | ||
694 | break; | ||
695 | } | ||
696 | |||
697 | // Now we check if the processor supports the brand id string extended CPUID level | ||
698 | if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000004) | ||
699 | { | ||
700 | // If it supports the extended CPUID level 0x80000004 we read the data | ||
701 | char tmp[52]; /* Flawfinder: ignore */ | ||
702 | memset(tmp, 0, sizeof(tmp)); | ||
703 | __asm | ||
704 | { | ||
705 | mov eax, 0x80000002 | ||
706 | cpuid | ||
707 | mov dword ptr [tmp], eax | ||
708 | mov dword ptr [tmp+4], ebx | ||
709 | mov dword ptr [tmp+8], ecx | ||
710 | mov dword ptr [tmp+12], edx | ||
711 | mov eax, 0x80000003 | ||
712 | cpuid | ||
713 | mov dword ptr [tmp+16], eax | ||
714 | mov dword ptr [tmp+20], ebx | ||
715 | mov dword ptr [tmp+24], ecx | ||
716 | mov dword ptr [tmp+28], edx | ||
717 | mov eax, 0x80000004 | ||
718 | cpuid | ||
719 | mov dword ptr [tmp+32], eax | ||
720 | mov dword ptr [tmp+36], ebx | ||
721 | mov dword ptr [tmp+40], ecx | ||
722 | mov dword ptr [tmp+44], edx | ||
723 | } | ||
724 | // And copy it to the brand id string | ||
725 | strncpy(CPUInfo.strBrandID, tmp,sizeof(CPUInfo.strBrandID-1)); /* Flawfinder: ignore */ | ||
726 | CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID-1)]='\0'; | ||
727 | } | ||
728 | else | ||
729 | { | ||
730 | // Or just tell there is no brand id string support | ||
731 | strcpy(CPUInfo.strBrandID, "Not supported"); /* Flawfinder: ignore */ | ||
732 | } | ||
733 | |||
734 | // After that we translate the processor family | ||
735 | switch(CPUInfo.uiFamily) | ||
736 | { | ||
737 | case 4: // Family = 4: 486 (80486) or 5x86 (80486) processor family | ||
738 | switch (CPUInfo.uiModel) | ||
739 | { | ||
740 | case 3: // Thanks to AMD for this nice form of family | ||
741 | case 7: // detection.... *grmpf* | ||
742 | case 8: | ||
743 | case 9: | ||
744 | strcpy(CPUInfo.strFamily, "AMD 80486"); /* Flawfinder: ignore */ | ||
745 | break; | ||
746 | case 0xE: | ||
747 | case 0xF: | ||
748 | strcpy(CPUInfo.strFamily, "AMD 5x86"); /* Flawfinder: ignore */ | ||
749 | break; | ||
750 | default: | ||
751 | strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */ | ||
752 | break; | ||
753 | } | ||
754 | break; | ||
755 | case 5: // Family = 5: K5 or K6 processor family | ||
756 | switch (CPUInfo.uiModel) | ||
757 | { | ||
758 | case 0: | ||
759 | case 1: | ||
760 | case 2: | ||
761 | case 3: | ||
762 | strcpy(CPUInfo.strFamily, "AMD K5"); /* Flawfinder: ignore */ | ||
763 | break; | ||
764 | case 6: | ||
765 | case 7: | ||
766 | case 8: | ||
767 | case 9: | ||
768 | strcpy(CPUInfo.strFamily, "AMD K6"); /* Flawfinder: ignore */ | ||
769 | break; | ||
770 | default: | ||
771 | strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */ | ||
772 | break; | ||
773 | } | ||
774 | break; | ||
775 | case 6: // Family = 6: K7 (Athlon, ...) processor family | ||
776 | strcpy(CPUInfo.strFamily, "AMD K7"); /* Flawfinder: ignore */ | ||
777 | break; | ||
778 | default: // For security | ||
779 | strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */ | ||
780 | break; | ||
781 | } | ||
782 | |||
783 | // After the family detection we come to the specific processor model | ||
784 | // detection | ||
785 | switch (CPUInfo.uiFamily) | ||
786 | { | ||
787 | case 4: // Family = 4: 486 (80486) or 5x85 (80486) processor family | ||
788 | switch (CPUInfo.uiModel) | ||
789 | { | ||
790 | case 3: // Model = 3: 80486 DX2 | ||
791 | strcpy(CPUInfo.strModel, "AMD 80486 DX2"); /* Flawfinder: ignore */ | ||
792 | strncat(strCPUName, "AMD 80486 DX2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
793 | break; | ||
794 | case 7: // Model = 7: 80486 write-back enhanced DX2 | ||
795 | strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX2"); /* Flawfinder: ignore */ | ||
796 | strncat(strCPUName, "AMD 80486 write-back enhanced DX2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
797 | break; | ||
798 | case 8: // Model = 8: 80486 DX4 | ||
799 | strcpy(CPUInfo.strModel, "AMD 80486 DX4"); /* Flawfinder: ignore */ | ||
800 | strncat(strCPUName, "AMD 80486 DX4", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
801 | break; | ||
802 | case 9: // Model = 9: 80486 write-back enhanced DX4 | ||
803 | strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX4"); /* Flawfinder: ignore */ | ||
804 | strncat(strCPUName, "AMD 80486 write-back enhanced DX4", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
805 | break; | ||
806 | case 0xE: // Model = 0xE: 5x86 | ||
807 | strcpy(CPUInfo.strModel, "AMD 5x86"); /* Flawfinder: ignore */ | ||
808 | strncat(strCPUName, "AMD 5x86", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
809 | break; | ||
810 | case 0xF: // Model = 0xF: 5x86 write-back enhanced (oh my god.....) | ||
811 | strcpy(CPUInfo.strModel, "AMD 5x86 write-back enhanced"); /* Flawfinder: ignore */ | ||
812 | strncat(strCPUName, "AMD 5x86 write-back enhanced", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
813 | break; | ||
814 | default: // ... | ||
815 | strcpy(CPUInfo.strModel, "Unknown AMD 80486 or 5x86 model"); /* Flawfinder: ignore */ | ||
816 | strncat(strCPUName, "AMD 80486 or 5x86 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
817 | break; | ||
818 | } | ||
819 | break; | ||
820 | case 5: // Family = 5: K5 / K6 processor family | ||
821 | switch (CPUInfo.uiModel) | ||
822 | { | ||
823 | case 0: // Model = 0: K5 SSA 5 (Pentium Rating *ggg* 75, 90 and 100 Mhz) | ||
824 | strcpy(CPUInfo.strModel, "AMD K5 SSA5 (PR75, PR90, PR100)"); /* Flawfinder: ignore */ | ||
825 | strncat(strCPUName, "AMD K5 SSA5 (PR75, PR90, PR100)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
826 | break; | ||
827 | case 1: // Model = 1: K5 5k86 (PR 120 and 133 MHz) | ||
828 | strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR120, PR133)"); /* Flawfinder: ignore */ | ||
829 | strncat(strCPUName, "AMD K5 5k86 (PR120, PR133)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
830 | break; | ||
831 | case 2: // Model = 2: K5 5k86 (PR 166 MHz) | ||
832 | strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR166)"); /* Flawfinder: ignore */ | ||
833 | strncat(strCPUName, "AMD K5 5k86 (PR166)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
834 | break; | ||
835 | case 3: // Model = 3: K5 5k86 (PR 200 MHz) | ||
836 | strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR200)"); /* Flawfinder: ignore */ | ||
837 | strncat(strCPUName, "AMD K5 5k86 (PR200)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
838 | break; | ||
839 | case 6: // Model = 6: K6 | ||
840 | strcpy(CPUInfo.strModel, "AMD K6 (0.30 micron)"); /* Flawfinder: ignore */ | ||
841 | strncat(strCPUName, "AMD K6 (0.30 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
842 | break; | ||
843 | case 7: // Model = 7: K6 (0.25 micron) | ||
844 | strcpy(CPUInfo.strModel, "AMD K6 (0.25 micron)"); /* Flawfinder: ignore */ | ||
845 | strncat(strCPUName, "AMD K6 (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
846 | break; | ||
847 | case 8: // Model = 8: K6-2 | ||
848 | strcpy(CPUInfo.strModel, "AMD K6-2"); /* Flawfinder: ignore */ | ||
849 | strncat(strCPUName, "AMD K6-2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
850 | break; | ||
851 | case 9: // Model = 9: K6-III | ||
852 | strcpy(CPUInfo.strModel, "AMD K6-III"); /* Flawfinder: ignore */ | ||
853 | strncat(strCPUName, "AMD K6-III", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
854 | break; | ||
855 | case 0xD: // Model = 0xD: K6-2+ / K6-III+ | ||
856 | strcpy(CPUInfo.strModel, "AMD K6-2+ or K6-III+ (0.18 micron)"); /* Flawfinder: ignore */ | ||
857 | strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); | ||
858 | break; | ||
859 | default: // ... | ||
860 | strcpy(CPUInfo.strModel, "Unknown AMD K5 or K6 model"); /* Flawfinder: ignore */ | ||
861 | strncat(strCPUName, "AMD K5 or K6 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
862 | break; | ||
863 | } | ||
864 | break; | ||
865 | case 6: // Family = 6: K7 processor family (AMDs first good processors) | ||
866 | switch (CPUInfo.uiModel) | ||
867 | { | ||
868 | case 1: // Athlon | ||
869 | strcpy(CPUInfo.strModel, "AMD Athlon (0.25 micron)"); /* Flawfinder: ignore */ | ||
870 | strncat(strCPUName, "AMD Athlon (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
871 | break; | ||
872 | case 2: // Athlon (0.18 micron) | ||
873 | strcpy(CPUInfo.strModel, "AMD Athlon (0.18 micron)"); /* Flawfinder: ignore */ | ||
874 | strncat(strCPUName, "AMD Athlon (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
875 | break; | ||
876 | case 3: // Duron (Spitfire core) | ||
877 | strcpy(CPUInfo.strModel, "AMD Duron (Spitfire)"); /* Flawfinder: ignore */ | ||
878 | strncat(strCPUName, "AMD Duron (Spitfire core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
879 | break; | ||
880 | case 4: // Athlon (Thunderbird core) | ||
881 | strcpy(CPUInfo.strModel, "AMD Athlon (Thunderbird)"); /* Flawfinder: ignore */ | ||
882 | strncat(strCPUName, "AMD Athlon (Thunderbird core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
883 | break; | ||
884 | case 6: // Athlon MP / Mobile Athlon (Palomino core) | ||
885 | strcpy(CPUInfo.strModel, "AMD Athlon MP/Mobile Athlon (Palomino)"); /* Flawfinder: ignore */ | ||
886 | strncat(strCPUName, "AMD Athlon MP/Mobile Athlon (Palomino core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
887 | break; | ||
888 | case 7: // Mobile Duron (Morgan core) | ||
889 | strcpy(CPUInfo.strModel, "AMD Mobile Duron (Morgan)"); /* Flawfinder: ignore */ | ||
890 | strncat(strCPUName, "AMD Mobile Duron (Morgan core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
891 | break; | ||
892 | default: // ... | ||
893 | strcpy(CPUInfo.strModel, "Unknown AMD K7 model"); /* Flawfinder: ignore */ | ||
894 | strncat(strCPUName, "AMD K7 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
895 | break; | ||
896 | } | ||
897 | break; | ||
898 | default: // ... | ||
899 | strcpy(CPUInfo.strModel, "Unknown AMD model"); /* Flawfinder: ignore */ | ||
900 | strncat(strCPUName, "AMD (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ | ||
901 | break; | ||
902 | } | ||
903 | |||
904 | // Now we read the standard processor extension that are stored in the same | ||
905 | // way the Intel standard extensions are | ||
906 | GetStandardProcessorExtensions(); | ||
907 | |||
908 | // Then we check if theres an extended CPUID level support | ||
909 | if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000001) | ||
910 | { | ||
911 | // If we can access the extended CPUID level 0x80000001 we get the | ||
912 | // edx register | ||
913 | __asm | ||
914 | { | ||
915 | mov eax, 0x80000001 | ||
916 | cpuid | ||
917 | mov edxreg, edx | ||
918 | } | ||
919 | |||
920 | // Now we can mask some AMD specific cpu extensions | ||
921 | CPUInfo._Ext.EMMX_MultimediaExtensions = CheckBit(edxreg, 22); | ||
922 | CPUInfo._Ext.AA64_AMD64BitArchitecture = CheckBit(edxreg, 29); | ||
923 | CPUInfo._Ext._E3DNOW_InstructionExtensions = CheckBit(edxreg, 30); | ||
924 | CPUInfo._Ext._3DNOW_InstructionExtensions = CheckBit(edxreg, 31); | ||
925 | } | ||
926 | |||
927 | // After that we check if the processor supports the ext. CPUID level | ||
928 | // 0x80000006 | ||
929 | if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000006) | ||
930 | { | ||
931 | // If it's present, we read it out | ||
932 | __asm | ||
933 | { | ||
934 | mov eax, 0x80000005 | ||
935 | cpuid | ||
936 | mov eaxreg, eax | ||
937 | mov ebxreg, ebx | ||
938 | mov ecxreg, ecx | ||
939 | mov edxreg, edx | ||
940 | } | ||
941 | |||
942 | // Then we mask the L1 Data TLB information | ||
943 | if ((ebxreg >> 16) && (eaxreg >> 16)) | ||
944 | { | ||
945 | CPUInfo._Data.bPresent = true; | ||
946 | strcpy(CPUInfo._Data.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/ | ||
947 | CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF; | ||
948 | CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF; | ||
949 | } | ||
950 | else if (eaxreg >> 16) | ||
951 | { | ||
952 | CPUInfo._Data.bPresent = true; | ||
953 | strcpy(CPUInfo._Data.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/ | ||
954 | CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF; | ||
955 | CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF; | ||
956 | } | ||
957 | else if (ebxreg >> 16) | ||
958 | { | ||
959 | CPUInfo._Data.bPresent = true; | ||
960 | strcpy(CPUInfo._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/ | ||
961 | CPUInfo._Data.uiAssociativeWays = (ebxreg >> 24) & 0xFF; | ||
962 | CPUInfo._Data.uiEntries = (ebxreg >> 16) & 0xFF; | ||
963 | } | ||
964 | if (CPUInfo._Data.uiAssociativeWays == 0xFF) | ||
965 | CPUInfo._Data.uiAssociativeWays = (unsigned int) -1; | ||
966 | |||
967 | // Now the L1 Instruction/Code TLB information | ||
968 | if ((ebxreg & 0xFFFF) && (eaxreg & 0xFFFF)) | ||
969 | { | ||
970 | CPUInfo._Instruction.bPresent = true; | ||
971 | strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/ | ||
972 | CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF; | ||
973 | CPUInfo._Instruction.uiEntries = eaxreg & 0xFF; | ||
974 | } | ||
975 | else if (eaxreg & 0xFFFF) | ||
976 | { | ||
977 | CPUInfo._Instruction.bPresent = true; | ||
978 | strcpy(CPUInfo._Instruction.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/ | ||
979 | CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF; | ||
980 | CPUInfo._Instruction.uiEntries = eaxreg & 0xFF; | ||
981 | } | ||
982 | else if (ebxreg & 0xFFFF) | ||
983 | { | ||
984 | CPUInfo._Instruction.bPresent = true; | ||
985 | strcpy(CPUInfo._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/ | ||
986 | CPUInfo._Instruction.uiAssociativeWays = (ebxreg >> 8) & 0xFF; | ||
987 | CPUInfo._Instruction.uiEntries = ebxreg & 0xFF; | ||
988 | } | ||
989 | if (CPUInfo._Instruction.uiAssociativeWays == 0xFF) | ||
990 | CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1; | ||
991 | |||
992 | // Then we read the L1 data cache information | ||
993 | if ((ecxreg >> 24) > 0) | ||
994 | { | ||
995 | CPUInfo._L1.Data.bPresent = true; | ||
996 | snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", ecxreg >> 24); /*Flawfinder: ignore*/ | ||
997 | CPUInfo._L1.Data.uiAssociativeWays = (ecxreg >> 15) & 0xFF; | ||
998 | CPUInfo._L1.Data.uiLineSize = ecxreg & 0xFF; | ||
999 | } | ||
1000 | // After that we read the L2 instruction/code cache information | ||
1001 | if ((edxreg >> 24) > 0) | ||
1002 | { | ||
1003 | CPUInfo._L1.Instruction.bPresent = true; | ||
1004 | snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", edxreg >> 24); /*Flawfinder: ignore*/ | ||
1005 | CPUInfo._L1.Instruction.uiAssociativeWays = (edxreg >> 15) & 0xFF; | ||
1006 | CPUInfo._L1.Instruction.uiLineSize = edxreg & 0xFF; | ||
1007 | } | ||
1008 | |||
1009 | // Note: I'm not absolutely sure that the L1 page size code (the | ||
1010 | // 'if/else if/else if' structs above) really detects the real page | ||
1011 | // size for the TLB. Somebody should check it.... | ||
1012 | |||
1013 | // Now we read the ext. CPUID level 0x80000006 | ||
1014 | __asm | ||
1015 | { | ||
1016 | mov eax, 0x80000006 | ||
1017 | cpuid | ||
1018 | mov eaxreg, eax | ||
1019 | mov ebxreg, ebx | ||
1020 | mov ecxreg, ecx | ||
1021 | } | ||
1022 | |||
1023 | // We only mask the unified L2 cache masks (never heard of an | ||
1024 | // L2 cache that is divided in data and code parts) | ||
1025 | if (((ecxreg >> 12) & 0xF) > 0) | ||
1026 | { | ||
1027 | CPUInfo._L2.bPresent = true; | ||
1028 | snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", ecxreg >> 16); /*Flawfinder: ignore*/ | ||
1029 | switch ((ecxreg >> 12) & 0xF) | ||
1030 | { | ||
1031 | case 1: | ||
1032 | CPUInfo._L2.uiAssociativeWays = 1; | ||
1033 | break; | ||
1034 | case 2: | ||
1035 | CPUInfo._L2.uiAssociativeWays = 2; | ||
1036 | break; | ||
1037 | case 4: | ||
1038 | CPUInfo._L2.uiAssociativeWays = 4; | ||
1039 | break; | ||
1040 | case 6: | ||
1041 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1042 | break; | ||
1043 | case 8: | ||
1044 | CPUInfo._L2.uiAssociativeWays = 16; | ||
1045 | break; | ||
1046 | case 0xF: | ||
1047 | CPUInfo._L2.uiAssociativeWays = (unsigned int) -1; | ||
1048 | break; | ||
1049 | default: | ||
1050 | CPUInfo._L2.uiAssociativeWays = 0; | ||
1051 | break; | ||
1052 | } | ||
1053 | CPUInfo._L2.uiLineSize = ecxreg & 0xFF; | ||
1054 | } | ||
1055 | } | ||
1056 | else | ||
1057 | { | ||
1058 | // If we could not detect the ext. CPUID level 0x80000006 we | ||
1059 | // try to read the standard processor configuration. | ||
1060 | GetStandardProcessorConfiguration(); | ||
1061 | } | ||
1062 | // After reading we translate the configuration to strings | ||
1063 | TranslateProcessorConfiguration(); | ||
1064 | |||
1065 | // And finally exit | ||
1066 | return true; | ||
1067 | #else | ||
1068 | return FALSE; | ||
1069 | #endif | ||
1070 | } | ||
1071 | |||
1072 | // bool CProcessor::AnalyzeUnknownProcessor() | ||
1073 | // ========================================== | ||
1074 | // Private class function to analyze an unknown (No Intel or AMD) processor | ||
1075 | /////////////////////////////////////////////////////////////////////////// | ||
1076 | bool CProcessor::AnalyzeUnknownProcessor() | ||
1077 | { | ||
1078 | #if LL_WINDOWS | ||
1079 | unsigned long eaxreg, ebxreg; | ||
1080 | |||
1081 | // We check if the CPUID command is available | ||
1082 | if (!CheckCPUIDPresence()) | ||
1083 | return false; | ||
1084 | |||
1085 | // First of all we read the standard CPUID level 0x00000001 | ||
1086 | // This level should be available on every x86-processor clone | ||
1087 | __asm | ||
1088 | { | ||
1089 | mov eax, 1 | ||
1090 | cpuid | ||
1091 | mov eaxreg, eax | ||
1092 | mov ebxreg, ebx | ||
1093 | } | ||
1094 | // Then we mask the processor model, family, type and stepping | ||
1095 | CPUInfo.uiStepping = eaxreg & 0xF; | ||
1096 | CPUInfo.uiModel = (eaxreg >> 4) & 0xF; | ||
1097 | CPUInfo.uiFamily = (eaxreg >> 8) & 0xF; | ||
1098 | CPUInfo.uiType = (eaxreg >> 12) & 0x3; | ||
1099 | |||
1100 | // To have complete information we also mask the brand id | ||
1101 | CPUInfo.uiBrandID = ebxreg & 0xF; | ||
1102 | |||
1103 | // Then we get the standard processor extensions | ||
1104 | GetStandardProcessorExtensions(); | ||
1105 | |||
1106 | // Now we mark everything we do not know as unknown | ||
1107 | strcpy(strCPUName, "Unknown"); /*Flawfinder: ignore*/ | ||
1108 | |||
1109 | strcpy(CPUInfo._Data.strTLB, "Unknown"); /*Flawfinder: ignore*/ | ||
1110 | strcpy(CPUInfo._Instruction.strTLB, "Unknown"); /*Flawfinder: ignore*/ | ||
1111 | |||
1112 | strcpy(CPUInfo._Trace.strCache, "Unknown"); /*Flawfinder: ignore*/ | ||
1113 | strcpy(CPUInfo._L1.Data.strCache, "Unknown"); /*Flawfinder: ignore*/ | ||
1114 | strcpy(CPUInfo._L1.Instruction.strCache, "Unknown"); /*Flawfinder: ignore*/ | ||
1115 | strcpy(CPUInfo._L2.strCache, "Unknown"); /*Flawfinder: ignore*/ | ||
1116 | strcpy(CPUInfo._L3.strCache, "Unknown"); /*Flawfinder: ignore*/ | ||
1117 | |||
1118 | strcpy(CPUInfo.strProcessorSerial, "Unknown / Not supported"); /*Flawfinder: ignore*/ | ||
1119 | |||
1120 | // For the family, model and brand id we can only print the numeric value | ||
1121 | snprintf(CPUInfo.strBrandID, sizeof(CPUInfo.strBrandID), "Brand-ID number %d", CPUInfo.uiBrandID); /*Flawfinder: ignore*/ | ||
1122 | snprintf(CPUInfo.strFamily, sizeof(CPUInfo.strFamily), "Family number %d", CPUInfo.uiFamily); /*Flawfinder: ignore*/ | ||
1123 | snprintf(CPUInfo.strModel, sizeof(CPUInfo.strModel), "Model number %d", CPUInfo.uiModel); /*Flawfinder: ignore*/ | ||
1124 | |||
1125 | // Nevertheless we can determine the processor type | ||
1126 | switch (CPUInfo.uiType) | ||
1127 | { | ||
1128 | case 0: | ||
1129 | strcpy(CPUInfo.strType, "Original OEM"); /*Flawfinder: ignore*/ | ||
1130 | break; | ||
1131 | case 1: | ||
1132 | strcpy(CPUInfo.strType, "Overdrive"); /*Flawfinder: ignore*/ | ||
1133 | break; | ||
1134 | case 2: | ||
1135 | strcpy(CPUInfo.strType, "Dual-capable"); /*Flawfinder: ignore*/ | ||
1136 | break; | ||
1137 | case 3: | ||
1138 | strcpy(CPUInfo.strType, "Reserved"); /*Flawfinder: ignore*/ | ||
1139 | break; | ||
1140 | default: | ||
1141 | strcpy(CPUInfo.strType, "Unknown"); /*Flawfinder: ignore*/ | ||
1142 | break; | ||
1143 | } | ||
1144 | |||
1145 | // And thats it | ||
1146 | return true; | ||
1147 | #else | ||
1148 | return FALSE; | ||
1149 | #endif | ||
1150 | } | ||
1151 | |||
1152 | // bool CProcessor::CheckCPUIDPresence() | ||
1153 | // ===================================== | ||
1154 | // This function checks if the CPUID command is available on the current | ||
1155 | // processor | ||
1156 | //////////////////////////////////////////////////////////////////////// | ||
1157 | bool CProcessor::CheckCPUIDPresence() | ||
1158 | { | ||
1159 | #if LL_WINDOWS | ||
1160 | unsigned long BitChanged; | ||
1161 | |||
1162 | // We've to check if we can toggle the flag register bit 21 | ||
1163 | // If we can't the processor does not support the CPUID command | ||
1164 | __asm | ||
1165 | { | ||
1166 | pushfd | ||
1167 | pop eax | ||
1168 | mov ebx, eax | ||
1169 | xor eax, 0x00200000 | ||
1170 | push eax | ||
1171 | popfd | ||
1172 | pushfd | ||
1173 | pop eax | ||
1174 | xor eax,ebx | ||
1175 | mov BitChanged, eax | ||
1176 | } | ||
1177 | |||
1178 | return ((BitChanged) ? true : false); | ||
1179 | #else | ||
1180 | return FALSE; | ||
1181 | #endif | ||
1182 | } | ||
1183 | |||
1184 | // void CProcessor::DecodeProcessorConfiguration(unsigned int cfg) | ||
1185 | // =============================================================== | ||
1186 | // This function (or switch ?!) just translates a one-byte processor configuration | ||
1187 | // byte to understandable values | ||
1188 | ////////////////////////////////////////////////////////////////////////////////// | ||
1189 | void CProcessor::DecodeProcessorConfiguration(unsigned int cfg) | ||
1190 | { | ||
1191 | // First we ensure that there's only one single byte | ||
1192 | cfg &= 0xFF; | ||
1193 | |||
1194 | // Then we do a big switch | ||
1195 | switch(cfg) | ||
1196 | { | ||
1197 | case 0: // cfg = 0: Unused | ||
1198 | break; | ||
1199 | case 0x1: // cfg = 0x1: code TLB present, 4 KB pages, 4 ways, 32 entries | ||
1200 | CPUInfo._Instruction.bPresent = true; | ||
1201 | strcpy(CPUInfo._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/ | ||
1202 | CPUInfo._Instruction.uiAssociativeWays = 4; | ||
1203 | CPUInfo._Instruction.uiEntries = 32; | ||
1204 | break; | ||
1205 | case 0x2: // cfg = 0x2: code TLB present, 4 MB pages, fully associative, 2 entries | ||
1206 | CPUInfo._Instruction.bPresent = true; | ||
1207 | strcpy(CPUInfo._Instruction.strPageSize, "4 MB"); /*Flawfinder: ignore*/ | ||
1208 | CPUInfo._Instruction.uiAssociativeWays = 4; | ||
1209 | CPUInfo._Instruction.uiEntries = 2; | ||
1210 | break; | ||
1211 | case 0x3: // cfg = 0x3: data TLB present, 4 KB pages, 4 ways, 64 entries | ||
1212 | CPUInfo._Data.bPresent = true; | ||
1213 | strcpy(CPUInfo._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/ | ||
1214 | CPUInfo._Data.uiAssociativeWays = 4; | ||
1215 | CPUInfo._Data.uiEntries = 64; | ||
1216 | break; | ||
1217 | case 0x4: // cfg = 0x4: data TLB present, 4 MB pages, 4 ways, 8 entries | ||
1218 | CPUInfo._Data.bPresent = true; | ||
1219 | strcpy(CPUInfo._Data.strPageSize, "4 MB"); /*Flawfinder: ignore*/ | ||
1220 | CPUInfo._Data.uiAssociativeWays = 4; | ||
1221 | CPUInfo._Data.uiEntries = 8; | ||
1222 | break; | ||
1223 | case 0x6: // cfg = 0x6: code L1 cache present, 8 KB, 4 ways, 32 byte lines | ||
1224 | CPUInfo._L1.Instruction.bPresent = true; | ||
1225 | strcpy(CPUInfo._L1.Instruction.strSize, "8 KB"); /*Flawfinder: ignore*/ | ||
1226 | CPUInfo._L1.Instruction.uiAssociativeWays = 4; | ||
1227 | CPUInfo._L1.Instruction.uiLineSize = 32; | ||
1228 | break; | ||
1229 | case 0x8: // cfg = 0x8: code L1 cache present, 16 KB, 4 ways, 32 byte lines | ||
1230 | CPUInfo._L1.Instruction.bPresent = true; | ||
1231 | strcpy(CPUInfo._L1.Instruction.strSize, "16 KB"); /*Flawfinder: ignore*/ | ||
1232 | CPUInfo._L1.Instruction.uiAssociativeWays = 4; | ||
1233 | CPUInfo._L1.Instruction.uiLineSize = 32; | ||
1234 | break; | ||
1235 | case 0xA: // cfg = 0xA: data L1 cache present, 8 KB, 2 ways, 32 byte lines | ||
1236 | CPUInfo._L1.Data.bPresent = true; | ||
1237 | strcpy(CPUInfo._L1.Data.strSize, "8 KB"); /*Flawfinder: ignore*/ | ||
1238 | CPUInfo._L1.Data.uiAssociativeWays = 2; | ||
1239 | CPUInfo._L1.Data.uiLineSize = 32; | ||
1240 | break; | ||
1241 | case 0xC: // cfg = 0xC: data L1 cache present, 16 KB, 4 ways, 32 byte lines | ||
1242 | CPUInfo._L1.Data.bPresent = true; | ||
1243 | strcpy(CPUInfo._L1.Data.strSize, "16 KB"); /*Flawfinder: ignore*/ | ||
1244 | CPUInfo._L1.Data.uiAssociativeWays = 4; | ||
1245 | CPUInfo._L1.Data.uiLineSize = 32; | ||
1246 | break; | ||
1247 | case 0x22: // cfg = 0x22: code and data L3 cache present, 512 KB, 4 ways, 64 byte lines, sectored | ||
1248 | CPUInfo._L3.bPresent = true; | ||
1249 | strcpy(CPUInfo._L3.strSize, "512 KB"); /*Flawfinder: ignore*/ | ||
1250 | CPUInfo._L3.uiAssociativeWays = 4; | ||
1251 | CPUInfo._L3.uiLineSize = 64; | ||
1252 | CPUInfo._L3.bSectored = true; | ||
1253 | break; | ||
1254 | case 0x23: // cfg = 0x23: code and data L3 cache present, 1024 KB, 8 ways, 64 byte lines, sectored | ||
1255 | CPUInfo._L3.bPresent = true; | ||
1256 | strcpy(CPUInfo._L3.strSize, "1024 KB"); /*Flawfinder: ignore*/ | ||
1257 | CPUInfo._L3.uiAssociativeWays = 8; | ||
1258 | CPUInfo._L3.uiLineSize = 64; | ||
1259 | CPUInfo._L3.bSectored = true; | ||
1260 | break; | ||
1261 | case 0x25: // cfg = 0x25: code and data L3 cache present, 2048 KB, 8 ways, 64 byte lines, sectored | ||
1262 | CPUInfo._L3.bPresent = true; | ||
1263 | strcpy(CPUInfo._L3.strSize, "2048 KB"); /*Flawfinder: ignore*/ | ||
1264 | CPUInfo._L3.uiAssociativeWays = 8; | ||
1265 | CPUInfo._L3.uiLineSize = 64; | ||
1266 | CPUInfo._L3.bSectored = true; | ||
1267 | break; | ||
1268 | case 0x29: // cfg = 0x29: code and data L3 cache present, 4096 KB, 8 ways, 64 byte lines, sectored | ||
1269 | CPUInfo._L3.bPresent = true; | ||
1270 | strcpy(CPUInfo._L3.strSize, "4096 KB"); /*Flawfinder: ignore*/ | ||
1271 | CPUInfo._L3.uiAssociativeWays = 8; | ||
1272 | CPUInfo._L3.uiLineSize = 64; | ||
1273 | CPUInfo._L3.bSectored = true; | ||
1274 | break; | ||
1275 | case 0x40: // cfg = 0x40: no integrated L2 cache (P6 core) or L3 cache (P4 core) | ||
1276 | break; | ||
1277 | case 0x41: // cfg = 0x41: code and data L2 cache present, 128 KB, 4 ways, 32 byte lines | ||
1278 | CPUInfo._L2.bPresent = true; | ||
1279 | strcpy(CPUInfo._L2.strSize, "128 KB"); /*Flawfinder: ignore*/ | ||
1280 | CPUInfo._L2.uiAssociativeWays = 4; | ||
1281 | CPUInfo._L2.uiLineSize = 32; | ||
1282 | break; | ||
1283 | case 0x42: // cfg = 0x42: code and data L2 cache present, 256 KB, 4 ways, 32 byte lines | ||
1284 | CPUInfo._L2.bPresent = true; | ||
1285 | strcpy(CPUInfo._L2.strSize, "256 KB"); /*Flawfinder: ignore*/ | ||
1286 | CPUInfo._L2.uiAssociativeWays = 4; | ||
1287 | CPUInfo._L2.uiLineSize = 32; | ||
1288 | break; | ||
1289 | case 0x43: // cfg = 0x43: code and data L2 cache present, 512 KB, 4 ways, 32 byte lines | ||
1290 | CPUInfo._L2.bPresent = true; | ||
1291 | strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */ | ||
1292 | CPUInfo._L2.uiAssociativeWays = 4; | ||
1293 | CPUInfo._L2.uiLineSize = 32; | ||
1294 | break; | ||
1295 | case 0x44: // cfg = 0x44: code and data L2 cache present, 1024 KB, 4 ways, 32 byte lines | ||
1296 | CPUInfo._L2.bPresent = true; | ||
1297 | strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */ | ||
1298 | CPUInfo._L2.uiAssociativeWays = 4; | ||
1299 | CPUInfo._L2.uiLineSize = 32; | ||
1300 | break; | ||
1301 | case 0x45: // cfg = 0x45: code and data L2 cache present, 2048 KB, 4 ways, 32 byte lines | ||
1302 | CPUInfo._L2.bPresent = true; | ||
1303 | strcpy(CPUInfo._L2.strSize, "2 MB"); /* Flawfinder: ignore */ | ||
1304 | CPUInfo._L2.uiAssociativeWays = 4; | ||
1305 | CPUInfo._L2.uiLineSize = 32; | ||
1306 | break; | ||
1307 | case 0x50: // cfg = 0x50: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 64 entries | ||
1308 | CPUInfo._Instruction.bPresent = true; | ||
1309 | strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ | ||
1310 | CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1; | ||
1311 | CPUInfo._Instruction.uiEntries = 64; | ||
1312 | break; | ||
1313 | case 0x51: // cfg = 0x51: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 128 entries | ||
1314 | CPUInfo._Instruction.bPresent = true; | ||
1315 | strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ | ||
1316 | CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1; | ||
1317 | CPUInfo._Instruction.uiEntries = 128; | ||
1318 | break; | ||
1319 | case 0x52: // cfg = 0x52: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 256 entries | ||
1320 | CPUInfo._Instruction.bPresent = true; | ||
1321 | strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ | ||
1322 | CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1; | ||
1323 | CPUInfo._Instruction.uiEntries = 256; | ||
1324 | break; | ||
1325 | case 0x5B: // cfg = 0x5B: data TLB present, 4 KB / 4 MB pages, fully associative, 64 entries | ||
1326 | CPUInfo._Data.bPresent = true; | ||
1327 | strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ | ||
1328 | CPUInfo._Data.uiAssociativeWays = (unsigned int) -1; | ||
1329 | CPUInfo._Data.uiEntries = 64; | ||
1330 | break; | ||
1331 | case 0x5C: // cfg = 0x5C: data TLB present, 4 KB / 4 MB pages, fully associative, 128 entries | ||
1332 | CPUInfo._Data.bPresent = true; | ||
1333 | strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ | ||
1334 | CPUInfo._Data.uiAssociativeWays = (unsigned int) -1; | ||
1335 | CPUInfo._Data.uiEntries = 128; | ||
1336 | break; | ||
1337 | case 0x5d: // cfg = 0x5D: data TLB present, 4 KB / 4 MB pages, fully associative, 256 entries | ||
1338 | CPUInfo._Data.bPresent = true; | ||
1339 | strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ | ||
1340 | CPUInfo._Data.uiAssociativeWays = (unsigned int) -1; | ||
1341 | CPUInfo._Data.uiEntries = 256; | ||
1342 | break; | ||
1343 | case 0x66: // cfg = 0x66: data L1 cache present, 8 KB, 4 ways, 64 byte lines, sectored | ||
1344 | CPUInfo._L1.Data.bPresent = true; | ||
1345 | strcpy(CPUInfo._L1.Data.strSize, "8 KB"); /* Flawfinder: ignore */ | ||
1346 | CPUInfo._L1.Data.uiAssociativeWays = 4; | ||
1347 | CPUInfo._L1.Data.uiLineSize = 64; | ||
1348 | break; | ||
1349 | case 0x67: // cfg = 0x67: data L1 cache present, 16 KB, 4 ways, 64 byte lines, sectored | ||
1350 | CPUInfo._L1.Data.bPresent = true; | ||
1351 | strcpy(CPUInfo._L1.Data.strSize, "16 KB"); /* Flawfinder: ignore */ | ||
1352 | CPUInfo._L1.Data.uiAssociativeWays = 4; | ||
1353 | CPUInfo._L1.Data.uiLineSize = 64; | ||
1354 | break; | ||
1355 | case 0x68: // cfg = 0x68: data L1 cache present, 32 KB, 4 ways, 64 byte lines, sectored | ||
1356 | CPUInfo._L1.Data.bPresent = true; | ||
1357 | strcpy(CPUInfo._L1.Data.strSize, "32 KB"); /* Flawfinder: ignore */ | ||
1358 | CPUInfo._L1.Data.uiAssociativeWays = 4; | ||
1359 | CPUInfo._L1.Data.uiLineSize = 64; | ||
1360 | break; | ||
1361 | case 0x70: // cfg = 0x70: trace L1 cache present, 12 KµOPs, 4 ways | ||
1362 | CPUInfo._Trace.bPresent = true; | ||
1363 | strcpy(CPUInfo._Trace.strSize, "12 K-micro-ops"); /* Flawfinder: ignore */ | ||
1364 | CPUInfo._Trace.uiAssociativeWays = 4; | ||
1365 | break; | ||
1366 | case 0x71: // cfg = 0x71: trace L1 cache present, 16 KµOPs, 4 ways | ||
1367 | CPUInfo._Trace.bPresent = true; | ||
1368 | strcpy(CPUInfo._Trace.strSize, "16 K-micro-ops"); /* Flawfinder: ignore */ | ||
1369 | CPUInfo._Trace.uiAssociativeWays = 4; | ||
1370 | break; | ||
1371 | case 0x72: // cfg = 0x72: trace L1 cache present, 32 KµOPs, 4 ways | ||
1372 | CPUInfo._Trace.bPresent = true; | ||
1373 | strcpy(CPUInfo._Trace.strSize, "32 K-micro-ops"); /* Flawfinder: ignore */ | ||
1374 | CPUInfo._Trace.uiAssociativeWays = 4; | ||
1375 | break; | ||
1376 | case 0x79: // cfg = 0x79: code and data L2 cache present, 128 KB, 8 ways, 64 byte lines, sectored | ||
1377 | CPUInfo._L2.bPresent = true; | ||
1378 | strcpy(CPUInfo._L2.strSize, "128 KB"); /* Flawfinder: ignore */ | ||
1379 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1380 | CPUInfo._L2.uiLineSize = 64; | ||
1381 | CPUInfo._L2.bSectored = true; | ||
1382 | break; | ||
1383 | case 0x7A: // cfg = 0x7A: code and data L2 cache present, 256 KB, 8 ways, 64 byte lines, sectored | ||
1384 | CPUInfo._L2.bPresent = true; | ||
1385 | strcpy(CPUInfo._L2.strSize, "256 KB"); /* Flawfinder: ignore */ | ||
1386 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1387 | CPUInfo._L2.uiLineSize = 64; | ||
1388 | CPUInfo._L2.bSectored = true; | ||
1389 | break; | ||
1390 | case 0x7B: // cfg = 0x7B: code and data L2 cache present, 512 KB, 8 ways, 64 byte lines, sectored | ||
1391 | CPUInfo._L2.bPresent = true; | ||
1392 | strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */ | ||
1393 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1394 | CPUInfo._L2.uiLineSize = 64; | ||
1395 | CPUInfo._L2.bSectored = true; | ||
1396 | break; | ||
1397 | case 0x7C: // cfg = 0x7C: code and data L2 cache present, 1024 KB, 8 ways, 64 byte lines, sectored | ||
1398 | CPUInfo._L2.bPresent = true; | ||
1399 | strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */ | ||
1400 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1401 | CPUInfo._L2.uiLineSize = 64; | ||
1402 | CPUInfo._L2.bSectored = true; | ||
1403 | break; | ||
1404 | case 0x81: // cfg = 0x81: code and data L2 cache present, 128 KB, 8 ways, 32 byte lines | ||
1405 | CPUInfo._L2.bPresent = true; | ||
1406 | strcpy(CPUInfo._L2.strSize, "128 KB"); /* Flawfinder: ignore */ | ||
1407 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1408 | CPUInfo._L2.uiLineSize = 32; | ||
1409 | break; | ||
1410 | case 0x82: // cfg = 0x82: code and data L2 cache present, 256 KB, 8 ways, 32 byte lines | ||
1411 | CPUInfo._L2.bPresent = true; | ||
1412 | strcpy(CPUInfo._L2.strSize, "256 KB"); /* Flawfinder: ignore */ | ||
1413 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1414 | CPUInfo._L2.uiLineSize = 32; | ||
1415 | break; | ||
1416 | case 0x83: // cfg = 0x83: code and data L2 cache present, 512 KB, 8 ways, 32 byte lines | ||
1417 | CPUInfo._L2.bPresent = true; | ||
1418 | strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */ | ||
1419 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1420 | CPUInfo._L2.uiLineSize = 32; | ||
1421 | break; | ||
1422 | case 0x84: // cfg = 0x84: code and data L2 cache present, 1024 KB, 8 ways, 32 byte lines | ||
1423 | CPUInfo._L2.bPresent = true; | ||
1424 | strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */ | ||
1425 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1426 | CPUInfo._L2.uiLineSize = 32; | ||
1427 | break; | ||
1428 | case 0x85: // cfg = 0x85: code and data L2 cache present, 2048 KB, 8 ways, 32 byte lines | ||
1429 | CPUInfo._L2.bPresent = true; | ||
1430 | strcpy(CPUInfo._L2.strSize, "2 MB"); /* Flawfinder: ignore */ | ||
1431 | CPUInfo._L2.uiAssociativeWays = 8; | ||
1432 | CPUInfo._L2.uiLineSize = 32; | ||
1433 | break; | ||
1434 | } | ||
1435 | } | ||
1436 | |||
1437 | FORCEINLINE static char *TranslateAssociativeWays(unsigned int uiWays, char *buf) | ||
1438 | { | ||
1439 | // We define 0xFFFFFFFF (= -1) as fully associative | ||
1440 | if (uiWays == ((unsigned int) -1)) | ||
1441 | strcpy(buf, "fully associative"); /* Flawfinder: ignore */ | ||
1442 | else | ||
1443 | { | ||
1444 | if (uiWays == 1) // A one way associative cache is just direct mapped | ||
1445 | strcpy(buf, "direct mapped"); /* Flawfinder: ignore */ | ||
1446 | else if (uiWays == 0) // This should not happen... | ||
1447 | strcpy(buf, "unknown associative ways"); /* Flawfinder: ignore */ | ||
1448 | else // The x-way associative cache | ||
1449 | sprintf(buf, "%d ways associative", uiWays); /* Flawfinder: ignore */ | ||
1450 | } | ||
1451 | // To ease the function use we return the buffer | ||
1452 | return buf; | ||
1453 | } | ||
1454 | FORCEINLINE static void TranslateTLB(ProcessorTLB *tlb) | ||
1455 | { | ||
1456 | char buf[64]; /* Flawfinder: ignore */ | ||
1457 | |||
1458 | // We just check if the TLB is present | ||
1459 | if (tlb->bPresent) | ||
1460 | snprintf(tlb->strTLB,sizeof(tlb->strTLB), "%s page size, %s, %d entries", tlb->strPageSize, TranslateAssociativeWays(tlb->uiAssociativeWays, buf), tlb->uiEntries); /* Flawfinder: ignore */ | ||
1461 | else | ||
1462 | strcpy(tlb->strTLB, "Not present"); /* Flawfinder: ignore */ | ||
1463 | } | ||
1464 | FORCEINLINE static void TranslateCache(ProcessorCache *cache) | ||
1465 | { | ||
1466 | char buf[64]; /* Flawfinder: ignore */ | ||
1467 | |||
1468 | // We just check if the cache is present | ||
1469 | if (cache->bPresent) | ||
1470 | { | ||
1471 | // If present we construct the string | ||
1472 | snprintf(cache->strCache, sizeof(cache->strCache), "%s cache size, %s, %d bytes line size", cache->strSize, TranslateAssociativeWays(cache->uiAssociativeWays, buf), cache->uiLineSize); /* Flawfinder: ignore */ | ||
1473 | if (cache->bSectored) | ||
1474 | strncat(cache->strCache, ", sectored", sizeof(cache->strCache)-strlen(cache->strCache)-1); /* Flawfinder: ignore */ | ||
1475 | } | ||
1476 | else | ||
1477 | { | ||
1478 | // Else we just say "Not present" | ||
1479 | strcpy(cache->strCache, "Not present"); /* Flawfinder: ignore */ | ||
1480 | } | ||
1481 | } | ||
1482 | |||
1483 | // void CProcessor::TranslateProcessorConfiguration() | ||
1484 | // ================================================== | ||
1485 | // Private class function to translate the processor configuration values | ||
1486 | // to strings | ||
1487 | ///////////////////////////////////////////////////////////////////////// | ||
1488 | void CProcessor::TranslateProcessorConfiguration() | ||
1489 | { | ||
1490 | // We just call the small functions defined above | ||
1491 | TranslateTLB(&CPUInfo._Data); | ||
1492 | TranslateTLB(&CPUInfo._Instruction); | ||
1493 | |||
1494 | TranslateCache(&CPUInfo._Trace); | ||
1495 | |||
1496 | TranslateCache(&CPUInfo._L1.Instruction); | ||
1497 | TranslateCache(&CPUInfo._L1.Data); | ||
1498 | TranslateCache(&CPUInfo._L2); | ||
1499 | TranslateCache(&CPUInfo._L3); | ||
1500 | } | ||
1501 | |||
1502 | // void CProcessor::GetStandardProcessorConfiguration() | ||
1503 | // ==================================================== | ||
1504 | // Private class function to read the standard processor configuration | ||
1505 | ////////////////////////////////////////////////////////////////////// | ||
1506 | void CProcessor::GetStandardProcessorConfiguration() | ||
1507 | { | ||
1508 | #if LL_WINDOWS | ||
1509 | unsigned long eaxreg, ebxreg, ecxreg, edxreg; | ||
1510 | |||
1511 | // We check if the CPUID function is available | ||
1512 | if (!CheckCPUIDPresence()) | ||
1513 | return; | ||
1514 | |||
1515 | // First we check if the processor supports the standard | ||
1516 | // CPUID level 0x00000002 | ||
1517 | if (CPUInfo.MaxSupportedLevel >= 2) | ||
1518 | { | ||
1519 | // Now we go read the std. CPUID level 0x00000002 the first time | ||
1520 | unsigned long count, num = 255; | ||
1521 | for (count = 0; count < num; count++) | ||
1522 | { | ||
1523 | __asm | ||
1524 | { | ||
1525 | mov eax, 2 | ||
1526 | cpuid | ||
1527 | mov eaxreg, eax | ||
1528 | mov ebxreg, ebx | ||
1529 | mov ecxreg, ecx | ||
1530 | mov edxreg, edx | ||
1531 | } | ||
1532 | // We have to repeat this reading for 'num' times | ||
1533 | num = eaxreg & 0xFF; | ||
1534 | |||
1535 | // Then we call the big decode switch function | ||
1536 | DecodeProcessorConfiguration(eaxreg >> 8); | ||
1537 | DecodeProcessorConfiguration(eaxreg >> 16); | ||
1538 | DecodeProcessorConfiguration(eaxreg >> 24); | ||
1539 | |||
1540 | // If ebx contains additional data we also decode it | ||
1541 | if ((ebxreg & 0x80000000) == 0) | ||
1542 | { | ||
1543 | DecodeProcessorConfiguration(ebxreg); | ||
1544 | DecodeProcessorConfiguration(ebxreg >> 8); | ||
1545 | DecodeProcessorConfiguration(ebxreg >> 16); | ||
1546 | DecodeProcessorConfiguration(ebxreg >> 24); | ||
1547 | } | ||
1548 | // And also the ecx register | ||
1549 | if ((ecxreg & 0x80000000) == 0) | ||
1550 | { | ||
1551 | DecodeProcessorConfiguration(ecxreg); | ||
1552 | DecodeProcessorConfiguration(ecxreg >> 8); | ||
1553 | DecodeProcessorConfiguration(ecxreg >> 16); | ||
1554 | DecodeProcessorConfiguration(ecxreg >> 24); | ||
1555 | } | ||
1556 | // At last the edx processor register | ||
1557 | if ((edxreg & 0x80000000) == 0) | ||
1558 | { | ||
1559 | DecodeProcessorConfiguration(edxreg); | ||
1560 | DecodeProcessorConfiguration(edxreg >> 8); | ||
1561 | DecodeProcessorConfiguration(edxreg >> 16); | ||
1562 | DecodeProcessorConfiguration(edxreg >> 24); | ||
1563 | } | ||
1564 | } | ||
1565 | } | ||
1566 | #endif | ||
1567 | } | ||
1568 | |||
1569 | // void CProcessor::GetStandardProcessorExtensions() | ||
1570 | // ================================================= | ||
1571 | // Private class function to read the standard processor extensions | ||
1572 | /////////////////////////////////////////////////////////////////// | ||
1573 | void CProcessor::GetStandardProcessorExtensions() | ||
1574 | { | ||
1575 | #if LL_WINDOWS | ||
1576 | unsigned long ebxreg, edxreg; | ||
1577 | |||
1578 | // We check if the CPUID command is available | ||
1579 | if (!CheckCPUIDPresence()) | ||
1580 | return; | ||
1581 | // We just get the standard CPUID level 0x00000001 which should be | ||
1582 | // available on every x86 processor | ||
1583 | __asm | ||
1584 | { | ||
1585 | mov eax, 1 | ||
1586 | cpuid | ||
1587 | mov ebxreg, ebx | ||
1588 | mov edxreg, edx | ||
1589 | } | ||
1590 | |||
1591 | // Then we mask some bits | ||
1592 | CPUInfo._Ext.FPU_FloatingPointUnit = CheckBit(edxreg, 0); | ||
1593 | CPUInfo._Ext.VME_Virtual8086ModeEnhancements = CheckBit(edxreg, 1); | ||
1594 | CPUInfo._Ext.DE_DebuggingExtensions = CheckBit(edxreg, 2); | ||
1595 | CPUInfo._Ext.PSE_PageSizeExtensions = CheckBit(edxreg, 3); | ||
1596 | CPUInfo._Ext.TSC_TimeStampCounter = CheckBit(edxreg, 4); | ||
1597 | CPUInfo._Ext.MSR_ModelSpecificRegisters = CheckBit(edxreg, 5); | ||
1598 | CPUInfo._Ext.PAE_PhysicalAddressExtension = CheckBit(edxreg, 6); | ||
1599 | CPUInfo._Ext.MCE_MachineCheckException = CheckBit(edxreg, 7); | ||
1600 | CPUInfo._Ext.CX8_COMPXCHG8B_Instruction = CheckBit(edxreg, 8); | ||
1601 | CPUInfo._Ext.APIC_AdvancedProgrammableInterruptController = CheckBit(edxreg, 9); | ||
1602 | CPUInfo._Ext.APIC_ID = (ebxreg >> 24) & 0xFF; | ||
1603 | CPUInfo._Ext.SEP_FastSystemCall = CheckBit(edxreg, 11); | ||
1604 | CPUInfo._Ext.MTRR_MemoryTypeRangeRegisters = CheckBit(edxreg, 12); | ||
1605 | CPUInfo._Ext.PGE_PTE_GlobalFlag = CheckBit(edxreg, 13); | ||
1606 | CPUInfo._Ext.MCA_MachineCheckArchitecture = CheckBit(edxreg, 14); | ||
1607 | CPUInfo._Ext.CMOV_ConditionalMoveAndCompareInstructions = CheckBit(edxreg, 15); | ||
1608 | CPUInfo._Ext.FGPAT_PageAttributeTable = CheckBit(edxreg, 16); | ||
1609 | CPUInfo._Ext.PSE36_36bitPageSizeExtension = CheckBit(edxreg, 17); | ||
1610 | CPUInfo._Ext.PN_ProcessorSerialNumber = CheckBit(edxreg, 18); | ||
1611 | CPUInfo._Ext.CLFSH_CFLUSH_Instruction = CheckBit(edxreg, 19); | ||
1612 | CPUInfo._Ext.CLFLUSH_InstructionCacheLineSize = (ebxreg >> 8) & 0xFF; | ||
1613 | CPUInfo._Ext.DS_DebugStore = CheckBit(edxreg, 21); | ||
1614 | CPUInfo._Ext.ACPI_ThermalMonitorAndClockControl = CheckBit(edxreg, 22); | ||
1615 | CPUInfo._Ext.MMX_MultimediaExtensions = CheckBit(edxreg, 23); | ||
1616 | CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore = CheckBit(edxreg, 24); | ||
1617 | CPUInfo._Ext.SSE_StreamingSIMD_Extensions = CheckBit(edxreg, 25); | ||
1618 | CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = CheckBit(edxreg, 26); | ||
1619 | CPUInfo._Ext.SS_SelfSnoop = CheckBit(edxreg, 27); | ||
1620 | CPUInfo._Ext.HT_HyperThreading = CheckBit(edxreg, 28); | ||
1621 | CPUInfo._Ext.HT_HyterThreadingSiblings = (ebxreg >> 16) & 0xFF; | ||
1622 | CPUInfo._Ext.TM_ThermalMonitor = CheckBit(edxreg, 29); | ||
1623 | CPUInfo._Ext.IA64_Intel64BitArchitecture = CheckBit(edxreg, 30); | ||
1624 | #endif | ||
1625 | } | ||
1626 | |||
1627 | // const ProcessorInfo *CProcessor::GetCPUInfo() | ||
1628 | // ============================================= | ||
1629 | // Calls all the other detection function to create an detailed | ||
1630 | // processor information | ||
1631 | /////////////////////////////////////////////////////////////// | ||
1632 | const ProcessorInfo *CProcessor::GetCPUInfo() | ||
1633 | { | ||
1634 | #if LL_WINDOWS | ||
1635 | unsigned long eaxreg, ebxreg, ecxreg, edxreg; | ||
1636 | |||
1637 | // First of all we check if the CPUID command is available | ||
1638 | if (!CheckCPUIDPresence()) | ||
1639 | return NULL; | ||
1640 | |||
1641 | // We read the standard CPUID level 0x00000000 which should | ||
1642 | // be available on every x86 processor | ||
1643 | __asm | ||
1644 | { | ||
1645 | mov eax, 0 | ||
1646 | cpuid | ||
1647 | mov eaxreg, eax | ||
1648 | mov ebxreg, ebx | ||
1649 | mov edxreg, edx | ||
1650 | mov ecxreg, ecx | ||
1651 | } | ||
1652 | // Then we connect the single register values to the vendor string | ||
1653 | *((unsigned long *) CPUInfo.strVendor) = ebxreg; | ||
1654 | *((unsigned long *) (CPUInfo.strVendor+4)) = edxreg; | ||
1655 | *((unsigned long *) (CPUInfo.strVendor+8)) = ecxreg; | ||
1656 | |||
1657 | // We can also read the max. supported standard CPUID level | ||
1658 | CPUInfo.MaxSupportedLevel = eaxreg & 0xFFFF; | ||
1659 | |||
1660 | // Then we read the ext. CPUID level 0x80000000 | ||
1661 | __asm | ||
1662 | { | ||
1663 | mov eax, 0x80000000 | ||
1664 | cpuid | ||
1665 | mov eaxreg, eax | ||
1666 | } | ||
1667 | // ...to check the max. supportted extended CPUID level | ||
1668 | CPUInfo.MaxSupportedExtendedLevel = eaxreg; | ||
1669 | |||
1670 | // Then we switch to the specific processor vendors | ||
1671 | switch (ebxreg) | ||
1672 | { | ||
1673 | case 0x756E6547: // GenuineIntel | ||
1674 | AnalyzeIntelProcessor(); | ||
1675 | break; | ||
1676 | case 0x68747541: // AuthenticAMD | ||
1677 | AnalyzeAMDProcessor(); | ||
1678 | break; | ||
1679 | case 0x69727943: // CyrixInstead | ||
1680 | // I really do not know anyone owning such a piece of crab | ||
1681 | // So we analyze it as an unknown processor *ggggg* | ||
1682 | default: | ||
1683 | AnalyzeUnknownProcessor(); | ||
1684 | break; | ||
1685 | } | ||
1686 | |||
1687 | #endif | ||
1688 | // After all we return the class CPUInfo member var | ||
1689 | return (&CPUInfo); | ||
1690 | } | ||
1691 | |||
1692 | #else | ||
1693 | // LL_DARWIN | ||
1694 | |||
1695 | #include <mach/machine.h> | ||
1696 | #include <sys/sysctl.h> | ||
1697 | |||
1698 | static char *TranslateAssociativeWays(unsigned int uiWays, char *buf) | ||
1699 | { | ||
1700 | // We define 0xFFFFFFFF (= -1) as fully associative | ||
1701 | if (uiWays == ((unsigned int) -1)) | ||
1702 | strcpy(buf, "fully associative"); /* Flawfinder: ignore */ | ||
1703 | else | ||
1704 | { | ||
1705 | if (uiWays == 1) // A one way associative cache is just direct mapped | ||
1706 | strcpy(buf, "direct mapped"); /* Flawfinder: ignore */ | ||
1707 | else if (uiWays == 0) // This should not happen... | ||
1708 | strcpy(buf, "unknown associative ways"); /* Flawfinder: ignore */ | ||
1709 | else // The x-way associative cache | ||
1710 | sprintf(buf, "%d ways associative", uiWays); /* Flawfinder: ignore */ | ||
1711 | } | ||
1712 | // To ease the function use we return the buffer | ||
1713 | return buf; | ||
1714 | } | ||
1715 | static void TranslateTLB(ProcessorTLB *tlb) | ||
1716 | { | ||
1717 | char buf[64]; /* Flawfinder: ignore */ | ||
1718 | |||
1719 | // We just check if the TLB is present | ||
1720 | if (tlb->bPresent) | ||
1721 | snprintf(tlb->strTLB, sizeof(tlb->strTLB), "%s page size, %s, %d entries", tlb->strPageSize, TranslateAssociativeWays(tlb->uiAssociativeWays, buf), tlb->uiEntries); /* Flawfinder: ignore */ | ||
1722 | else | ||
1723 | strcpy(tlb->strTLB, "Not present"); /* Flawfinder: ignore */ | ||
1724 | } | ||
1725 | static void TranslateCache(ProcessorCache *cache) | ||
1726 | { | ||
1727 | char buf[64]; /* Flawfinder: ignore */ | ||
1728 | |||
1729 | // We just check if the cache is present | ||
1730 | if (cache->bPresent) | ||
1731 | { | ||
1732 | // If present we construct the string | ||
1733 | snprintf(cache->strCache,sizeof(cache->strCache), "%s cache size, %s, %d bytes line size", cache->strSize, TranslateAssociativeWays(cache->uiAssociativeWays, buf), cache->uiLineSize); /* Flawfinder: ignore */ | ||
1734 | if (cache->bSectored) | ||
1735 | strncat(cache->strCache, ", sectored", sizeof(cache->strCache)-strlen(cache->strCache)-1); /* Flawfinder: ignore */ | ||
1736 | } | ||
1737 | else | ||
1738 | { | ||
1739 | // Else we just say "Not present" | ||
1740 | strcpy(cache->strCache, "Not present"); /* Flawfinder: ignore */ | ||
1741 | } | ||
1742 | } | ||
1743 | |||
1744 | // void CProcessor::TranslateProcessorConfiguration() | ||
1745 | // ================================================== | ||
1746 | // Private class function to translate the processor configuration values | ||
1747 | // to strings | ||
1748 | ///////////////////////////////////////////////////////////////////////// | ||
1749 | void CProcessor::TranslateProcessorConfiguration() | ||
1750 | { | ||
1751 | // We just call the small functions defined above | ||
1752 | TranslateTLB(&CPUInfo._Data); | ||
1753 | TranslateTLB(&CPUInfo._Instruction); | ||
1754 | |||
1755 | TranslateCache(&CPUInfo._Trace); | ||
1756 | |||
1757 | TranslateCache(&CPUInfo._L1.Instruction); | ||
1758 | TranslateCache(&CPUInfo._L1.Data); | ||
1759 | TranslateCache(&CPUInfo._L2); | ||
1760 | TranslateCache(&CPUInfo._L3); | ||
1761 | } | ||
1762 | |||
1763 | // CProcessor::CProcessor | ||
1764 | // ====================== | ||
1765 | // Class constructor: | ||
1766 | ///////////////////////// | ||
1767 | CProcessor::CProcessor() | ||
1768 | { | ||
1769 | uqwFrequency = 0; | ||
1770 | memset(&CPUInfo, 0, sizeof(CPUInfo)); | ||
1771 | } | ||
1772 | |||
1773 | // unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) | ||
1774 | // ========================================================================= | ||
1775 | // Function to query the current CPU frequency | ||
1776 | //////////////////////////////////////////////////////////////////////////// | ||
1777 | F64 CProcessor::GetCPUFrequency(unsigned int /*uiMeasureMSecs*/) | ||
1778 | { | ||
1779 | U64 frequency = 0; | ||
1780 | size_t len = sizeof(frequency); | ||
1781 | |||
1782 | if(sysctlbyname("hw.cpufrequency", &frequency, &len, NULL, 0) == 0) | ||
1783 | { | ||
1784 | uqwFrequency = (F64)frequency; | ||
1785 | } | ||
1786 | |||
1787 | return uqwFrequency; | ||
1788 | } | ||
1789 | |||
1790 | static bool hasFeature(const char *name) | ||
1791 | { | ||
1792 | bool result = false; | ||
1793 | int val = 0; | ||
1794 | size_t len = sizeof(val); | ||
1795 | |||
1796 | if(sysctlbyname(name, &val, &len, NULL, 0) == 0) | ||
1797 | { | ||
1798 | if(val != 0) | ||
1799 | result = true; | ||
1800 | } | ||
1801 | |||
1802 | return result; | ||
1803 | } | ||
1804 | |||
1805 | // const ProcessorInfo *CProcessor::GetCPUInfo() | ||
1806 | // ============================================= | ||
1807 | // Calls all the other detection function to create an detailed | ||
1808 | // processor information | ||
1809 | /////////////////////////////////////////////////////////////// | ||
1810 | const ProcessorInfo *CProcessor::GetCPUInfo() | ||
1811 | { | ||
1812 | int pagesize = 0; | ||
1813 | int cachelinesize = 0; | ||
1814 | int l1icachesize = 0; | ||
1815 | int l1dcachesize = 0; | ||
1816 | int l2settings = 0; | ||
1817 | int l2cachesize = 0; | ||
1818 | int l3settings = 0; | ||
1819 | int l3cachesize = 0; | ||
1820 | int ncpu = 0; | ||
1821 | int cpusubtype = 0; | ||
1822 | |||
1823 | // sysctl knows all. | ||
1824 | int mib[2]; | ||
1825 | size_t len; | ||
1826 | mib[0] = CTL_HW; | ||
1827 | |||
1828 | mib[1] = HW_PAGESIZE; | ||
1829 | len = sizeof(pagesize); | ||
1830 | sysctl(mib, 2, &pagesize, &len, NULL, 0); | ||
1831 | |||
1832 | mib[1] = HW_CACHELINE; | ||
1833 | len = sizeof(cachelinesize); | ||
1834 | sysctl(mib, 2, &cachelinesize, &len, NULL, 0); | ||
1835 | |||
1836 | mib[1] = HW_L1ICACHESIZE; | ||
1837 | len = sizeof(l1icachesize); | ||
1838 | sysctl(mib, 2, &l1icachesize, &len, NULL, 0); | ||
1839 | |||
1840 | mib[1] = HW_L1DCACHESIZE; | ||
1841 | len = sizeof(l1dcachesize); | ||
1842 | sysctl(mib, 2, &l1dcachesize, &len, NULL, 0); | ||
1843 | |||
1844 | mib[1] = HW_L2SETTINGS; | ||
1845 | len = sizeof(l2settings); | ||
1846 | sysctl(mib, 2, &l2settings, &len, NULL, 0); | ||
1847 | |||
1848 | mib[1] = HW_L2CACHESIZE; | ||
1849 | len = sizeof(l2cachesize); | ||
1850 | sysctl(mib, 2, &l2cachesize, &len, NULL, 0); | ||
1851 | |||
1852 | mib[1] = HW_L3SETTINGS; | ||
1853 | len = sizeof(l3settings); | ||
1854 | sysctl(mib, 2, &l3settings, &len, NULL, 0); | ||
1855 | |||
1856 | mib[1] = HW_L3CACHESIZE; | ||
1857 | len = sizeof(l3cachesize); | ||
1858 | sysctl(mib, 2, &l3cachesize, &len, NULL, 0); | ||
1859 | |||
1860 | mib[1] = HW_NCPU; | ||
1861 | len = sizeof(ncpu); | ||
1862 | sysctl(mib, 2, &ncpu, &len, NULL, 0); | ||
1863 | |||
1864 | sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0); | ||
1865 | |||
1866 | strCPUName[0] = 0; | ||
1867 | |||
1868 | if((ncpu == 0) || (ncpu == 1)) | ||
1869 | { | ||
1870 | // Uhhh... | ||
1871 | } | ||
1872 | else if(ncpu == 2) | ||
1873 | { | ||
1874 | strncat(strCPUName, "Dual ", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1875 | } | ||
1876 | else | ||
1877 | { | ||
1878 | snprintf(strCPUName, sizeof(strCPUName), "%d x ", ncpu); /* Flawfinder: ignore */ | ||
1879 | } | ||
1880 | |||
1881 | #if __ppc__ | ||
1882 | switch(cpusubtype) | ||
1883 | { | ||
1884 | case CPU_SUBTYPE_POWERPC_601:// ((cpu_subtype_t) 1) | ||
1885 | strncat(strCPUName, "PowerPC 601", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1886 | strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1887 | |||
1888 | break; | ||
1889 | case CPU_SUBTYPE_POWERPC_602:// ((cpu_subtype_t) 2) | ||
1890 | strncat(strCPUName, "PowerPC 602", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1891 | strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1892 | break; | ||
1893 | case CPU_SUBTYPE_POWERPC_603:// ((cpu_subtype_t) 3) | ||
1894 | strncat(strCPUName, "PowerPC 603", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1895 | strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1896 | break; | ||
1897 | case CPU_SUBTYPE_POWERPC_603e:// ((cpu_subtype_t) 4) | ||
1898 | strncat(strCPUName, "PowerPC 603e", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1899 | strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1900 | break; | ||
1901 | case CPU_SUBTYPE_POWERPC_603ev:// ((cpu_subtype_t) 5) | ||
1902 | strncat(strCPUName, "PowerPC 603ev", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1903 | strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1904 | break; | ||
1905 | case CPU_SUBTYPE_POWERPC_604:// ((cpu_subtype_t) 6) | ||
1906 | strncat(strCPUName, "PowerPC 604", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1907 | strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1908 | break; | ||
1909 | case CPU_SUBTYPE_POWERPC_604e:// ((cpu_subtype_t) 7) | ||
1910 | strncat(strCPUName, "PowerPC 604e", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1911 | strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1912 | break; | ||
1913 | case CPU_SUBTYPE_POWERPC_620:// ((cpu_subtype_t) 8) | ||
1914 | strncat(strCPUName, "PowerPC 620", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1915 | strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1916 | break; | ||
1917 | case CPU_SUBTYPE_POWERPC_750:// ((cpu_subtype_t) 9) | ||
1918 | strncat(strCPUName, "PowerPC 750", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1919 | strncat(CPUInfo.strFamily, "PowerPC G3", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1920 | break; | ||
1921 | case CPU_SUBTYPE_POWERPC_7400:// ((cpu_subtype_t) 10) | ||
1922 | strncat(strCPUName, "PowerPC 7400", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1923 | strncat(CPUInfo.strFamily, "PowerPC G4", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1924 | break; | ||
1925 | case CPU_SUBTYPE_POWERPC_7450:// ((cpu_subtype_t) 11) | ||
1926 | strncat(strCPUName, "PowerPC 7450", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1927 | strncat(CPUInfo.strFamily, "PowerPC G4", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1928 | break; | ||
1929 | case CPU_SUBTYPE_POWERPC_970:// ((cpu_subtype_t) 100) | ||
1930 | strncat(strCPUName, "PowerPC 970", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1931 | strncat(CPUInfo.strFamily, "PowerPC G5", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ | ||
1932 | break; | ||
1933 | |||
1934 | default: | ||
1935 | strncat(strCPUName, "PowerPC (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1936 | break; | ||
1937 | } | ||
1938 | |||
1939 | // It's kinda like MMX or SSE... | ||
1940 | CPUInfo._Ext.EMMX_MultimediaExtensions = | ||
1941 | CPUInfo._Ext.MMX_MultimediaExtensions = | ||
1942 | CPUInfo._Ext.SSE_StreamingSIMD_Extensions = | ||
1943 | CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = hasFeature("hw.optional.altivec"); | ||
1944 | |||
1945 | #endif | ||
1946 | |||
1947 | #if __i386__ | ||
1948 | // MBW -- XXX -- TODO -- make this call AnalyzeIntelProcessor()? | ||
1949 | switch(cpusubtype) | ||
1950 | { | ||
1951 | default: | ||
1952 | strncat(strCPUName, "i386 (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ | ||
1953 | break; | ||
1954 | } | ||
1955 | |||
1956 | CPUInfo._Ext.EMMX_MultimediaExtensions = hasFeature("hw.optional.mmx"); // MBW -- XXX -- this may be wrong... | ||
1957 | CPUInfo._Ext.MMX_MultimediaExtensions = hasFeature("hw.optional.mmx"); | ||
1958 | CPUInfo._Ext.SSE_StreamingSIMD_Extensions = hasFeature("hw.optional.sse"); | ||
1959 | CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = hasFeature("hw.optional.sse2"); | ||
1960 | CPUInfo._Ext.AA64_AMD64BitArchitecture = hasFeature("hw.optional.x86_64"); | ||
1961 | |||
1962 | #endif | ||
1963 | |||
1964 | // Terse CPU info uses this string... | ||
1965 | strncpy(CPUInfo.strBrandID, strCPUName,sizeof(CPUInfo.strBrandID)-1); /* Flawfinder: ignore */ | ||
1966 | CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0'; | ||
1967 | |||
1968 | // Fun cache config stuff... | ||
1969 | |||
1970 | if(l1dcachesize != 0) | ||
1971 | { | ||
1972 | CPUInfo._L1.Data.bPresent = true; | ||
1973 | snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", l1dcachesize / 1024); /* Flawfinder: ignore */ | ||
1974 | // CPUInfo._L1.Data.uiAssociativeWays = ???; | ||
1975 | CPUInfo._L1.Data.uiLineSize = cachelinesize; | ||
1976 | } | ||
1977 | |||
1978 | if(l1icachesize != 0) | ||
1979 | { | ||
1980 | CPUInfo._L1.Instruction.bPresent = true; | ||
1981 | snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", l1icachesize / 1024); /* Flawfinder: ignore */ | ||
1982 | // CPUInfo._L1.Instruction.uiAssociativeWays = ???; | ||
1983 | CPUInfo._L1.Instruction.uiLineSize = cachelinesize; | ||
1984 | } | ||
1985 | |||
1986 | if(l2cachesize != 0) | ||
1987 | { | ||
1988 | CPUInfo._L2.bPresent = true; | ||
1989 | snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", l2cachesize / 1024); /* Flawfinder: ignore */ | ||
1990 | // CPUInfo._L2.uiAssociativeWays = ???; | ||
1991 | CPUInfo._L2.uiLineSize = cachelinesize; | ||
1992 | } | ||
1993 | |||
1994 | if(l3cachesize != 0) | ||
1995 | { | ||
1996 | CPUInfo._L2.bPresent = true; | ||
1997 | snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", l3cachesize / 1024); /* Flawfinder: ignore */ | ||
1998 | // CPUInfo._L2.uiAssociativeWays = ???; | ||
1999 | CPUInfo._L2.uiLineSize = cachelinesize; | ||
2000 | } | ||
2001 | |||
2002 | CPUInfo._Ext.FPU_FloatingPointUnit = hasFeature("hw.optional.floatingpoint"); | ||
2003 | |||
2004 | // printf("pagesize = 0x%x\n", pagesize); | ||
2005 | // printf("cachelinesize = 0x%x\n", cachelinesize); | ||
2006 | // printf("l1icachesize = 0x%x\n", l1icachesize); | ||
2007 | // printf("l1dcachesize = 0x%x\n", l1dcachesize); | ||
2008 | // printf("l2settings = 0x%x\n", l2settings); | ||
2009 | // printf("l2cachesize = 0x%x\n", l2cachesize); | ||
2010 | // printf("l3settings = 0x%x\n", l3settings); | ||
2011 | // printf("l3cachesize = 0x%x\n", l3cachesize); | ||
2012 | |||
2013 | // After reading we translate the configuration to strings | ||
2014 | TranslateProcessorConfiguration(); | ||
2015 | |||
2016 | // After all we return the class CPUInfo member var | ||
2017 | return (&CPUInfo); | ||
2018 | } | ||
2019 | |||
2020 | #endif // LL_DARWIN | ||
2021 | |||
2022 | // bool CProcessor::CPUInfoToText(char *strBuffer, unsigned int uiMaxLen) | ||
2023 | // ====================================================================== | ||
2024 | // Gets the frequency and processor information and writes it to a string | ||
2025 | ///////////////////////////////////////////////////////////////////////// | ||
2026 | bool CProcessor::CPUInfoToText(char *strBuffer, unsigned int uiMaxLen) | ||
2027 | { | ||
2028 | #define LENCHECK len = (unsigned int) strlen(buf); if (len >= uiMaxLen) return false; strcpy(strBuffer, buf); strBuffer += len; /*Flawfinder: ignore*/ | ||
2029 | #define COPYADD(str) strcpy(buf, str); LENCHECK; /* Flawfinder: ignore */ | ||
2030 | #define FORMATADD(format, var) sprintf(buf, format, var); LENCHECK; /* Flawfinder: ignore */ | ||
2031 | #define BOOLADD(str, boolvar) COPYADD(str); if (boolvar) { COPYADD(" Yes\n"); } else { COPYADD(" No\n"); } | ||
2032 | |||
2033 | char buf[1024]; /* Flawfinder: ignore */ | ||
2034 | unsigned int len; | ||
2035 | |||
2036 | // First we have to get the frequency | ||
2037 | GetCPUFrequency(50); | ||
2038 | |||
2039 | // Then we get the processor information | ||
2040 | GetCPUInfo(); | ||
2041 | |||
2042 | // Now we construct the string (see the macros at function beginning) | ||
2043 | strBuffer[0] = 0; | ||
2044 | |||
2045 | COPYADD("// CPU General Information\n//////////////////////////\n"); | ||
2046 | FORMATADD("Processor name: %s\n", strCPUName); | ||
2047 | FORMATADD("Frequency: %.2f MHz\n\n", (float) uqwFrequency / 1000000.0f); | ||
2048 | FORMATADD("Vendor: %s\n", CPUInfo.strVendor); | ||
2049 | FORMATADD("Family: %s\n", CPUInfo.strFamily); | ||
2050 | FORMATADD("Extended family: %d\n", CPUInfo.uiExtendedFamily); | ||
2051 | FORMATADD("Model: %s\n", CPUInfo.strModel); | ||
2052 | FORMATADD("Extended model: %d\n", CPUInfo.uiExtendedModel); | ||
2053 | FORMATADD("Type: %s\n", CPUInfo.strType); | ||
2054 | FORMATADD("Brand ID: %s\n", CPUInfo.strBrandID); | ||
2055 | if (CPUInfo._Ext.PN_ProcessorSerialNumber) | ||
2056 | { | ||
2057 | FORMATADD("Processor Serial: %s\n", CPUInfo.strProcessorSerial); | ||
2058 | } | ||
2059 | else | ||
2060 | { | ||
2061 | COPYADD("Processor Serial: Disabled\n"); | ||
2062 | } | ||
2063 | |||
2064 | COPYADD("\n\n// CPU Configuration\n////////////////////\n"); | ||
2065 | FORMATADD("L1 instruction cache: %s\n", CPUInfo._L1.Instruction.strCache); | ||
2066 | FORMATADD("L1 data cache: %s\n", CPUInfo._L1.Data.strCache); | ||
2067 | FORMATADD("L2 cache: %s\n", CPUInfo._L2.strCache); | ||
2068 | FORMATADD("L3 cache: %s\n", CPUInfo._L3.strCache); | ||
2069 | FORMATADD("Trace cache: %s\n", CPUInfo._Trace.strCache); | ||
2070 | FORMATADD("Instruction TLB: %s\n", CPUInfo._Instruction.strTLB); | ||
2071 | FORMATADD("Data TLB: %s\n", CPUInfo._Data.strTLB); | ||
2072 | FORMATADD("Max Supported CPUID-Level: 0x%08lX\n", CPUInfo.MaxSupportedLevel); | ||
2073 | FORMATADD("Max Supported Ext. CPUID-Level: 0x%08lX\n", CPUInfo.MaxSupportedExtendedLevel); | ||
2074 | |||
2075 | COPYADD("\n\n// CPU Extensions\n/////////////////\n"); | ||
2076 | BOOLADD("AA64 AMD 64-bit Architecture: ", CPUInfo._Ext.AA64_AMD64BitArchitecture); | ||
2077 | BOOLADD("ACPI Thermal Monitor And Clock Control: ", CPUInfo._Ext.ACPI_ThermalMonitorAndClockControl); | ||
2078 | BOOLADD("APIC Advanced Programmable Interrupt Controller: ", CPUInfo._Ext.APIC_AdvancedProgrammableInterruptController); | ||
2079 | FORMATADD(" APIC-ID: %d\n", CPUInfo._Ext.APIC_ID); | ||
2080 | BOOLADD("CLFSH CLFLUSH Instruction Presence: ", CPUInfo._Ext.CLFSH_CFLUSH_Instruction); | ||
2081 | FORMATADD(" CLFLUSH Instruction Cache Line Size: %d\n", CPUInfo._Ext.CLFLUSH_InstructionCacheLineSize); | ||
2082 | BOOLADD("CMOV Conditional Move And Compare Instructions: ", CPUInfo._Ext.CMOV_ConditionalMoveAndCompareInstructions); | ||
2083 | BOOLADD("CX8 COMPXCHG8B Instruction: ", CPUInfo._Ext.CX8_COMPXCHG8B_Instruction); | ||
2084 | BOOLADD("DE Debugging Extensions: ", CPUInfo._Ext.DE_DebuggingExtensions); | ||
2085 | BOOLADD("DS Debug Store: ", CPUInfo._Ext.DS_DebugStore); | ||
2086 | BOOLADD("FGPAT Page Attribute Table: ", CPUInfo._Ext.FGPAT_PageAttributeTable); | ||
2087 | BOOLADD("FPU Floating Point Unit: ", CPUInfo._Ext.FPU_FloatingPointUnit); | ||
2088 | BOOLADD("FXSR Fast Streaming SIMD Extensions Save/Restore:", CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore); | ||
2089 | BOOLADD("HT Hyper Threading: ", CPUInfo._Ext.HT_HyperThreading); | ||
2090 | BOOLADD("IA64 Intel 64-Bit Architecture: ", CPUInfo._Ext.IA64_Intel64BitArchitecture); | ||
2091 | BOOLADD("MCA Machine Check Architecture: ", CPUInfo._Ext.MCA_MachineCheckArchitecture); | ||
2092 | BOOLADD("MCE Machine Check Exception: ", CPUInfo._Ext.MCE_MachineCheckException); | ||
2093 | BOOLADD("MMX Multimedia Extensions: ", CPUInfo._Ext.MMX_MultimediaExtensions); | ||
2094 | BOOLADD("MMX+ Multimedia Extensions: ", CPUInfo._Ext.EMMX_MultimediaExtensions); | ||
2095 | BOOLADD("MSR Model Specific Registers: ", CPUInfo._Ext.MSR_ModelSpecificRegisters); | ||
2096 | BOOLADD("MTRR Memory Type Range Registers: ", CPUInfo._Ext.MTRR_MemoryTypeRangeRegisters); | ||
2097 | BOOLADD("PAE Physical Address Extension: ", CPUInfo._Ext.PAE_PhysicalAddressExtension); | ||
2098 | BOOLADD("PGE PTE Global Flag: ", CPUInfo._Ext.PGE_PTE_GlobalFlag); | ||
2099 | if (CPUInfo._Ext.PN_ProcessorSerialNumber) | ||
2100 | { | ||
2101 | FORMATADD("PN Processor Serial Number: %s\n", CPUInfo.strProcessorSerial); | ||
2102 | } | ||
2103 | else | ||
2104 | { | ||
2105 | COPYADD("PN Processor Serial Number: Disabled\n"); | ||
2106 | } | ||
2107 | BOOLADD("PSE Page Size Extensions: ", CPUInfo._Ext.PSE_PageSizeExtensions); | ||
2108 | BOOLADD("PSE36 36-bit Page Size Extension: ", CPUInfo._Ext.PSE36_36bitPageSizeExtension); | ||
2109 | BOOLADD("SEP Fast System Call: ", CPUInfo._Ext.SEP_FastSystemCall); | ||
2110 | BOOLADD("SS Self Snoop: ", CPUInfo._Ext.SS_SelfSnoop); | ||
2111 | BOOLADD("SSE Streaming SIMD Extensions: ", CPUInfo._Ext.SSE_StreamingSIMD_Extensions); | ||
2112 | BOOLADD("SSE2 Streaming SIMD 2 Extensions: ", CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions); | ||
2113 | BOOLADD("TM Thermal Monitor: ", CPUInfo._Ext.TM_ThermalMonitor); | ||
2114 | BOOLADD("TSC Time Stamp Counter: ", CPUInfo._Ext.TSC_TimeStampCounter); | ||
2115 | BOOLADD("VME Virtual 8086 Mode Enhancements: ", CPUInfo._Ext.VME_Virtual8086ModeEnhancements); | ||
2116 | BOOLADD("3DNow! Instructions: ", CPUInfo._Ext._3DNOW_InstructionExtensions); | ||
2117 | BOOLADD("Enhanced 3DNow! Instructions: ", CPUInfo._Ext._E3DNOW_InstructionExtensions); | ||
2118 | |||
2119 | // Yippie!!! | ||
2120 | return true; | ||
2121 | } | ||
2122 | |||
2123 | // bool CProcessor::WriteInfoTextFile(const char *strFilename) | ||
2124 | // =========================================================== | ||
2125 | // Takes use of CProcessor::CPUInfoToText and saves the string to a | ||
2126 | // file | ||
2127 | /////////////////////////////////////////////////////////////////// | ||
2128 | bool CProcessor::WriteInfoTextFile(const char *strFilename) | ||
2129 | { | ||
2130 | char buf[16384]; /* Flawfinder: ignore */ | ||
2131 | |||
2132 | // First we get the string | ||
2133 | if (!CPUInfoToText(buf, 16383)) | ||
2134 | return false; | ||
2135 | |||
2136 | // Then we create a new file (CREATE_ALWAYS) | ||
2137 | FILE *file = LLFile::fopen(strFilename, "w"); /* Flawfinder: ignore */ | ||
2138 | if (!file) | ||
2139 | return false; | ||
2140 | |||
2141 | // After that we write the string to the file | ||
2142 | unsigned long dwBytesToWrite, dwBytesWritten; | ||
2143 | dwBytesToWrite = (unsigned long) strlen(buf); /*Flawfinder: ignore*/ | ||
2144 | dwBytesWritten = (unsigned long) fwrite(buf, 1, dwBytesToWrite, file); | ||
2145 | fclose(file); | ||
2146 | if (dwBytesToWrite != dwBytesWritten) | ||
2147 | return false; | ||
2148 | |||
2149 | // Done | ||
2150 | return true; | ||
2151 | } | ||