2016年8月17日星期三

获取Intel CPU的温度

#include <ntifs.h>
#include <windef.h>
#include <ntddk.h>
#include <ntstrsafe.h>

#include <intrin.h> //VS2012编译。
#include <immintrin.h>//VS2012编译。
//#include <mmintrin.h> //WDK 编译。
//#include <emmintrin.h>//WDK 编译。
//#include <xmmintrin.h>//WDK 编译。

#pragma warning(disable:4100)

/*
CPUID.06H:EAX[bit0]

19CH 412   IA32_THERM_STATUS Core Thermal Monitor Status (R/W) See Table 35-2.

1A2H 418   MSR_TEMPERATURE_TARGET Package
15:0  Reserved.
23:16 Temperature Target (R)
The default thermal throttling or PROCHOT# activation temperature in degree C,
The effective temperature for thermal throttling or PROCHOT# activation is “Temperature Target” +“Target Offset”
29:24 Target Offset (R/W)
Specifies an offset in degrees C to adjust the throttling and PROCHOT# activation temperature from the default target specified in TEMPERATURE_TARGET (bits 23:16).
*/


#define IA32_THERM_STATUS         0x19C
#define MSR_TEMPERATURE_TARGET    0x1A2


BOOL is_support_intel()
{
    BOOL B = FALSE;
    char CPUString[0x20];
    int CPUInfo[4] = { -1 };
    unsigned    nIds;

    // __cpuid with an InfoType argument of 0 returns the number of valid Ids in CPUInfo[0] and the CPU identification string in the other three array elements.
    // The CPU identification string is not in linear order.
    // The code below arranges the information in a human readable form.
    __cpuid(CPUInfo, 0);
    nIds = CPUInfo[0];
    memset(CPUString, 0, sizeof(CPUString));
    *((int*) CPUString) = CPUInfo[1];
    *((int*) (CPUString + 4)) = CPUInfo[3];
    *((int*) (CPUString + 8)) = CPUInfo[2];

    //printf_s("\n\nCPU String: %s\n", CPUString);//GenuineIntel
    if (_stricmp(CPUString, "GenuineIntel") == 0)
    {
        B = TRUE;
    }

    return B;
}


BOOL is_support_cpuid()
/*
判断CPU是否支持CPUID指令。
*/
{
    BOOL B = FALSE;
    SIZE_T eflags1;
    SIZE_T eflags2;

    eflags1 = __readeflags();
    __writeeflags(eflags1 | 0x200000);
    eflags2 = __readeflags();
    __writeeflags(eflags1);
    if (eflags1 == eflags2) {
        B = FALSE;
    }
    else {
        B = TRUE;
    }

    return B;
}


//DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


//DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    unsigned __int64 tt = 0;
    unsigned __int64 ts = 0;
    int x = 0;
    int to = 0;
    int i = 0;
    int CPUInfo[4] = { -1 };
    unsigned int t = 0;

    //KdBreakPoint();
    //__debugbreak();

    DriverObject->DriverUnload = Unload;

    //识别是否支持CPUID指令。
    if (!is_support_cpuid())
    {
        return 0;
    }
 
    //识别是不是Intel处理器。
    if (!is_support_intel())
    {
        return 0;
    }

    //识别是否支持查询CPU的温度。
    __cpuid(CPUInfo, 6);
    t = CPUInfo[0];
    //CPUID.06H:EAX[bit0] == 1
    //可是下面的两个值获取的都为零。

    tt = __readmsr(MSR_TEMPERATURE_TARGET);//如果这个数字为0,可以认为是在虚拟机中,有的软件叫:耐热,可能是极限。
    ts = __readmsr(IA32_THERM_STATUS);

    //KdPrint(("MSR_TEMPERATURE_TARGET:0x%x.\r\n", tt));
    //KdPrint(("IA32_THERM_STATUS:0x%x.\r\n", ts));

    x = tt & (0xFF0000);//23:16 Temperature Target (R)
    to = ts & (0x7F0000);//22:16 Digital Readout (RO)

    i = x - to;
    i = i / 0x10000;

    KdPrint(("TEMPERATURE:%d.\r\n", i));
    //这个数字和别的软件有1-2度的差别。
    //不过Core-Temp和hwmonitor也是相差1-2度。

    return status;
}

/*
注意:测试环境最好不要用虚拟机,用真实的物理机器。
如是64位Windows,可以开启WINDBG的本机内核调试:
lkd> rdmsr 0x19C; rdmsr 0x1A2
msr[19c] = 00000000`88470000
msr[1a2] = 00000000`00691400
再计算。

注意:每个核心有个温度,不是每个CPU线程有个温度。

具体的做法有:
1.创建个设备,提供个借口供应用层用。
2.开启个定时器,在内核不停的打印消息。


made by correy
made at 2016.05.12
homepage:http://correy.webs.com
*/

没有评论:

发表评论