Skip to content
Snippets Groups Projects
llprocessor.cpp 90.1 KiB
Newer Older
James Cook's avatar
James Cook committed
/** 
 * @file llprocessor.cpp
 * @brief Code to figure out the processor. Originally by Benjamin Jurke.
 *
 * $LicenseInfo:firstyear=2002&license=viewergpl$
 * 
 * Copyright (c) 2002-2009, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
James Cook's avatar
James Cook committed
 */

// Filename: Processor.cpp
// =======================
// Author: Benjamin Jurke
// File history: 27.02.2002  - File created. Support for Intel and AMD processors
//               05.03.2002  - Fixed the CPUID bug: On Pre-Pentium CPUs the CPUID
//                             command is not available
//                           - The CProcessor::WriteInfoTextFile function do not 
//                             longer use Win32 file functions (-> os independend)
//                           - Optional include of the windows.h header which is
//                             still need for CProcessor::GetCPUFrequency.
//               06.03.2002  - My birthday (18th :-))
//                           - Replaced the '\r\n' line endings in function 
//                             CProcessor::CPUInfoToText by '\n'
//                           - Replaced unsigned __int64 by signed __int64 for
//                             solving some compiler conversion problems
//                           - Fixed a bug at family=6, model=6 (Celeron -> P2)
//////////////////////////////////////////////////////////////////////////////////

#include "linden_common.h"


#if LL_WINDOWS
#	define WIN32_LEAN_AND_MEAN
#	include <winsock2.h>
#	include <windows.h>
#endif
James Cook's avatar
James Cook committed

James Cook's avatar
James Cook committed

#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
// We need the QueryPerformanceCounter and Sleep functions
#define FORCEINLINE __forceinline
#else
#define FORCEINLINE 
#endif


// Some macros we often need
////////////////////////////
#define CheckBit(var, bit)   ((var & (1 << bit)) ? true : false)

#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
// Delays for the specified amount of milliseconds
static	void	_Delay(unsigned int ms)
{
   LARGE_INTEGER	freq, c1, c2;
	__int64		x;

   // Get High-Res Timer frequency
	if (!QueryPerformanceFrequency(&freq))	
		return;
		
	// Convert ms to High-Res Timer value
	x = freq.QuadPart/1000*ms;		

   // Get first snapshot of High-Res Timer value
	QueryPerformanceCounter(&c1);		
	do
	{
            // Get second snapshot
	    QueryPerformanceCounter(&c2);	
	}while(c2.QuadPart-c1.QuadPart < x);
	// Loop while (second-first < x)	
}
#endif

// CProcessor::CProcessor
// ======================
// Class constructor:
/////////////////////////
CProcessor::CProcessor()
{
	uqwFrequency = 0;
James Cook's avatar
James Cook committed
	memset(&CPUInfo, 0, sizeof(CPUInfo));
}

// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
// =========================================================================
// Function to measure the current CPU frequency
////////////////////////////////////////////////////////////////////////////
F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs)
{
#ifndef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
	return 0;
#else
	// If there are invalid measure time parameters, zero msecs for example,
	// we've to exit the function
	if (uiMeasureMSecs < 1)
	{
		// If theres already a measured frequency available, we return it
        if (uqwFrequency > 0)
			return uqwFrequency;
		else
			return 0;
	}

	// Now we check if the CPUID command is available
	if (!CheckCPUIDPresence())
		return 0;

	// First we get the CPUID standard level 0x00000001
	unsigned long reg;
	__asm
	{
		mov eax, 1
        cpuid
		mov reg, edx
	}

	// Then we check, if the RDTSC (Real Date Time Stamp Counter) is available.
	// This function is necessary for our measure process.
	if (!(reg & (1 << 4)))
		return 0;

	// After that we declare some vars and check the frequency of the high
	// resolution timer for the measure process.
	// If there's no high-res timer, we exit.
	__int64 starttime, endtime, timedif, freq, start, end, dif;
	if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq))
		return 0;

	// Now we can init the measure process. We set the process and thread priority
	// to the highest available level (Realtime priority). Also we focus the
	// first processor in the multiprocessor system.
	HANDLE hProcess = GetCurrentProcess();
	HANDLE hThread = GetCurrentThread();
	unsigned long dwCurPriorityClass = GetPriorityClass(hProcess);
	int iCurThreadPriority = GetThreadPriority(hThread);
	unsigned long dwProcessMask, dwSystemMask, dwNewMask = 1;
	GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask);

	SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS);
	SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
	SetProcessAffinityMask(hProcess, dwNewMask);

	// Now we call a CPUID to ensure, that all other prior called functions are
	// completed now (serialization)
	__asm cpuid

	// We ask the high-res timer for the start time
	QueryPerformanceCounter((LARGE_INTEGER *) &starttime);

	// Then we get the current cpu clock and store it
	__asm 
	{
		rdtsc
		mov dword ptr [start+4], edx
		mov dword ptr [start], eax
	}

	// Now we wart for some msecs
	_Delay(uiMeasureMSecs);
