获取传感器温度-cpu 温度篇

  最近搞cpu 内核温度,总算是有点成就了。需要参考的文献有:

PCI Local Bus Specification

AMD相关:

BIOS and Kernel Developer's Guide for AMD Athlon 64 and AMD Opteron Processors

BIOS and Kernel Dveloper's Guide (BKDG) For AMD Family 10h Processor

BIOS and Kernel Dveloper's Guide ( For AMD NPT Family 0Fh Processor

AMD CPUID Specification

...

Intel相关:

Intel A3

...

 

Core Temp软件相关说明:

 

Intel and AMD recently published detailed, public information about the "DTS" (Digital Thermal Sensor), which provides much higher accuracy and more relevant temperature reading than the standard thermal diode sensors do

Core Temp lets you monitor Intel "Core Duo", "Core Solo" (Yonah), "Core 2 Duo", "Core 2 Extreme", "Core 2 Quad", " Pentium E2000" series, "Celeron 400/500" series (Allendale, Conroe, Merom, Kentsfield, Conroe-L respectively), "Xeon 3000/3200/5100/5300" series (Woodcrest, Clovertown respectively) and all AMD K8 (AMD64) and K10 (Phenom, Opteron) series die temperature.
The temperature readings are very accurate as the data is collected from a Digital Thermal Sensor (or DTS) which is located in each individual processing core, near the hottest part. This sensor is digital, which means it doesn't rely on an external circuit located on the motherboard to report temperature, its value is stored in a special register in the processor so any software can access and read it. This eliminates any inaccuracy that can be caused by external motherboard circuits and sensors and then different types of programs trying to read those sensors.

 

This is how the program works:

Intel defines a certain Tjunction temperature for the processor. In the case of Yonah it is 85C° or 100C°. First of all the program reads from a Model Specific Register (or MSR), and detects the Tjunction temperature. A different MSR contains the temperature data, this data is represented as Delta in C° between current temperature and Tjunction.

So the actual temperature is calculated like this 'Core Temp = Tjunction - Delta'

The size of the data field is 7 bits. This means a Delta of 0 - 127C° can be reported in theory. But from preliminary tests, the reported temperature doesn't go below 0C°, no matter what kind of cooling was used.


AMD chips report the temperature by a special register in the CPU's NB. Core Temp reads that register and uses a formula provided by AMD to calculate the current temperature.
The formula for the K8 is: 'Core Temp = Value - 49'.
The formula for the K10* is: 'CPU Temp** = Value / 8'.

The sensor in AMD CPUs can report temperatures between -49C and 206C.

