linux 如何读取的cpu 温度? (真实平台)


author: hjjdebug

date: 2026年 05月 28日 星期四 11:36:20 CST

descrip: linux 如何读取的cpu 温度? (真实平台)


文章目录

  • [1. 读取温度.](#1. 读取温度.)
    • [1.1 读取测试点参考温度](#1.1 读取测试点参考温度)
    • [1.2 读取测试点温差温度](#1.2 读取测试点温差温度)
    • [1.3 计算实际温度.](#1.3 计算实际温度.)
  • [2. 注册一个热区 :](#2. 注册一个热区 :)
  • [3. 测试](#3. 测试)
  • [4. 驱动源码 (82行)](#4. 驱动源码 (82行))

前面曾经写过一个虚拟平台读取cpu 温度, 只要完善读取温度函数,从
真实机器上读取温度, 那就是真正的cpu温度.
完整驱动代码见后面附录
关键点梳理:

1. 读取温度.

通过读取某个特定寄存器来读取到温度.

具体过程稍微复杂一点. 先读取一个参考值, 再读取到参考值的差值计算出温度.

1.1 读取测试点参考温度

#define MSR_IA32_TEMPERATURE_TARGET 0x1A2

MSR : model specified register, 模型特定寄存器

IA32_TEMPERATURE_TARGET:Intel 统一命名,地址固定 0x1A2

作用: 该地址保存了 CPU 出厂烧录的温度阈值,或者说温度参考值, 或者说最大温度值. 一般是100或105

所有测量的温度是以该值为参考的.

特定的寄存器, 只能用特定的指令来读取.

rdmsrl(MSR_IA32_TEMPERATURE_TARGET, msr_target);

读取参考值到msr_target, 计算出最大温度tj_max

tj 就是test junction, 测试结点的意思

1.2 读取测试点温差温度

#define MSR_IA32_PACKAGE_THERM_STATUS 0x1B1

rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_status);

读取cpu 温度温度到 msr_status.

读取的数值并不直接代表温度值, 而是到参考值的差值.

1.3 计算实际温度.

所以温度是tj_max-tj_offset, 看看代码就一目了然.

这个地址0x1b1 决定了读取的是哪里的温度值.

2. 注册一个热区 :

怎样执行到我们的驱动代码? 需要在内核上开一个窗口.

这需要注册一个热区.

intel_cpu_tz = thermal_zone_device_register(

"intel_cpu_real", //类型名称,自定义

0,

0,

NULL,

&intel_tz_ops, //操作函数

&intel_tz_params, //操作函数参数

0,

2000 //polling_delay,查询间隔

);

该函数会在内核上开一个窗口,使用户通过窗口访问到内部驱动.

这个窗口就是/sysfs 文件. 具体为:

/sys/devices/virtual/thermal/thernal_zoneX

首先, 它是开在/devices/virtual 总线下, 因为它不具体对应设备,所以在virtual 线下就很合适.

第2,它属于热区,故下级目录为thermal, 这两层目录是接口函数决定的.

thermal_zoneX, 其中这个X 是代表的是zone编号. 由系统根据当前的zone个数来确定.

函数中的参数意义也已经注明.

如果我不这样开口子,而是注册一个cdev, 在/dev/创建一个字符设备, 也是可以的.

不过内核为热区专门提供了函数接口thermal_zone_device_register 函数, 用它就更方便了.

这样也了解到了其它thermal_zone 是怎么来的.

3. 测试

$ insmod intel_minimal_temp.ko

$ lsmod

$ dmesg

15031.287916 ✅ 本机CPU真实TJ Max临界温度 = 105 °C

15031.287995 ✅ 精准Intel CPU测温驱动加载完成

15031.287997 👉 读取温度命令: cat /sys/class/thermal/thermal_zoneX/temp

insmod 后,我们发现在/sys/class/thermal/下多出了thermal_zone4, 那就进入到该目录

hjj@hjj-laptop:/sys/devices/virtual/thermal/thermal_zone4$ cat temp

51000

还发现,我们新添的这个zone4 跟 zone3 的数值是一致的,

这说明,我们的驱动是正确的, 而且它就等价于系统zone3.

至此,消除了cpu温度测量的神秘性. 就是读一个MSR 来实现的. 而展现它,用thermal_zone来展示.

我们也能写完整的驱动.

附件代码给出了完整实现.

4. 驱动源码 (82行)

cpp 复制代码
$ cat intel_minimal_temp.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/thermal.h>
#include <asm/msr.h>

// Intel 官方温度寄存器定义
//#define MSR_IA32_PACKAGE_THERM_STATUS  0x1B1
//#define MSR_IA32_TEMPERATURE_TARGET    0x1A2

static int tj_max = 100; // 全局存储本机真实临界温度

static int intel_real_get_temp(struct thermal_zone_device *tz, int *temp)
{
    u64 msr_status;
    int tj_offset;

    // 读取CPU当前热状态
    rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_status);
    // 提取距离过热临界点的剩余度数
    tj_offset = (msr_status >> 16) & 0xFF;

    // 用CPU原生真实TJ_MAX精准计算毫摄氏度
    *temp = (tj_max - tj_offset) * 1000;

    return 0;
}

static struct thermal_zone_device_ops intel_tz_ops = {
    .get_temp = intel_real_get_temp,  //实现查看温度函数
};

static struct thermal_zone_params intel_tz_params = {
    .no_hwmon = true,
};

static struct thermal_zone_device *intel_cpu_tz;

static int __init intel_temp_init(void)
{
    u64 msr_target;

    // 第一步:自动读取CPU出厂自带的真实TJ Max临界温度
    rdmsrl(MSR_IA32_TEMPERATURE_TARGET, msr_target);
    tj_max = (msr_target >> 16) & 0xFF;

    pr_info("✅ 本机CPU真实TJ Max临界温度 = %d °C\n", tj_max);

    // 严格适配 Linux 5.4 内核 完整8参数原型,注册一个热区
    intel_cpu_tz = thermal_zone_device_register(
        "intel_cpu_real",
        0,
        0,
        NULL,
        &intel_tz_ops,
        &intel_tz_params,
        0,
        2000           //polling_delay
    );

    if (IS_ERR(intel_cpu_tz)) {
        pr_err("❌ 温控域注册失败\n");
        return PTR_ERR(intel_cpu_tz);
    }

    pr_info("✅ 精准Intel CPU测温驱动加载完成\n");
    pr_info("👉 读取温度命令: cat /sys/class/thermal/thermal_zoneX/temp\n");

    return 0;
}

static void __exit intel_temp_exit(void)
{
    thermal_zone_device_unregister(intel_cpu_tz);
    pr_info("✅ 驱动已安全卸载\n");
}

module_init(intel_temp_init);
module_exit(intel_temp_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("自动TJ Max 100%对齐官方驱动版");
相关推荐
A小辣椒7 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒11 小时前
TShark:基础知识
linux
AlfredZhao13 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334661 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪1 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言