用C/C++获取CPU温度总结(一)

最近在研究怎样获取CPU的温度,网上也有一些办法,但都不算完整,没有清晰的解决方案,现在把我的方法完整的说一下,其实是很简单的东西,没有什么很复杂的。有些地方班门弄斧,各位大侠多多担待。因为我用的是Intel的CPU,所以只做了Intel的,APU的没办法测试,感兴趣的可以研究。

Intel从Core Duo处理器开始,每一个物理核心都有一个温度传感器(DTS-Digital Thermal Sensor)用来获取核心温度,这是Intel推荐的获取温度的方法,因为DTS处在每个物理核心温度最高的位置。这个传感器的温度值是通过MSR寄存器来获得的。MSR是什么大家都知道吧,具体可以参考Developer’s manual第3卷第35章。在我的下载里面有Intel的manual。

通过DTS获取温度并不是直接得到CPU的实际温度,而是两个温度的差。第一个叫做Tjmax,这个Intel叫TCC activation temperature,意思是当CPU温度达到或超过这个值时,就会触发相关的温度控制电路,系统此时会采取必要的动作来降低CPU的温度,或者直接重启或关机。所以CPU的温度永远不会超过这个值。这个值一般是100℃或85℃(也有其他值),对于具体的处理器来说就是一个固定的值。第二个就是DTS获取的CPU温度相对Tjmax的偏移值,暂且叫Toffset,那CPU的实际温度就是:currentTemp=Tjmax – Toffset。

这两个温度值都是通过MSR来获得,获得MSR寄存器中的值用汇编指令rdmsr,Tjmax值相关的MSR的Signature是1A2H,执行

mov ecx, 0x1A2

rdmsr

后,eax中16~23位就是Tjmax的值。

同理,Toffset值相关的MSR的Signature是19CH,执行

mov ecx, 0x19C

rdmsr

后,eax中16~22(注意这里是7位)位就是Toffset的值。

问题在于,rdmsr指令需要ring0权限,而Windows下应用程序的权限都是ring3,所以如果在C中直接build-in汇编执行,程序立即停止工作。

于是我在网上猛搜怎样获取CPU的ring0权限,可惜没有找到相关的代码。这时我参考了Open Hardware Monitor这个软件,Open Hardware Monitor是用C sharp写的,可以检测各个硬件的温度和频率等,可惜我看不懂C#代码。但在里面找到了WinRing0.sys,WinRing0也是开源的,看到它的实现之后顿时大吃一惊,里面直接提供rdmsr指令的C函数,已经帮你绕过了Windows的重重城墙,当时下巴就掉下来了。

所以直接调用Rdmsr()函数就可以了,没有其它。当然要具体了解Winring0是怎样获得ring0权限的,可以直接看它的代码。

在执行MSR读取时,要先用CPUID判断处理器是否支持DTS,最近的处理器都是支持的。具体是CPUID.06H:EAX[bit0]是否被置位。置1时就是可以的。

另外,我的是处理器是4核,每个物理核心都应该对应一个温度,可我只获得了一个。跟Open Hardware Monitor对比之后,这个值总是4个核心中最小的那个,怎样获得4个核心加一个package的温度,还需要再研究。无聊还跟鲁大娘对比了一下,大娘不太靠谱,在我的处理器上低了大概10度。CPU负载突然变大时,温度会瞬间提高,大娘基本没反应。

网上还有另处一种方法我觉得是可行的,是读PMU值,端口号是68H和6CH,同样是绕过Windows来获得ring0权限,用的是WinI/O,不过我没有试。

还有一种方法说是用WMI,CSDN里面也有相关内容,但这个是哄人的,光一个架子,得不到数据。原因是WMI是通过SMBios来读DMI信息的,,微软在做WMI时可能参考了SMBios协议,认为硬件厂商会往DMI里面写信息,但“幼稚”的微软并没有想到“任性”的硬件厂商并没有这么做。。。所有传感器数据都是null。但WMI在获取硬件其它信息时还是很方便的。

提到的相关的Open Hardware Monitor,Winring0,WinI/O,都在我的下载里面。最后提供一张Console里面程序的运行画面。

缘是浪漫的相遇,瞬间让你我的心化为永恒!

用C/C++获取CPU温度总结(一)

相关文章:

你感兴趣的文章:

标签云: