// CPU.cpp : Defines the initialization routines for the DLL. // // created by Unwinder ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include #include #include #include #include "CPU.h" #include "CPUGlobals.h" #include "CPUTopology.h" #include "MAHMSharedMemory.h" #include "MSIAfterburnerMonitoringSourceDesc.h" #include "MSIAfterburnerExports.h" #include "ProcessAffinityMask.h" #include "TimestampedDataCache.h" ////////////////////////////////////////////////////////////////////// #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ////////////////////////////////////////////////////////////////////// static AFX_EXTENSION_MODULE CPUDLL = { NULL, NULL }; ////////////////////////////////////////////////////////////////////// #define MAX_CPU 256 ////////////////////////////////////////////////////////////////////// #define CPU_ARCH_UNKNOWN 0x00000000 #define CPU_ARCH_INTEL_NETBURST 0x80860001 #define CPU_ARCH_INTEL_CORE 0x80860002 #define CPU_ARCH_INTEL_ATOM 0x80860003 #define CPU_ARCH_INTEL_NEHALEM 0x80860004 #define CPU_ARCH_INTEL_SANDYBRIDGE 0x80860005 #define CPU_ARCH_INTEL_IVYBRIDGE 0x80860006 #define CPU_ARCH_INTEL_HASWELL 0x80860007 #define CPU_ARCH_INTEL_BROADWELL 0x80860008 #define CPU_ARCH_INTEL_SILVERMONT 0x80860009 #define CPU_ARCH_INTEL_SKYLAKE 0x8086000A #define CPU_ARCH_INTEL_AIRMONT 0x8086000B #define CPU_ARCH_INTEL_KABYLAKE 0x8086000C #define CPU_ARCH_INTEL_GOLDMONT 0x8086000D #define CPU_ARCH_INTEL_GOLDMONTPLUS 0x8086000E #define CPU_ARCH_INTEL_CANNONLAKE 0x8086000F #define CPU_ARCH_INTEL_ICELAKE 0x80860010 #define CPU_ARCH_INTEL_COMETLAKE 0x80860011 #define CPU_ARCH_INTEL_TREMONT 0x80860012 #define CPU_ARCH_INTEL_TIGERLAKE 0x80860013 #define CPU_ARCH_INTEL_ROCKETLAKE 0x80860014 #define CPU_ARCH_AMD_FAMILY_10H 0x10220001 #define CPU_ARCH_AMD_FAMILY_11H 0x10220002 #define CPU_ARCH_AMD_FAMILY_12H 0x10220003 #define CPU_ARCH_AMD_FAMILY_14H 0x10220004 #define CPU_ARCH_AMD_FAMILY_15H_MODEL_00 0x10220005 #define CPU_ARCH_AMD_FAMILY_15H_MODEL_10 0x10220006 #define CPU_ARCH_AMD_FAMILY_15H_MODEL_30 0x10220007 #define CPU_ARCH_AMD_FAMILY_16H_MODEL_00 0x10220008 #define CPU_ARCH_AMD_FAMILY_16H_MODEL_30 0x10220009 #define CPU_ARCH_AMD_FAMILY_17H_MODEL_00 0x1022000A #define CPU_ARCH_AMD_FAMILY_17H_MODEL_10 0x1022000B #define CPU_ARCH_AMD_FAMILY_17H_MODEL_60 0x1022000C #define CPU_ARCH_AMD_FAMILY_17H_MODEL_70 0x1022000D #define CPU_ARCH_AMD_FAMILY_19H_MODEL_20 0x1022000E #define CPU_ARCH_AMD_FAMILY_19H_MODEL_50 0x1022000F ////////////////////////////////////////////////////////////////////// READ_BUS_DATA_ULONG_PROC g_pReadBusDataUlong = NULL; READ_BUS_DATA_USHORT_PROC g_pReadBusDataUshort = NULL; READ_BUS_DATA_UCHAR_PROC g_pReadBusDataUchar = NULL; WRITE_BUS_DATA_ULONG_PROC g_pWriteBusDataUlong = NULL; WRITE_BUS_DATA_USHORT_PROC g_pWriteBusDataUshort = NULL; WRITE_BUS_DATA_UCHAR_PROC g_pWriteBusDataUchar = NULL; READ_MSR_PROC g_pReadMSR = NULL; WRITE_MSR_PROC g_pWriteMSR = NULL; GET_TIMESTAMP_PROC g_pGetTimestamp = NULL; HINSTANCE g_hModule = 0; BOOL g_bEnableLog = FALSE; DWORD g_dwCpuCount = 0; char g_szCpuString[0x20] = { 0 }; char g_szCpuBrandString[0x40] = { 0 }; DWORD g_dwCpuStepping = 0; DWORD g_dwCpuModel = 0; DWORD g_dwCpuModelExt = 0; DWORD g_dwCpuFamily = 0; DWORD g_dwCpuFamilyExt = 0; DWORD g_dwCpuArch = 0; CCPUTopology g_cpuTopology; CTimestampedDataCache g_cpuTemperatureCache; //Intel CPU architecture specific variables DWORD g_dwTjmaxOverride = 0; DWORD g_dwTjmax[MAX_CPU] = { 0 }; //AMD CPU architecture specific variables DWORD g_dwMiscControlDevFn[MAX_CPU] = { 0 }; ////////////////////////////////////////////////////////////////////// // This helper function is used to check if CPU is Intel ////////////////////////////////////////////////////////////////////// BOOL IsIntelCpu() { return !_stricmp(g_szCpuString, "GenuineIntel"); } ////////////////////////////////////////////////////////////////////// // This helper function is used to check if CPU is AMD ////////////////////////////////////////////////////////////////////// BOOL IsAMDCpu() { return !_stricmp(g_szCpuString, "AuthenticAMD"); } ////////////////////////////////////////////////////////////////////// BOOL IsAMDZenArchitecture() { if ((g_dwCpuArch == CPU_ARCH_AMD_FAMILY_17H_MODEL_00) || (g_dwCpuArch == CPU_ARCH_AMD_FAMILY_17H_MODEL_10) || (g_dwCpuArch == CPU_ARCH_AMD_FAMILY_17H_MODEL_60) || (g_dwCpuArch == CPU_ARCH_AMD_FAMILY_17H_MODEL_70) || (g_dwCpuArch == CPU_ARCH_AMD_FAMILY_19H_MODEL_20) || (g_dwCpuArch == CPU_ARCH_AMD_FAMILY_19H_MODEL_50)) return TRUE; return FALSE; } ////////////////////////////////////////////////////////////////////// // This helper function is returning CPU string ////////////////////////////////////////////////////////////////////// LPCSTR GetCpuString() { return g_szCpuString; } ////////////////////////////////////////////////////////////////////// // This helper function is returning CPU brand string ////////////////////////////////////////////////////////////////////// LPCSTR GetCpuBrandString() { return g_szCpuBrandString; } ////////////////////////////////////////////////////////////////////// // This helper function is used to read DWORD from PCR register // if host application supports PCI configuration space access ////////////////////////////////////////////////////////////////////// DWORD ReadBusDataUlong(DWORD bus, DWORD devfn, DWORD offset) { if (g_pReadBusDataUlong) return g_pReadBusDataUlong(bus, devfn, offset); return 0; } ////////////////////////////////////////////////////////////////////// // This helper function is used to read WORD from PCR register // if host application supports PCI configuration space access ////////////////////////////////////////////////////////////////////// WORD ReadBusDataUshort(DWORD bus, DWORD devfn, DWORD offset) { if (g_pReadBusDataUshort) return g_pReadBusDataUshort(bus, devfn, offset); return 0; } ////////////////////////////////////////////////////////////////////// // This helper function is used to read BYTE from PCR register // if host application supports PCI configuration space access ////////////////////////////////////////////////////////////////////// BYTE ReadBusDataUchar(DWORD bus, DWORD devfn, DWORD offset) { if (g_pReadBusDataUchar) return g_pReadBusDataUchar(bus, devfn, offset); return 0; } ////////////////////////////////////////////////////////////////////// // This helper function is used to write DWORD to PCR register // if host application supports PCI configuration space access ////////////////////////////////////////////////////////////////////// void WriteBusDataUlong(DWORD bus, DWORD devfn, DWORD offset, DWORD data) { if (g_pWriteBusDataUlong) g_pWriteBusDataUlong(bus, devfn, offset, data); } ////////////////////////////////////////////////////////////////////// // This helper function is used to write WORD to PCR register // if host application supports PCI configuration space access ////////////////////////////////////////////////////////////////////// void WriteBusDataUshort(DWORD bus, DWORD devfn, DWORD offset, WORD data) { if (g_pWriteBusDataUshort) g_pWriteBusDataUshort(bus, devfn, offset, data); } ////////////////////////////////////////////////////////////////////// // This helper function is used to write BYTE to PCR register // if host application supports PCI configuration space access ////////////////////////////////////////////////////////////////////// void WriteBusDataUchar(DWORD bus, DWORD devfn, DWORD offset, BYTE data) { if (g_pWriteBusDataUchar) g_pWriteBusDataUchar(bus, devfn, offset, data); } ////////////////////////////////////////////////////////////////////// // This helper function is used to read MSR register if host application // supports MSR access ////////////////////////////////////////////////////////////////////// BOOL ReadMSR(DWORD dwIndex, LPDWORD lpHigh, LPDWORD lpLow) { if (g_pReadMSR) return g_pReadMSR(dwIndex, lpHigh, lpLow); return FALSE; } ////////////////////////////////////////////////////////////////////// // This helper function is used to write MSR register if host application // supports MSR access ////////////////////////////////////////////////////////////////////// BOOL WriteMSR(DWORD dwIndex, DWORD dwHigh, DWORD dwLow) { if (g_pWriteMSR) return g_pWriteMSR(dwIndex, dwHigh, dwLow); return FALSE; } ////////////////////////////////////////////////////////////////////// // This helper function is used to read hardware monitoring timestamp // if host application supports reporting it ////////////////////////////////////////////////////////////////////// DWORD GetTimestamp() { if (g_pGetTimestamp) return g_pGetTimestamp(); return 0; } ////////////////////////////////////////////////////////////////////// // This helper function is returning CPU family ////////////////////////////////////////////////////////////////////// DWORD GetCpuFamily() { if (IsIntelCpu()) // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-2a-manual.pdf // // The Extended Family ID needs to be examined only when the Family ID is 0FH. Integrate the fields into a display // using the following rule: // IF Family_ID != 0FH // THEN DisplayFamily = Family_ID; // ELSE DisplayFamily = Extended_Family_ID + Family_ID; // (* Right justify and zero-extend 4-bit field. *) // FI; // (* Show DisplayFamily as HEX field. *) { if (g_dwCpuFamily != 0x0F) return g_dwCpuFamily; return g_dwCpuFamily + g_dwCpuFamilyExt; } if (IsAMDCpu()) // http://support.amd.com/TechDocs/25481.pdf // // The Family is an 8-bit value and is defined as: Family[7:0] = ({0000b,BaseFamily[3:0]} + ExtendedFamily[7:0]). // For example, if BaseFamily[3:0] = Fh and ExtendedFamily[7:0] = 01h, then Family[7:0] = 10h. If // BaseFamily[3:0] is less than Fh then ExtendedFamily[7:0] is reserved and Family is equal to BaseFamily[3:0]. { if (g_dwCpuFamily < 0x0F) return g_dwCpuFamily; return g_dwCpuFamily + g_dwCpuFamilyExt; } return g_dwCpuFamily; } ////////////////////////////////////////////////////////////////////// // This helper function is returning CPU model ////////////////////////////////////////////////////////////////////// DWORD GetCpuModel() { if (IsIntelCpu()) // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-2a-manual.pdf // // The Extended Model ID needs to be examined only when the Family ID is 06H or 0FH. Integrate the field into a // display using the following rule: // IF (Family_ID = 06H or Family_ID = 0FH) // THEN DisplayModel = (Extended_Model_ID < 4) + Model_ID; // (* Right justify and zero-extend 4-bit field; display Model_ID as HEX field.*) // ELSE DisplayModel = Model_ID; // FI; // (* Show DisplayModel as HEX field. *) { if ((g_dwCpuFamily == 0x06) || (g_dwCpuFamily == 0x0F)) return g_dwCpuModel + (g_dwCpuModelExt<<4); return g_dwCpuModel; } if (IsAMDCpu()) // http://support.amd.com/TechDocs/25481.pdf // //Model is an 8-bit value and is defined as: Model[7:0] = {ExtendedModel[3:0],BaseModel[3:0]}. For example, //if ExtendedModel[3:0] = Eh and BaseModel[3:0] = 8h, then Model[7:0] = E8h. If BaseFamily[3:0] is less than //0Fh then ExtendedModel[3:0] is reserved and Model is equal to BaseModel[3:0]. { if (g_dwCpuFamily < 0x0F) return g_dwCpuModel; return g_dwCpuModel + (g_dwCpuModelExt<<4); } return g_dwCpuModel; } ////////////////////////////////////////////////////////////////////// // This helper function is returning CPU stepping ////////////////////////////////////////////////////////////////////// DWORD GetCpuStepping() { return g_dwCpuStepping; } ////////////////////////////////////////////////////////////////////// // This helper function is used to init AMD CPU specific variables // // Source : https://github.com/openhardwaremonitor/openhardwaremonitor/blob/master/Hardware/CPU/AMD10CPU.cs ////////////////////////////////////////////////////////////////////// void InitAMDCpu() { DWORD dwCpuFamily = GetCpuFamily(); DWORD dwCpuModel = GetCpuModel(); if (IsAMDCpu()) //detect AMD CPU architecture and miscellaneous control PCI DeviceID { DWORD dwDeviceID = 0; switch (dwCpuFamily) { case 0x10: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_10H; dwDeviceID = 0x12031022; break; case 0x11: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_11H; dwDeviceID = 0x13031022; break; case 0x12: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_12H; dwDeviceID = 0x17031022; break; case 0x14: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_14H; dwDeviceID = 0x17031022; break; case 0x15: switch (dwCpuModel & 0xF0) { case 0x00: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_15H_MODEL_00; dwDeviceID = 0x16031022; break; case 0x10: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_15H_MODEL_10; dwDeviceID = 0x14031022; break; case 0x30: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_15H_MODEL_30; dwDeviceID = 0x141D1022; break; } break; case 0x16: switch (dwCpuModel & 0xF0) { case 0x00: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_16H_MODEL_00; dwDeviceID = 0x15331022; break; case 0x30: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_16H_MODEL_30; dwDeviceID = 0x15831022; break; } break; case 0x17: switch (dwCpuModel & 0xF0) { case 0x00: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_17H_MODEL_00; break; case 0x10: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_17H_MODEL_10; break; case 0x60: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_17H_MODEL_60; break; case 0x70: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_17H_MODEL_70; break; } case 0x19: switch (dwCpuModel & 0xF0) { case 0x20: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_19H_MODEL_20; break; case 0x50: g_dwCpuArch = CPU_ARCH_AMD_FAMILY_19H_MODEL_50; break; } } if (g_bEnableLog) { CString strLog; strLog.Format("Miscellaneous control PCI DeviceID : %X", dwDeviceID); AppendLog(strLog, TRUE); } if (dwDeviceID) //if we detected supported CPU architecture, miscellaneous control PCI DeviceID is not zero { for (DWORD dwCpu=0; dwCpu>16) & 0x7F; if (g_bEnableLog) { CString strLog; strLog.Format("CPU%d Tjmax : %d°C", dwCpu, g_dwTjmax[dwCpu]); AppendLog(strLog, TRUE); } } else { if (g_bEnableLog) { CString strLog; strLog.Format("CPU%d Tjmax : %d°C hardcoded", dwCpu, g_dwTjmax[dwCpu]); AppendLog(strLog, TRUE); } } } } } ///////////////////////////////////////////////////////////////////////////// // This helper function is used to init vendor agnostic and vendor specific // CPU variables ///////////////////////////////////////////////////////////////////////////// void InitCpu() { //init CPU count SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); g_dwCpuCount = sysInfo.dwNumberOfProcessors; //init CPU model related variables int cpuInfo[4] = { 0 }; __cpuid(cpuInfo, 0); ZeroMemory(g_szCpuString, sizeof(g_szCpuString)); ZeroMemory(g_szCpuBrandString, sizeof(g_szCpuBrandString)); *((int*)g_szCpuString) = cpuInfo[1]; *((int*)(g_szCpuString+4)) = cpuInfo[3]; *((int*)(g_szCpuString+8)) = cpuInfo[2]; __cpuid(cpuInfo, 1); g_dwCpuStepping = (cpuInfo[0] )&0x0F; g_dwCpuModel = (cpuInfo[0]>>4 )&0x0F; g_dwCpuFamily = (cpuInfo[0]>>8 )&0x0F; g_dwCpuModelExt = (cpuInfo[0]>>16)&0x0F; g_dwCpuFamilyExt = (cpuInfo[0]>>20)&0xFF; __cpuid(cpuInfo, 0x80000000); int nMaxEx = cpuInfo[0]; if (nMaxEx >= 0x80000002) { __cpuid(cpuInfo, 0x80000002); CopyMemory(g_szCpuBrandString, cpuInfo, sizeof(cpuInfo)); } if (nMaxEx >= 0x80000003) { __cpuid(cpuInfo, 0x80000003); CopyMemory(g_szCpuBrandString + 16, cpuInfo, sizeof(cpuInfo)); } if (nMaxEx >= 0x80000004) { __cpuid(cpuInfo, 0x80000004); CopyMemory(g_szCpuBrandString + 32, cpuInfo, sizeof(cpuInfo)); } if (g_bEnableLog) { CString strLog; strLog.Format("%s (family %X, model %X, stepping %X), %d logical processors", GetCpuBrandString(), GetCpuFamily(), GetCpuModel(), GetCpuStepping(), g_dwCpuCount); AppendLog(strLog, FALSE); } //init CPU topology g_cpuTopology.Init(); if (g_bEnableLog) { for (DWORD dwCpu=0; dwCpudwData; //otherwise we need to reread the sensor and add it to cache float fltTemperature = GetAMDCpuTemperature(dwCpu); g_cpuTemperatureCache.SetData(dwCpu, dwTimestamp, (DWORD)fltTemperature); return fltTemperature; } return GetAMDCpuTemperature(dwCpu); } } return FLT_MAX; } ///////////////////////////////////////////////////////////////////////////// // This helper function is checking if temperature reporting is supported // on Intel CPUs ///////////////////////////////////////////////////////////////////////////// BOOL IsIntelCpuTemperatureReportingSupported(DWORD dwCpu) { if (IsIntelCpu()) { if (dwCpu == 0xFFFFFFFF) //package temperature { int cpuInfo[4] = { 0 }; __cpuid(cpuInfo, 6); if (cpuInfo[0] & 0x40) return TRUE; } else //core temperature { CProcessAffinityMask affinity(g_dwCpuCount, dwCpu); int cpuInfo[4] = { 0 }; __cpuid(cpuInfo, 6); if (cpuInfo[0] & 1) return TRUE; } } return FALSE; } ////////////////////////////////////////////////////////////////////// // This helper function is checking if temperature reporting is supported // on AMD CPUs ///////////////////////////////////////////////////////////////////////////// BOOL IsAMDCpuTemperatureReportingSupported(DWORD dwCpu) { if (IsAMDCpu()) { if (dwCpu == 0xFFFFFFFF) //package temperature { return FALSE; } else //core tempeature { if (IsAMDZenArchitecture()) { if (!dwCpu) return TRUE; return FALSE; } else { if (g_dwMiscControlDevFn[dwCpu]) return TRUE; return FALSE; } } } return FALSE; } ///////////////////////////////////////////////////////////////////////////// // This helper function is reading CPU temperature on Intel CPUs ///////////////////////////////////////////////////////////////////////////// float GetIntelCpuTemperature(DWORD dwCpu) { float fltResult = FLT_MAX; if (IsIntelCpu()) { DWORD dwTjmax = GetTjmax(dwCpu); if (dwTjmax) { if (dwCpu == 0xFFFFFFFF) //package temperature { DWORD dwLow = 0; DWORD dwHigh = 0; if (ReadMSR(0x1B1/*IA32_PACKAGE_THERM_STATUS*/, &dwHigh, &dwLow)) { DWORD dwTdist = (dwLow>>16) & 0x7F; fltResult = (float)(dwTjmax - dwTdist); } } else //core temperature { CProcessAffinityMask affinity(g_dwCpuCount, dwCpu); DWORD dwLow = 0; DWORD dwHigh = 0; if (ReadMSR(0x19C/*IA32_THERM_STATUS*/, &dwHigh, &dwLow)) { DWORD dwTdist = (dwLow>>16) & 0x7F; fltResult = (float)(dwTjmax - dwTdist); } } } return fltResult; } return FLT_MAX; } ////////////////////////////////////////////////////////////////////// // This helper function is reading system management network register on AMD CPUs ///////////////////////////////////////////////////////////////////////////// DWORD GetAMDSMNRegister(DWORD dwRegister) { HANDLE hMutex = CreateMutex(NULL, FALSE, "Global\\Access_PCI"); if (hMutex) WaitForSingleObject(hMutex, INFINITE); WriteBusDataUlong(0, 0, 0x60, dwRegister); DWORD dwResult = ReadBusDataUlong(0, 0, 0x64); if (hMutex) { ReleaseMutex(hMutex); CloseHandle(hMutex); } return dwResult; } ///////////////////////////////////////////////////////////////////////////// // This helper function is reading CPU temperature on AMD CPUs ///////////////////////////////////////////////////////////////////////////// float GetAMDCpuTemperature(DWORD dwCpu) { if (IsAMDCpu()) { float fltResult = FLT_MAX; if (dwCpu == 0xFFFFFFFF) //package temperature { } else //core temperature { if (IsAMDZenArchitecture()) { if (!dwCpu) { DWORD dwTempControl = GetAMDSMNRegister(0x59800/*F17H_M01H_REPORTED_TEMP_CTRL_OFFSET*/); if ((dwTempControl & 0x80000) == 0x80000) fltResult = ((dwTempControl>>21) & 0x7FF) / 8.0f - 49.0f; else fltResult = ((dwTempControl>>21) & 0x7FF) / 8.0f; if (strstr(g_szCpuBrandString, "AMD Ryzen 7 2700X")) fltResult = fltResult - 10.0f; if (strstr(g_szCpuBrandString, "AMD Ryzen 7 1800X") || strstr(g_szCpuBrandString, "AMD Ryzen 7 1700X") || strstr(g_szCpuBrandString, "AMD Ryzen 5 1600X")) fltResult = fltResult - 20.0f; if (strstr(g_szCpuBrandString, "AMD Ryzen Threadripper 19") || strstr(g_szCpuBrandString, "AMD Ryzen Threadripper 29")) fltResult = fltResult - 27.0f; } } else { if (g_dwMiscControlDevFn[dwCpu]) { DWORD dwTempControl; DWORD dwCpuFamily = GetCpuFamily(); switch (dwCpuFamily) { case 0x10: case 0x11: case 0x12: case 0x14: case 0x15: case 0x16: dwTempControl = ReadBusDataUlong(0, g_dwMiscControlDevFn[dwCpu], 0xA4); break; } switch (dwCpuFamily) { case 0x10: case 0x11: case 0x12: case 0x14: fltResult = ((dwTempControl>>21) & 0x7FF) / 8.0f; break; case 0x15: if ((dwTempControl & 0x30000) == 0x30000) fltResult = ((dwTempControl>>21) & 0x7FC) / 8.0f - 49.0f; else fltResult = ((dwTempControl>>21) & 0x7FF) / 8.0f; break; case 0x16: if (((dwTempControl & 0x30000) == 0x30000) || ((dwTempControl & 0x80000) == 0x80000)) fltResult = ((dwTempControl>>21) & 0x7FF) / 8.0f - 49.0f; else fltResult = ((dwTempControl>>21) & 0x7FF) / 8.0f; break; } } } } return fltResult; } return FLT_MAX; } ////////////////////////////////////////////////////////////////////// extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { UNREFERENCED_PARAMETER(lpReserved); if (dwReason == DLL_PROCESS_ATTACH) { if (!AfxInitExtensionModule(CPUDLL, hInstance)) return 0; new CDynLinkLibrary(CPUDLL); g_hModule = hInstance; } else if (dwReason == DLL_PROCESS_DETACH) { AfxTermExtensionModule(CPUDLL); } return 1; } ////////////////////////////////////////////////////////////////////// // This exported function is called by MSI Afterburner to get a number of // data sources in this plugin ////////////////////////////////////////////////////////////////////// CPU_API DWORD GetSourcesNum() { if (!g_dwCpuCount) { //load plugin settings g_bEnableLog = GetPrivateProfileInt("Debug" , "EnableLog" , 0, GetCfgPath()); g_dwTjmaxOverride = GetPrivateProfileInt("Settings" , "TjmaxOverride" , 0, GetCfgPath()); //get host application module handle HMODULE hHost = GetModuleHandle(NULL); //get ptrs to required plugin API functions g_pReadBusDataUlong = (READ_BUS_DATA_ULONG_PROC )GetProcAddress(hHost, "ReadBusDataUlong" ); g_pReadBusDataUshort = (READ_BUS_DATA_USHORT_PROC )GetProcAddress(hHost, "ReadBusDataUshort" ); g_pReadBusDataUchar = (READ_BUS_DATA_UCHAR_PROC )GetProcAddress(hHost, "ReadBusDataUchar" ); g_pWriteBusDataUlong = (WRITE_BUS_DATA_ULONG_PROC )GetProcAddress(hHost, "WriteBusDataUlong" ); g_pWriteBusDataUshort = (WRITE_BUS_DATA_USHORT_PROC )GetProcAddress(hHost, "WriteBusDataUshort" ); g_pWriteBusDataUchar = (WRITE_BUS_DATA_UCHAR_PROC )GetProcAddress(hHost, "WriteBusDataUchar" ); g_pReadMSR = (READ_MSR_PROC )GetProcAddress(hHost, "ReadMSR" ); g_pWriteMSR = (WRITE_MSR_PROC )GetProcAddress(hHost, "WriteMSR" ); g_pGetTimestamp = (GET_TIMESTAMP_PROC )GetProcAddress(hHost, "GetTimestamp" ); //init CPU related variables InitCpu(); } if (g_dwCpuCount) //package temeprature + core temepratures return 1 + g_dwCpuCount; return 0; } ////////////////////////////////////////////////////////////////////// // This exported function is called by MSI Afterburner to get descriptor // for the specified data source ////////////////////////////////////////////////////////////////////// CPU_API BOOL GetSourceDesc(DWORD dwIndex, LPMONITORING_SOURCE_DESC pDesc) { if (!g_dwCpuCount) { //load plugin settings g_bEnableLog = GetPrivateProfileInt("Debug" , "EnableLog" , 0, GetCfgPath()); g_dwTjmaxOverride = GetPrivateProfileInt("Settings" , "TjmaxOverride" , 0, GetCfgPath()); //get host application module handle HMODULE hHost = GetModuleHandle(NULL); //get ptrs to required plugin API functions g_pReadBusDataUlong = (READ_BUS_DATA_ULONG_PROC )GetProcAddress(hHost, "ReadBusDataUlong" ); g_pReadBusDataUshort = (READ_BUS_DATA_USHORT_PROC )GetProcAddress(hHost, "ReadBusDataUshort" ); g_pReadBusDataUchar = (READ_BUS_DATA_UCHAR_PROC )GetProcAddress(hHost, "ReadBusDataUchar" ); g_pWriteBusDataUlong = (WRITE_BUS_DATA_ULONG_PROC )GetProcAddress(hHost, "WriteBusDataUlong" ); g_pWriteBusDataUshort = (WRITE_BUS_DATA_USHORT_PROC )GetProcAddress(hHost, "WriteBusDataUshort" ); g_pWriteBusDataUchar = (WRITE_BUS_DATA_UCHAR_PROC )GetProcAddress(hHost, "WriteBusDataUchar" ); g_pReadMSR = (READ_MSR_PROC )GetProcAddress(hHost, "ReadMSR" ); g_pWriteMSR = (WRITE_MSR_PROC )GetProcAddress(hHost, "WriteMSR" ); g_pGetTimestamp = (GET_TIMESTAMP_PROC )GetProcAddress(hHost, "GetTimestamp" ); //init CPU related variables InitCpu(); } if (IsCpuTemperatureReportingSupported(dwIndex - 1)) { if (dwIndex) { sprintf_s(pDesc->szName , sizeof(pDesc->szName) , "CPU%d temperature", dwIndex); sprintf_s(pDesc->szGroup , sizeof(pDesc->szGroup) , "CPU%d", dwIndex); strcpy_s(pDesc->szNameTemplate , sizeof(pDesc->szNameTemplate) , "CPU%d temperature"); strcpy_s(pDesc->szGroupTemplate , sizeof(pDesc->szGroupTemplate), "CPU%d"); } else { strcpy_s(pDesc->szName , sizeof(pDesc->szName) , "CPU temperature"); strcpy_s(pDesc->szGroup , sizeof(pDesc->szGroup) , "CPU"); } strcpy_s(pDesc->szUnits , sizeof(pDesc->szUnits) , "°C"); pDesc->dwID = MONITORING_SOURCE_ID_CPU_TEMPERATURE; pDesc->dwInstance = dwIndex - 1; pDesc->fltMaxLimit = 200.0f; pDesc->fltMinLimit = 0.0f; return TRUE; } return FALSE; } ///////////////////////////////////////////////////////////////////////////// // This exported function is called by MSI Afterburner to poll data sources ///////////////////////////////////////////////////////////////////////////// CPU_API FLOAT GetSourceData(DWORD dwIndex) { return GetCpuTemperature(dwIndex - 1); } ///////////////////////////////////////////////////////////////////////////// // This helper function is used to return fully qualified path to .cfg file ///////////////////////////////////////////////////////////////////////////// CString GetCfgPath() { char szCfgPath[MAX_PATH]; GetModuleFileName(g_hModule, szCfgPath, MAX_PATH); PathRenameExtension(szCfgPath, ".cfg"); return szCfgPath; } ///////////////////////////////////////////////////////////////////////////// // This helper function is used to return fully qualified path to .log file ///////////////////////////////////////////////////////////////////////////// CString GetLogPath() { char szLogPath[MAX_PATH]; GetModuleFileName(g_hModule, szLogPath, MAX_PATH); PathRenameExtension(szLogPath, ".log"); return szLogPath; } ///////////////////////////////////////////////////////////////////////////// // This helper function adds specified line to log file ///////////////////////////////////////////////////////////////////////////// void AppendLog(LPCSTR lpLine, BOOL bAppend) { CString strLogPath = GetLogPath(); CStdioFile logFile; if (bAppend) { if (!logFile.Open(strLogPath, CFile::modeWrite|CFile::shareDenyWrite)) if (!logFile.Open(strLogPath, CFile::modeCreate|CFile::modeWrite|CFile::shareDenyWrite)) return; } else if (!logFile.Open(strLogPath, CFile::modeCreate|CFile::modeWrite|CFile::shareDenyWrite)) return; logFile.SeekToEnd(); SYSTEMTIME sysTime; GetLocalTime(&sysTime); CString strTime; strTime.Format("%.2d-%.2d-%.2d, %.2d:%.2d:%.2d ", sysTime.wDay, sysTime.wMonth, sysTime.wYear, sysTime.wHour, sysTime.wMinute, sysTime.wSecond); logFile.WriteString(strTime); logFile.WriteString(lpLine); logFile.WriteString("\n"); logFile.Close(); logFile.Flush(); } /////////////////////////////////////////////////////////////////////////////