//	Sleep(uiMeasureMSecs);

	// We ask for the end time
	QueryPerformanceCounter((LARGE_INTEGER *) &endtime);

	// And also for the end cpu clock
	__asm 
	{
		rdtsc
		mov dword ptr [end+4], edx
		mov dword ptr [end], eax
	}

	// Now we can restore the default process and thread priorities
	SetProcessAffinityMask(hProcess, dwProcessMask);
	SetThreadPriority(hThread, iCurThreadPriority);
	SetPriorityClass(hProcess, dwCurPriorityClass);

	// Then we calculate the time and clock differences
	dif = end - start;
	timedif = endtime - starttime;

	// And finally the frequency is the clock difference divided by the time
	// difference. 
	uqwFrequency = (F64)dif / (((F64)timedif) / freq);

	// At last we just return the frequency that is also stored in the call
	// member var uqwFrequency
	return uqwFrequency;
#endif
}

// bool CProcessor::AnalyzeIntelProcessor()
// ========================================
// Private class function for analyzing an Intel processor
//////////////////////////////////////////////////////////
bool CProcessor::AnalyzeIntelProcessor()
{
#if LL_WINDOWS
	unsigned long eaxreg, ebxreg, edxreg;

	// First we check if the CPUID command is available
	if (!CheckCPUIDPresence())
		return false;

	// Now we get the CPUID standard level 0x00000001
	__asm
	{
		mov eax, 1
		cpuid
		mov eaxreg, eax
		mov ebxreg, ebx
		mov edxreg, edx
	}
    
	// Then get the cpu model, family, type, stepping and brand id by masking
	// the eax and ebx register
	CPUInfo.uiStepping = eaxreg & 0xF;
	CPUInfo.uiModel    = (eaxreg >> 4) & 0xF;
	CPUInfo.uiFamily   = (eaxreg >> 8) & 0xF;
	CPUInfo.uiType     = (eaxreg >> 12) & 0x3;
	CPUInfo.uiBrandID  = ebxreg & 0xF;

James Cook's avatar
James Cook committed
	{
		/* 0x00 */ "",
		/* 0x01 */ "0.18 micron Intel Celeron",
		/* 0x02 */ "0.18 micron Intel Pentium III",
		/* 0x03 */ "0.13 micron Intel Celeron",
		/* 0x04 */ "0.13 micron Intel Pentium III",
		/* 0x05 */ "",
		/* 0x06 */ "0.13 micron Intel Pentium III Mobile",
		/* 0x07 */ "0.13 micron Intel Celeron Mobile",
		/* 0x08 */ "0.18 micron Intel Pentium 4",
		/* 0x09 */ "0.13 micron Intel Pentium 4",
		/* 0x0A */ "0.13 micron Intel Celeron",
		/* 0x0C */ "Intel Xeon MP",
		/* 0x0D */ "",
		/* 0x0E */ "0.18 micron Intel Pentium 4 Xeon",
		/* 0x0F */ "Mobile Intel Celeron",
		/* 0x11 */ "Mobile Genuine Intel",
		/* 0x13 */ "Mobile Intel Celeron",
		/* 0x15 */ "Mobile Genuine Intel",
		/* 0x17 */ "Mobile Intel Celeron",
	};

	// Only override the brand if we have it in the lookup table.  We should
	// already have a string here from GetCPUInfo().  JC
	if ( CPUInfo.uiBrandID < LL_ARRAY_SIZE(INTEL_BRAND) )
James Cook's avatar
James Cook committed
	{
Tofu Linden's avatar
Tofu Linden committed
		strncpy(CPUInfo.strBrandID, INTEL_BRAND[CPUInfo.uiBrandID], sizeof(CPUInfo.strBrandID)-1);
		CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';

		if (CPUInfo.uiBrandID == 3 && CPUInfo.uiModel == 6)
		{
			strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III Xeon");
		}
James Cook's avatar
James Cook committed
	}

	// Then we translate the cpu family
    switch (CPUInfo.uiFamily)
	{
		case 3:			// Family = 3:  i386 (80386) processor family
			strcpy(CPUInfo.strFamily, "Intel i386");	/* Flawfinder: ignore */	
			break;
		case 4:			// Family = 4:  i486 (80486) processor family
			strcpy(CPUInfo.strFamily, "Intel i486");	/* Flawfinder: ignore */	
			break;
		case 5:			// Family = 5:  Pentium (80586) processor family
			strcpy(CPUInfo.strFamily, "Intel Pentium");	/* Flawfinder: ignore */	
			break;
		case 6:			// Family = 6:  Pentium Pro (80686) processor family
			strcpy(CPUInfo.strFamily, "Intel Pentium Pro/2/3, Core");	/* Flawfinder: ignore */	
James Cook's avatar
James Cook committed
			break;
		case 15:		// Family = 15:  Extended family specific
			// Masking the extended family
			CPUInfo.uiExtendedFamily = (eaxreg >> 20) & 0xFF;
			switch (CPUInfo.uiExtendedFamily)
			{
				case 0:			// Family = 15, Ext. Family = 0:  Pentium 4 (80786 ??) processor family
					strcpy(CPUInfo.strFamily, "Intel Pentium 4");	/* Flawfinder: ignore */	
					break;
				case 1:			// Family = 15, Ext. Family = 1:  McKinley (64-bit) processor family
					strcpy(CPUInfo.strFamily, "Intel McKinley (IA-64)");	/* Flawfinder: ignore */	
					break;
				default:		// Sure is sure
					strcpy(CPUInfo.strFamily, "Unknown Intel Pentium 4+");	/* Flawfinder: ignore */	
					break;
			}
			break;
		default:		// Failsave
			strcpy(CPUInfo.strFamily, "Unknown");	/* Flawfinder: ignore */
			break;
    }

	// Now we come to the big deal, the exact model name
	switch (CPUInfo.uiFamily)
	{
		case 3:			// i386 (80386) processor family
			strcpy(CPUInfo.strModel, "Unknown Intel i386");	/* Flawfinder: ignore */
			strncat(strCPUName, "Intel i386", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */		
			break;
		case 4:			// i486 (80486) processor family
			switch (CPUInfo.uiModel)
			{
				case 0:			// Model = 0:  i486 DX-25/33 processor model
					strcpy(CPUInfo.strModel, "Intel i486 DX-25/33");	/* Flawfinder: ignore */			
					strncat(strCPUName, "Intel i486 DX-25/33", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */		
					break;
				case 1:			// Model = 1:  i486 DX-50 processor model
					strcpy(CPUInfo.strModel, "Intel i486 DX-50");	/* Flawfinder: ignore */		
					strncat(strCPUName, "Intel i486 DX-50", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */		
					break;
				case 2:			// Model = 2:  i486 SX processor model
					strcpy(CPUInfo.strModel, "Intel i486 SX");	/* Flawfinder: ignore */		
					strncat(strCPUName, "Intel i486 SX", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */		
					break;
				case 3:			// Model = 3:  i486 DX2 (with i487 numeric coprocessor) processor model
					strcpy(CPUInfo.strModel, "Intel i486 487/DX2");	/* Flawfinder: ignore */		
					strncat(strCPUName, "Intel i486 DX2 with i487 numeric coprocessor", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */		
					break;
				case 4:			// Model = 4:  i486 SL processor model (never heard ?!?)
					strcpy(CPUInfo.strModel, "Intel i486 SL");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel i486 SL", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;
				case 5:			// Model = 5:  i486 SX2 processor model
					strcpy(CPUInfo.strModel, "Intel i486 SX2");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel i486 SX2", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;
				case 7:			// Model = 7:  i486 write-back enhanced DX2 processor model
					strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX2");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel i486 write-back enhanced DX2", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;
				case 8:			// Model = 8:  i486 DX4 processor model
					strcpy(CPUInfo.strModel, "Intel i486 DX4");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;
				case 9:			// Model = 9:  i486 write-back enhanced DX4 processor model
					strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX4");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;
				default:		// ...
					strcpy(CPUInfo.strModel, "Unknown Intel i486");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel i486 (Unknown model)", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;
			}
			break;
		case 5:			// Pentium (80586) processor family
			switch (CPUInfo.uiModel)
			{
				case 0:			// Model = 0:  Pentium (P5 A-Step) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium (P5 A-Step)");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel Pentium (P5 A-Step core)", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;		// Famous for the DIV bug, as far as I know
				case 1:			// Model = 1:  Pentium 60/66 processor model
					strcpy(CPUInfo.strModel, "Intel Pentium 60/66 (P5)");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel Pentium 60/66 (P5 core)", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;
				case 2:			// Model = 2:  Pentium 75-200 (P54C) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium 75-200 (P54C)");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel Pentium 75-200 (P54C core)", sizeof(strCPUName)-strlen(strCPUName)-1);	/* Flawfinder: ignore */	
					break;
				case 3:			// Model = 3:  Pentium overdrive for 486 systems processor model
					strcpy(CPUInfo.strModel, "Intel Pentium for 486 system (P24T Overdrive)");	/* Flawfinder: ignore */	
					strncat(strCPUName, "Intel Pentium for 486 (P24T overdrive core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 4:			// Model = 4:  Pentium MMX processor model
					strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C)");	/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium MMX (P55C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 7:			// Model = 7:  Pentium processor model (don't know difference to Model=2)
					strcpy(CPUInfo.strModel, "Intel Pentium (P54C)");		/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium (P54C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 8:			// Model = 8:  Pentium MMX (0.25 micron) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C), 0.25 micron");		/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium MMX (P55C core), 0.25 micron", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				default:		// ...
					strcpy(CPUInfo.strModel, "Unknown Intel Pentium");	/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium (Unknown P5-model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
			}
			break;
		case 6:			// Pentium Pro (80686) processor family
			switch (CPUInfo.uiModel)
			{
				case 0:			// Model = 0:  Pentium Pro (P6 A-Step) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6 A-Step)");		/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium Pro (P6 A-Step core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 1:			// Model = 1:  Pentium Pro
					strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6)");		/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium Pro (P6 core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 3:			// Model = 3:  Pentium II (66 MHz FSB, I think) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium II Model 3, 0.28 micron");		/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium II (Model 3 core, 0.28 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 5:			// Model = 5:  Pentium II/Xeon/Celeron (0.25 micron) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium II Model 5/Xeon/Celeron, 0.25 micron");		/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium II/Xeon/Celeron (Model 5 core, 0.25 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 6:			// Model = 6:  Pentium II with internal L2 cache
					strcpy(CPUInfo.strModel, "Intel Pentium II - internal L2 cache");	/*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium II with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 7:			// Model = 7:  Pentium III/Xeon (extern L2 cache) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium III/Pentium III Xeon - external L2 cache, 0.25 micron");		 /*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium III/Pentium III Xeon (0.25 micron process) with external L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 8:			// Model = 8:  Pentium III/Xeon/Celeron (256 KB on-die L2 cache) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron");	 /*Flawfinder: ignore*/
					// We want to know it exactly:
					switch (CPUInfo.uiBrandID)
					{
						case 1:			// Model = 8, Brand id = 1:  Celeron (on-die L2 cache) processor model
							strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
                        case 2:			// Model = 8, Brand id = 2:  Pentium III (on-die L2 cache) processor model (my current cpu :-))
James Cook's avatar
James Cook committed
							strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
						case 3:			// Model = 8, Brand id = 3:  Pentium III Xeon (on-die L2 cache) processor model
                            strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
James Cook's avatar
James Cook committed
							break;
James Cook's avatar
James Cook committed
							strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
					}
					break;
				case 9:		// Model = 9:  Intel Pentium M processor, Intel Celeron M processor, model 9
					strcpy(CPUInfo.strModel, "Intel Pentium M Series Processor");	 /*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium M Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
James Cook's avatar
James Cook committed
				case 0xA:		// Model = 0xA:  Pentium III/Xeon/Celeron (1 or 2 MB on-die L2 cache) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron");	 /*Flawfinder: ignore*/
					// Exact detection:
					switch (CPUInfo.uiBrandID)
					{
						case 1:			// Model = 0xA, Brand id = 1:  Celeron (1 or 2 MB on-die L2 cache (does it exist??)) processor model
							strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
                        case 2:			// Model = 0xA, Brand id = 2:  Pentium III (1 or 2 MB on-die L2 cache (never seen...)) processor model
James Cook's avatar
James Cook committed
							strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
						case 3:			// Model = 0xA, Brand id = 3:  Pentium III Xeon (1 or 2 MB on-die L2 cache) processor model
                            strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
James Cook's avatar
James Cook committed
							break;
						default:		// Getting bored of this............
							strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
					}
					break;
				case 0xB:		// Model = 0xB: Pentium III/Xeon/Celeron (Tualatin core, on-die cache) processor model
					strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.13 micron");	 /*Flawfinder: ignore*/
					// Omniscient: ;-)
					switch (CPUInfo.uiBrandID)
					{
						case 3:			// Model = 0xB, Brand id = 3:  Celeron (Tualatin core) processor model
							strncat(strCPUName, "Intel Celeron (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
                        case 4:			// Model = 0xB, Brand id = 4:  Pentium III (Tualatin core) processor model
James Cook's avatar
James Cook committed
							strncat(strCPUName, "Intel Pentium III (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
						case 7:			// Model = 0xB, Brand id = 7:  Celeron mobile (Tualatin core) processor model
                            strncat(strCPUName, "Intel Celeron mobile (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
James Cook's avatar
James Cook committed
							break;
						default:		// *bored*
							strncat(strCPUName, "Intel Pentium III Tualatin core (unknown model, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
							break;
					}
					break;
				case 0xD:		// Model = 0xD:  Intel Pentium M processor, Intel Celeron M processor, model D
					strcpy(CPUInfo.strModel, "Intel Pentium M Series Processor");	 /*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium M Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;
				case 0xE:		// Model = 0xE:  Intel Core Duo processor, Intel Core Solo processor, model E
					strcpy(CPUInfo.strModel, "Intel Core Series Processor");	 /*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Core Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					break;	
				case 0xF:		// Model = 0xF:  Intel Core 2 Duo processor, model F
					strcpy(CPUInfo.strModel, "Intel Core 2 Series Processor");	 /*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Core 2 Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
James Cook's avatar
James Cook committed
				default:		// *more bored*
					strcpy(CPUInfo.strModel, "Unknown Intel Pentium Pro/2/3, Core"); /*Flawfinder: ignore*/
					strncat(strCPUName, "Intel Pentium Pro/2/3, Core (Unknown model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
James Cook's avatar
James Cook committed
					break;
			}
			break;
		case 15:		// Extended processor family
			// Masking the extended model
			CPUInfo.uiExtendedModel = (eaxreg >> 16) & 0xFF;
			switch (CPUInfo.uiModel)
			{
				case 0:			// Model = 0:  Pentium 4 Willamette (A-Step) core
					if ((CPUInfo.uiBrandID) == 8)	// Brand id = 8:  P4 Willamette
					{
						strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette (A-Step)"); /*Flawfinder: ignore*/
						strncat(strCPUName, "Intel Pentium 4 Willamette (A-Step)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/
					}
					else							// else Xeon
					{
						strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon (A-Step)");		/* Flawfinder: ignore */
						strncat(strCPUName, "Intel Pentium 4 Willamette Xeon (A-Step)", sizeof(strCPUName) - strlen(strCPUName) - 1);		/* Flawfinder: ignore */	
					}
					break;
				case 1:			// Model = 1:  Pentium 4 Willamette core
					if ((CPUInfo.uiBrandID) == 8)	// Brand id = 8:  P4 Willamette
					{
						strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette");		/* Flawfinder: ignore */
						strncat(strCPUName, "Intel Pentium 4 Willamette", sizeof(strCPUName) - strlen(strCPUName) - 1);		/* Flawfinder: ignore */
					}
					else							// else Xeon
					{
						strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon");		/* Flawfinder: ignore */
						strncat(strCPUName, "Intel Pentium 4 Willamette Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1);		/* Flawfinder: ignore */
					}
					break;
				case 2:			// Model = 2:  Pentium 4 Northwood core
					if (((CPUInfo.uiBrandID) == 9) || ((CPUInfo.uiBrandID) == 0xA))		// P4 Willamette
					{
						strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood");		/* Flawfinder: ignore */
						strncat(strCPUName, "Intel Pentium 4 Northwood", sizeof(strCPUName) - strlen(strCPUName) - 1);		/* Flawfinder: ignore */
					}
					else							// Xeon
					{
						strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood Xeon");		/* Flawfinder: ignore */
						strncat(strCPUName, "Intel Pentium 4 Northwood Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1);		/* Flawfinder: ignore */
					}
					break;
				default:		// Silly stupid never used failsave option
					strcpy(CPUInfo.strModel, "Unknown Intel Pentium 4");		/* Flawfinder: ignore */
					strncat(strCPUName, "Intel Pentium 4 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1);		/* Flawfinder: ignore */
					break;
			}
			break;
		default:		// *grmpf*
			strcpy(CPUInfo.strModel, "Unknown Intel model");		/* Flawfinder: ignore */
			strncat(strCPUName, "Intel (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1);		/* Flawfinder: ignore */
			break;
    }

	// After the long processor model block we now come to the processors serial
	// number.
	// First of all we check if the processor supports the serial number
	if (CPUInfo.MaxSupportedLevel >= 3)
	{
		// If it supports the serial number CPUID level 0x00000003 we read the data
		unsigned long sig1, sig2, sig3;
		__asm
		{
			mov eax, 1
			cpuid
			mov sig1, eax
			mov eax, 3
			cpuid
			mov sig2, ecx
			mov sig3, edx
		}
		// Then we convert the data to a readable string
James Cook's avatar
James Cook committed
			CPUInfo.strProcessorSerial,
			sizeof(CPUInfo.strProcessorSerial),
			"%04lX-%04lX-%04lX-%04lX-%04lX-%04lX",
			sig1 >> 16,
			sig1 & 0xFFFF,
			sig3 >> 16,
			sig3 & 0xFFFF,
James Cook's avatar
James Cook committed
	}
	else
	{
		// If there's no serial number support we just put "No serial number"
Karen Clark's avatar
Karen Clark committed
		snprintf(	/* Flawfinder: ignore */
James Cook's avatar
James Cook committed
			CPUInfo.strProcessorSerial,
			sizeof(CPUInfo.strProcessorSerial),
James Cook's avatar
James Cook committed
	}

	// Now we get the standard processor extensions
	GetStandardProcessorExtensions();

	// And finally the processor configuration (caches, TLBs, ...) and translate
	// the data to readable strings
	GetStandardProcessorConfiguration();
	TranslateProcessorConfiguration();

	// At last...
	return true;
#else
	return FALSE;
#endif
}

// bool CProcessor::AnalyzeAMDProcessor()
// ======================================
// Private class function for analyzing an AMD processor
////////////////////////////////////////////////////////
bool CProcessor::AnalyzeAMDProcessor()
{
#if LL_WINDOWS
	unsigned long eaxreg, ebxreg, ecxreg, edxreg;

	// First of all we check if the CPUID command is available
	if (!CheckCPUIDPresence())
		return 0;

	// Now we get the CPUID standard level 0x00000001
	__asm
	{
		mov eax, 1
		cpuid
		mov eaxreg, eax
		mov ebxreg, ebx
		mov edxreg, edx
	}
    
	// Then we mask the model, family, stepping and type (AMD does not support brand id)
	CPUInfo.uiStepping = eaxreg & 0xF;
	CPUInfo.uiModel    = (eaxreg >> 4) & 0xF;
	CPUInfo.uiFamily   = (eaxreg >> 8) & 0xF;
	CPUInfo.uiType     = (eaxreg >> 12) & 0x3;

	// Now we check if the processor supports the brand id string extended CPUID level
	if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000004)
	{
		// If it supports the extended CPUID level 0x80000004 we read the data
		char tmp[52];		/* Flawfinder: ignore */
		memset(tmp, 0, sizeof(tmp));
        __asm
		{
			mov eax, 0x80000002
			cpuid
			mov dword ptr [tmp], eax
			mov dword ptr [tmp+4], ebx
			mov dword ptr [tmp+8], ecx
			mov dword ptr [tmp+12], edx
			mov eax, 0x80000003
			cpuid
			mov dword ptr [tmp+16], eax
			mov dword ptr [tmp+20], ebx
			mov dword ptr [tmp+24], ecx
			mov dword ptr [tmp+28], edx
			mov eax, 0x80000004
			cpuid
			mov dword ptr [tmp+32], eax
			mov dword ptr [tmp+36], ebx
			mov dword ptr [tmp+40], ecx
			mov dword ptr [tmp+44], edx
		}
		// And copy it to the brand id string
		strncpy(CPUInfo.strBrandID, tmp,sizeof(CPUInfo.strBrandID)-1);
		CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
James Cook's avatar
James Cook committed
	}
	else
	{
		// Or just tell there is no brand id string support
		strcpy(CPUInfo.strBrandID, "");		/* Flawfinder: ignore */
James Cook's avatar
James Cook committed
	}

	// After that we translate the processor family
    switch(CPUInfo.uiFamily)
	{
		case 4:			// Family = 4:  486 (80486) or 5x86 (80486) processor family
			switch (CPUInfo.uiModel)
			{
				case 3:			// Thanks to AMD for this nice form of family
				case 7:			// detection.... *grmpf*
				case 8:
				case 9:
					strcpy(CPUInfo.strFamily, "AMD 80486");		/* Flawfinder: ignore */
					break;
				case 0xE:
				case 0xF:
					strcpy(CPUInfo.strFamily, "AMD 5x86");		/* Flawfinder: ignore */
					break;
				default:
					strcpy(CPUInfo.strFamily, "Unknown family");		/* Flawfinder: ignore */
					break;
			}
			break;
		case 5:			// Family = 5:  K5 or K6 processor family
			switch (CPUInfo.uiModel)
			{
				case 0:
				case 1:
				case 2:
				case 3:
					strcpy(CPUInfo.strFamily, "AMD K5");		/* Flawfinder: ignore */
					break;
				case 6:
				case 7:
				case 8:
				case 9:
					strcpy(CPUInfo.strFamily, "AMD K6");		/* Flawfinder: ignore */
					break;
				default:
					strcpy(CPUInfo.strFamily, "Unknown family");		/* Flawfinder: ignore */
					break;
			}
			break;
		case 6:			// Family = 6:  K7 (Athlon, ...) processor family
			strcpy(CPUInfo.strFamily, "AMD K7");		/* Flawfinder: ignore */
			break;
		default:		// For security
			strcpy(CPUInfo.strFamily, "Unknown family");		/* Flawfinder: ignore */
			break;
	}

	// After the family detection we come to the specific processor model
	// detection
	switch (CPUInfo.uiFamily)
	{
		case 4:			// Family = 4:  486 (80486) or 5x85 (80486) processor family
			switch (CPUInfo.uiModel)
			{
				case 3:			// Model = 3:  80486 DX2
					strcpy(CPUInfo.strModel, "AMD 80486 DX2");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD 80486 DX2", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 7:			// Model = 7:  80486 write-back enhanced DX2
					strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX2");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD 80486 write-back enhanced DX2", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 8:			// Model = 8:  80486 DX4
					strcpy(CPUInfo.strModel, "AMD 80486 DX4");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD 80486 DX4", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 9:			// Model = 9:  80486 write-back enhanced DX4
					strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX4");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD 80486 write-back enhanced DX4", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 0xE:		// Model = 0xE:  5x86
					strcpy(CPUInfo.strModel, "AMD 5x86");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD 5x86", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 0xF:		// Model = 0xF:  5x86 write-back enhanced (oh my god.....)
					strcpy(CPUInfo.strModel, "AMD 5x86 write-back enhanced");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD 5x86 write-back enhanced", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				default:		// ...
					strcpy(CPUInfo.strModel, "Unknown AMD 80486 or 5x86 model");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD 80486 or 5x86 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
			}
			break;
		case 5:			// Family = 5:  K5 / K6 processor family
			switch (CPUInfo.uiModel)
			{
				case 0:			// Model = 0:  K5 SSA 5 (Pentium Rating *ggg* 75, 90 and 100 Mhz)
					strcpy(CPUInfo.strModel, "AMD K5 SSA5 (PR75, PR90, PR100)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K5 SSA5 (PR75, PR90, PR100)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 1:			// Model = 1:  K5 5k86 (PR 120 and 133 MHz)
					strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR120, PR133)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K5 5k86 (PR120, PR133)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 2:			// Model = 2:  K5 5k86 (PR 166 MHz)
					strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR166)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K5 5k86 (PR166)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 3:			// Model = 3:  K5 5k86 (PR 200 MHz)
					strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR200)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K5 5k86 (PR200)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 6:			// Model = 6:  K6
					strcpy(CPUInfo.strModel, "AMD K6 (0.30 micron)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K6 (0.30 micron)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 7:			// Model = 7:  K6 (0.25 micron)
					strcpy(CPUInfo.strModel, "AMD K6 (0.25 micron)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K6 (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 8:			// Model = 8:  K6-2
					strcpy(CPUInfo.strModel, "AMD K6-2");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K6-2", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 9:			// Model = 9:  K6-III
					strcpy(CPUInfo.strModel, "AMD K6-III");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K6-III", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 0xD:		// Model = 0xD:  K6-2+ / K6-III+
					strcpy(CPUInfo.strModel, "AMD K6-2+ or K6-III+ (0.18 micron)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1);	/* Flawfinder: ignore */
James Cook's avatar
James Cook committed
					break;
				default:		// ...
					strcpy(CPUInfo.strModel, "Unknown AMD K5 or K6 model");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K5 or K6 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
			}
			break;
		case 6:			// Family = 6:  K7 processor family (AMDs first good processors)
			switch (CPUInfo.uiModel)
			{
				case 1:			// Athlon
					strcpy(CPUInfo.strModel, "AMD Athlon (0.25 micron)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD Athlon (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 2:			// Athlon (0.18 micron)
					strcpy(CPUInfo.strModel, "AMD Athlon (0.18 micron)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD Athlon (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 3:			// Duron (Spitfire core)
					strcpy(CPUInfo.strModel, "AMD Duron (Spitfire)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD Duron (Spitfire core)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 4:			// Athlon (Thunderbird core)
					strcpy(CPUInfo.strModel, "AMD Athlon (Thunderbird)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD Athlon (Thunderbird core)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 6:			// Athlon MP / Mobile Athlon (Palomino core)
					strcpy(CPUInfo.strModel, "AMD Athlon MP/Mobile Athlon (Palomino)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD Athlon MP/Mobile Athlon (Palomino core)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				case 7:			// Mobile Duron (Morgan core)
					strcpy(CPUInfo.strModel, "AMD Mobile Duron (Morgan)");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD Mobile Duron (Morgan core)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
				default:		// ...
					strcpy(CPUInfo.strModel, "Unknown AMD K7 model");		/* Flawfinder: ignore */
					strncat(strCPUName, "AMD K7 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
					break;
			}
			break;
		default:		// ...
			strcpy(CPUInfo.strModel, "Unknown AMD model");		/* Flawfinder: ignore */
			strncat(strCPUName, "AMD (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1);		/* Flawfinder: ignore */
			break;
    }

	// Now we read the standard processor extension that are stored in the same
	// way the Intel standard extensions are
	GetStandardProcessorExtensions();

	// Then we check if theres an extended CPUID level support
	if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000001)
	{
		// If we can access the extended CPUID level 0x80000001 we get the
		// edx register
		__asm
		{
			mov eax, 0x80000001
			cpuid
			mov edxreg, edx
		}

		// Now we can mask some AMD specific cpu extensions
		CPUInfo._Ext.EMMX_MultimediaExtensions					= CheckBit(edxreg, 22);
		CPUInfo._Ext.AA64_AMD64BitArchitecture					= CheckBit(edxreg, 29);
		CPUInfo._Ext._E3DNOW_InstructionExtensions				= CheckBit(edxreg, 30);
		CPUInfo._Ext._3DNOW_InstructionExtensions				= CheckBit(edxreg, 31);
	}

	// After that we check if the processor supports the ext. CPUID level
	// 0x80000006
	if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000006)
	{
		// If it's present, we read it out
        __asm
		{
            mov eax, 0x80000005
			cpuid
			mov eaxreg, eax
			mov ebxreg, ebx
			mov ecxreg, ecx
			mov edxreg, edx
		}

		// Then we mask the L1 Data TLB information
		if ((ebxreg >> 16) && (eaxreg >> 16))
		{
			CPUInfo._Data.bPresent = true;
			strcpy(CPUInfo._Data.strPageSize, "4 KB / 2 MB / 4MB"); 	/*Flawfinder: ignore*/
			CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF;
			CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF;
		}
		else if (eaxreg >> 16)
		{
			CPUInfo._Data.bPresent = true;
			strcpy(CPUInfo._Data.strPageSize, "2 MB / 4MB");		/*Flawfinder: ignore*/
			CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF;
			CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF;
		}
		else if (ebxreg >> 16)
		{
			CPUInfo._Data.bPresent = true;
			strcpy(CPUInfo._Data.strPageSize, "4 KB");		/*Flawfinder: ignore*/
			CPUInfo._Data.uiAssociativeWays = (ebxreg >> 24) & 0xFF;
			CPUInfo._Data.uiEntries = (ebxreg >> 16) & 0xFF;
		}
		if (CPUInfo._Data.uiAssociativeWays == 0xFF)
			CPUInfo._Data.uiAssociativeWays = (unsigned int) -1;

		// Now the L1 Instruction/Code TLB information
		if ((ebxreg & 0xFFFF) && (eaxreg & 0xFFFF))
		{
			CPUInfo._Instruction.bPresent = true;
			strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4MB");		/*Flawfinder: ignore*/
			CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF;
			CPUInfo._Instruction.uiEntries = eaxreg & 0xFF;
		}
		else if (eaxreg & 0xFFFF)
		{
			CPUInfo._Instruction.bPresent = true;
			strcpy(CPUInfo._Instruction.strPageSize, "2 MB / 4MB");		/*Flawfinder: ignore*/
			CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF;
			CPUInfo._Instruction.uiEntries = eaxreg & 0xFF;
		}
		else if (ebxreg & 0xFFFF)
		{
			CPUInfo._Instruction.bPresent = true;
			strcpy(CPUInfo._Instruction.strPageSize, "4 KB");	/*Flawfinder: ignore*/
			CPUInfo._Instruction.uiAssociativeWays = (ebxreg >> 8) & 0xFF;
			CPUInfo._Instruction.uiEntries = ebxreg & 0xFF;
		}
		if (CPUInfo._Instruction.uiAssociativeWays == 0xFF)
			CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1;
		
		// Then we read the L1 data cache information
		if ((ecxreg >> 24) > 0)
		{
			CPUInfo._L1.Data.bPresent = true;
Karen Clark's avatar
Karen Clark committed
			snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", ecxreg >> 24);		/* Flawfinder: ignore */
James Cook's avatar
James Cook committed
			CPUInfo._L1.Data.uiAssociativeWays = (ecxreg >> 15) & 0xFF;
			CPUInfo._L1.Data.uiLineSize = ecxreg & 0xFF;
		}
		// After that we read the L2 instruction/code cache information
		if ((edxreg >> 24) > 0)
		{
			CPUInfo._L1.Instruction.bPresent = true;
Karen Clark's avatar
Karen Clark committed
			snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", edxreg >> 24); 	/* Flawfinder: ignore */
James Cook's avatar
James Cook committed
			CPUInfo._L1.Instruction.uiAssociativeWays = (edxreg >> 15) & 0xFF;
			CPUInfo._L1.Instruction.uiLineSize = edxreg & 0xFF;
		}

		// Note: I'm not absolutely sure that the L1 page size code (the
		// 'if/else if/else if' structs above) really detects the real page
		// size for the TLB. Somebody should check it....

		// Now we read the ext. CPUID level 0x80000006
        __asm
		{
			mov eax, 0x80000006
			cpuid
			mov eaxreg, eax
			mov ebxreg, ebx
			mov ecxreg, ecx
		}

		// We only mask the unified L2 cache masks (never heard of an
		// L2 cache that is divided in data and code parts)
		if (((ecxreg >> 12) & 0xF) > 0)
		{
			CPUInfo._L2.bPresent = true;
Karen Clark's avatar
Karen Clark committed
			snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", ecxreg >> 16);		/* Flawfinder: ignore */
James Cook's avatar
James Cook committed
			switch ((ecxreg >> 12) & 0xF)
			{
				case 1:
					CPUInfo._L2.uiAssociativeWays = 1;
					break;
				case 2:
					CPUInfo._L2.uiAssociativeWays = 2;
					break;
				case 4:
					CPUInfo._L2.uiAssociativeWays = 4;
					break;