2024年1月4日发(作者:)

Linux下cpu温度读取

pb7210168何彩福

现在的cpu都内置了温度传感器(DTS),并且可以通过寄存器较准确的读取温度值。Intel

cpu温度保存在msr寄存器中,可以通过rdmsr指令读取;AMD cpu保存在NB寄存器中,可以通过pci总线读取。不过intel从Core Duo开始支持DTS,AMD不记得什么时候开始。我只有AMD k8体系的机器,所以我主要谈的是AMD k8 cpu温度读取。

对硬件的封装程度可以分为三个层次,一是直接读取端口,大多是以汇编或内嵌汇编的形式操作,例如对intel cpu 可以用asm{“mov $0xee ,%%ecx n“ ”rdmsr”:”=a”(register):)读取;第二个层次是写驱动,在驱动中读取;第三是操作系统都做好了,我们直接系统调用就可以了。由于AMD cpu是通过0Xcf8和0XCFC读取pci配置空间,我不太会,而且各种参数,AMD寄存器名称等也不了解,ubuntu下也没找到相应的系统调用,虽然有人说温度保存在/proc/acpi/thermal_zone/THRM/temperature中,不过我系统里没找到。所幸linux是开源的,我们很容易得到温度驱动的源代码,intel 是coretemp.c,AMD是k8temp.c和k10temp.c,都在driver/hwmon/下。

linux支持模块机制,我们可以自己写驱动模块并动态的添加到内核里,我做的工作就是修改了k8temp. c驱动,在编译成模块添加到内核里。

k8temp.c主要有两部分,一是通过pci读取温度值,一是通过sysfs系统输出温度,虽然sysfs比proc更好,但是我对sysfs不了解,而且网上proc的资料更好找一些,所以我把驱动里sysfs相关的代码全删除了,换成proc。模块运行后在/proc下可以看到cpu_temp(名字可以自己取)这个新文件,其它程序可以读取这个文件来得到温度值。

下面是具体工作:

一、修改k8temp.c:

1、 删除代码里sysfs相关的代码:

代码里的show_name,show_temp函数,以及相关的宏调用,删除k8temp_probe函数中sysfs creat和remove的相关代码,删除k8temp_remove中sysfs remove的相关代码。

2、 添加proc代码:

添加proc_read函数

ssize_t our_read(struct file *file, char *buf, size_t size, loff_t *ppos)

{

int f2,i;

const struct pci_device_id *id;

if(*ppos>500)

return 0;

pdev1=pci_get_device

(PCI_VENDOR_ID_AMD,PCI_DEVICE_ID_AMD_K8_NB_MISC,NULL);

if(pdev1)

{

f2=k8temp_(pdev1,id);

printk("init pic here %dn",f2);

if(f2!=0)

{

sprintf(msg,"%sn","pci init failed");

}

pci_dev_put(pdev1);

k8temp_(pdev1);

}

else

sprintf(msg,"%sn","pci open failed");

if(*ppos>500)

return 0;

for (i=0;i

{

put_user(msg[i],buf+i);

*ppos=*ppos+1;

}

return i;

}

添加proc数据结构

struct file_operations fops={

read:our_read,

};

在init函数里添加创建代码

my_proc_ptr=create_proc_entry("cpu_temp",S_IRUSR|S_IWUSR,NULL);

if(my_proc_ptr)

{

my_proc_ptr->proc_fops=&fops;

printk("init k8temp heren");

}

在cleanup函数中添加移除代码

remove_proc_entry("cpu_temp",NULL);

二、编译

下面是Makefile正文,很经典:

ifneq ($(KERNELRELEASE),)

obj-m:=k8temp.o

else

KDIR:=/lib/modules/$(SHELL uname –r)/build

PWD:=$(shell pwd)

default:

$(MAKE) –C $(KDIR) M=$(PWD) modules

endif

注意:ifneq后有空格,default下的命令不能以空格代替tab键,否则编译出错(至少我是这样)。

代码的执行过程是这样的:

由于KERNELREASE是在内核源码顶层Makefile中定义的,所以先执行else下的代

码,-C $(KDIR)指明跳转到内核源码目录下读取那里的Makefile,$(PWD)指返回当前目录读取执行当前的Makefile,由于此时KERNELREASE已经被定义了,所以执行obi-m:=k8temp.o。obj-m:=xxx.o是指用xxx.c生成xxx.o模块。

三、添加模块

生成模块后就是添加模块了,使用sudo insmod ./,必须要有sudo否则出错,另外./是指模块已在当前目录下。这时你可以用demsg|tail查看模块中printk输出的信息,并且在/proc下可以看到新建的文件cpu_temp。

四、测试程序

测试程序只是打开文件,读取模块中产生的温度值。编译后运行可以得到结果,运行时也要sudo提权。