*K10 = Phenom (Agena), Opteron (Barcelona). The K10 reports a temperature value that is relative to a certain predefined value, it doesn't report the actual processor temperature! So take that into consideration.
**CPU Temp is because the Phenom/Opteron (K10) have only one sensor per package, meaning there is only one reading per processor.

 

      刚接手这个的时候,可以说是一头雾水,完全不知道该怎么搞。首先接触到的就是hwmonitor和core temp 这两款软件,同时看到上面core temp 的说明,可以说知道一点东西了。可以它其中说的amd是在nb的特殊寄存器中,这个到底是什么寄存器了。当时没有去看amd的一些文档,就直接看是逆向hwmonitor和core temp软件,通过动态和静态分析了这两个软件的驱动和应用程序,只能说知道其中他们是在不断的进行端口读写分别是0XCF8和0xCFC这两个端口。你可以上网查找这两个端口是干什么的,之前由于我左右pci 配置空间读取问题,所以对这个两个端口不是很陌生。pci 配置空间相关说明就要看pci 规范了,说的很详细。

   之后,看是学习cpu 手册了,因为我的机器是amd的,所以就先或许amd的温度吧。看了很多,刚开始还不知道什么事,慢慢的,就知道其中有一个thermal status register,这个寄存器中保存了当前核心温度。这个寄存器就是core temp所说的nb中的特殊寄存器。那么这个寄存器是如何读取的呢,看来了amd bios and kernel ‘guid 。。。中我们知道这个基础器是Fn3 E4.其中会说的pci配置空间。Fn3 是指读取pci配置空间时要用的到fun 3,而E4就是对应于这个fun 3的偏移为E4。读取这个32bit数据。然后我们就可以解析获取原始的当前温度了。

     由于amd对这个寄存器有过修改,因而在解析的时候我们需要知道这是那种型号的。我们看到core temp是能获取k8和k10 的amd内核温度计算公式。那么是什么是k8什么是k10呢。

      使用cpuid (eax = 0x1)得到的eax中的family,model,和stepping进行判断。

      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] = 0Fh and ExtendedFamily[7:0] = 01h, then Family[7:0] = 10h. If BaseFamily[3:0] is less than 0Fh then ExtendedFamily[7:0] is reserved and Family is equal to BaseFamily[3:0].
      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] = 0Eh and BaseModel[3:0] = 08h, 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].

 

      如果family > 0xF,那么就是k10.

      而对于k8的是怎么判断的呢,family 为0xF,而除了

        /* feature available since SH-C0, exclude older revisions */
               (((model == 4) && (stepping == 0)) ||
                    ((model == 5) && (stepping <= 1)))

 

     这些类型的cpu都可以算是k8的。

     如何读pci,应该也清楚了,就是通过0xcf8和0xcfc进行读取,但是需要busno,devno,funno和reg,这样才能读取到指定的数据。但是我们并不知道busno和devno啊。而funno就是0x3,而reg就是E4或A4.

    首先我们根据cpu类型获取到时k8还是k10.这两种类型的cpu对应的deviceid是不同。k8 为0x1103而k10为1203.通过这两个数据以及baseclass,就可以在遍历过程中得到busno和devno了。后面就是对数据进行解析了。哦。。。还有一点就是在看了bios and kernel书之后,按照它的方式我们发现需要有个diodeoffset来进行校正。而temp(23-14bit)/(23-16bit),diodeOffset的值也是不同的。不管哪种,得到的数据总是有点问题。郁闷了。你想core temp算法确实是按照上面的方式进行的。currtemp =rawtemp/4 - 49 + basetemp;后来,偶然机会发现在linux的内核中有一个k8temp.c这个东西,这个就是获取k8的温度。认真的学习了代码。发现可以正确的获取内核温度。他的方法并不是上面先除4在减49的。而是用上面coretemp说明中的value -49进行的。这个value就是读取的(23-16bit)数据,这个让我有点奇怪,amd温度中说了,currenttemp添加为(23-14bit)。真是搞不清楚。

    既然可以通过linux的k8temp.c中的方法获取到,那就这样吧。现在这个k8temp.c已经支持k10了。所以完全可以借用了。有一点需要说的就是,k8temp.c中不断的写端口,以获取其他sensor和core的温度(因为amd有每个core都有2个sensor),但是这个寄存器总是不能写成功。那如何获取其他的core温度呢。这就要使用windows api了。可以通过GetProcessAffinityMask和SetProcessAffinityMask进行。不断改变当前进程所在的核心,来获取不同核的温度。

 

   新的酷瑞CPU和AMD的CPU 内部都集成有温度传感器DTS (Digital Thermal Sensor),每个核心有一个,以前的移动CPU好像也支持温度探测,但手头没有这样的CPU没法做测试.AMD 的温度值保存在 NB 寄存器中,酷瑞CPU 的 DTS 值保存在 MSR 0x19c 中,可以通过 rdmsr 来读取

       这里只说酷睿CPU的读取过程

       Intel 定义 eax=6 执行 cpuid,  然后测试 eax 第一位是否为1,如果为1表示CPU支持DTS ,当然之前应该以 eax=0 执行 cpuid 检测 eax 支持的最大命令数,如果小于6就肯定不支持DTS。

       读取DTS:1 以 ecx=0xee 执行 rdmsr 指令, 测试 eax 的第30位是否为 1, 如果为 1 表示温度计算的初始值为 85 度否则表示从100度开始计算,这个值称为 Tjunction. 然后以 ecx=0x19c 执行 rdmsr 指令,  eax 的 16:23 位为表示当前DTS 值,这个值并不代表当前温度,而要以下面公式计算.

       当前cpu温度 = Tjunction - DTS

       注意  signature 为 0x6f1, 0x6f0的 CPU DTS 值直接代表当前温度而不用Tjunction 相减. 而 signature 小于等于 0x6f4 的 Tjunction 一直为100, 如果你是双核的cpu 可以使用 SetProcessAffinityMask API 来指定执行的CPU,以检测这个核心的温度。Signature是通过读取MSR_IA32_BIOS_SIGN_ID得到的。

 

      要获取这些驱动通过驱动才能读取。可以参看winio驱动代码。在我的下载资源中提供winio代码。

 

 

 

    我想应该说的很明白了。

 

      

 

   

 

 

 

 

你可能感兴趣的:(获取传感器温度-cpu 温度篇)