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

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

Intel从Core Duo处理器开始,每一个物理核心都有一个温度传感器(DTS-Digital Thermal Sensor)用来获取核心温度,这是Intel推荐的获取温度的方法,因为DTS处在每个物理核心温度最高的位置。这个传感器的温度值是通过MSR寄存器来获得的。MSR的相关信息可以参考Intel 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在获取其它硬件信息时还是很方便的。

以上的方法适用与Windows。 Linux下不需要所谓ring0,因为在linux下我们有root,我们怕谁。

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


你可能感兴趣的:(杂谈,cpu,传感器,硬件,c)