#include <float.h>
#include <stdio.h>
#include <windows.h>
#include "C2DTemp.h"
#include "RivaTunerExports.h"
#include "MonitoringSourceDesc.h"
HINSTANCE g_hModule = NULL;
HMODULE g_hHost = NULL;
READ_MSR_PROC g_pReadMSR = NULL;
DWORD g_dwCPU = 0;
BOOL g_bHasDTS = FALSE;
FLOAT g_fTjmax = 100.0f;
const char * const szDim = "°C";
const char * const szDesc = "CPU temperature as reported by on-die Digital Thermal Sensor";
const char * const szGroup = "CPU";
BOOL DetectCPUFeatures(void)
{
const char ven_intel[12] = {'G','e','n','u','i','n','e','I','n','t','e','l'};
char vendor[12];
DWORD last_fn = 0, fn6_eax = 0;
memset(vendor, 0, 12);
// try to execute CPUID instruction
__try {
__asm {
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
cpuid
mov dword ptr [last_fn], eax
mov dword ptr [vendor], ebx
mov dword ptr [vendor + 4], edx
mov dword ptr [vendor + 8], ecx
}
}
__except (GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION) {
return FALSE;
}
// Is it GenuineIntel CPU?
if (strncmp(vendor, ven_intel, 12) != 0) {
return FALSE;
}
// Does it support Digital Thermal Sensor and Power Management CPUID leaf?
if (last_fn < 6) {
return FALSE;
}
__asm {
mov eax, 6
cpuid
mov dword ptr [fn6_eax], eax
}
// Is Digital Thermal Sensor feature supported?
if ((fn6_eax & 0x1) == 0) {
return FALSE;
}
return TRUE;
}
BOOL
WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH) {
g_hModule = hInstance;
g_bHasDTS = DetectCPUFeatures();
}
return TRUE;
}
C2DTEMP_API DWORD GetSourcesNum(void)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
g_dwCPU = si.dwNumberOfProcessors;
return g_dwCPU;
}
C2DTEMP_API BOOL GetSourceDesc(DWORD dwIndex, LPMONITORING_SOURCE_DESC pDesc)
{
DWORD hi, lo;
if (g_pReadMSR == NULL) {
g_hHost = GetModuleHandle(NULL);
if (g_hHost == NULL) {
return FALSE;
}
g_pReadMSR = (READ_MSR_PROC)GetProcAddress(g_hHost, "ReadMSR");
if (g_pReadMSR == NULL) {
return FALSE;
}
if (!g_bHasDTS) {
return FALSE;
} else {
// Try to detect Tjunction
if (!g_pReadMSR(0xEE, &hi, &lo)) {
return FALSE;
}
if (lo & 0x40000000) {
g_fTjmax = 85.0f;
}
}
}
sprintf(pDesc->szName, "CPU%ld temperature", dwIndex);
strcpy(pDesc->szDim , szDim);
strcpy(pDesc->szDesc , szDesc);
if (pDesc->dwVersion >= 0x00010002) {
strcpy(pDesc->szGroup, szGroup);
}
pDesc->fltMaxLimit = 100.0f;
pDesc->fltMinLimit = 0.0f;
pDesc->fltGridDim = 10.0f;
return TRUE;
}
C2DTEMP_API FLOAT GetSourceData(DWORD dwIndex)
{
static FLOAT val[32] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX
};
DWORD_PTR dwMask, dwProcessAffinityMask, dwSystemAffinityMask;
DWORD hi, lo;
// Is DTS supported by this CPU?
if (!g_bHasDTS) {
return FLT_MAX;
}
// NOTE: This should be done by RivaTuner before calling plugins
// Will be removed when Alexey implements it internally
// Get current process and system affinity mask
if (!GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask)) {
return FLT_MAX;
}
// Temporarily enable execution on all the CPUs in the system
if (!SetProcessAffinityMask(GetCurrentProcess(), dwSystemAffinityMask)) {
return FLT_MAX;
}
dwMask = 1 << dwIndex;
// Move the thread to the proper core
if (!SetThreadAffinityMask(GetCurrentThread(), dwMask)) {
return FLT_MAX;
}
// Read IA32_THERM_STATUS MSR
if (!g_pReadMSR(0x19C, &hi, &lo)) {
return FLT_MAX;
}
// Is reading valid?
// If not, just return previous value
if ((lo & 0x80000000) == 0) {
return val[dwIndex];
}
val[dwIndex] = g_fTjmax - (FLOAT)((lo >> 16) & 0x7F);
return val[dwIndex];
}