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提权。


发布评论