楼主: A1111ML
35 0

[作业] 分析Linux sys 文件目录系统起始 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

80%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
30 点
帖子
2
精华
0
在线时间
0 小时
注册时间
2018-12-4
最后登录
2018-12-4

楼主
A1111ML 发表于 2025-11-22 10:54:51 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

第一部分:ARM64系统启动与设备树初始化

树根:ARM64硬件启动流程

在ARM64架构中,系统的启动过程遵循一系列有序的引导阶段:

BootROM → ATF (ARM Trusted Firmware) → U-Boot → Linux内核

第一层:内核入口点(ARM64架构特定)

机制功能:负责处理ARM64平台的内核启动初始流程,包括异常向量设置、内存管理单元初始化以及跳转至C语言环境。

关键数据结构大小:

  • struct proc_info_list
    (64字节)——处理器信息结构
  • struct machine_desc
    (128字节)——机器描述符结构

核心源码分析(位于 head.S):

ENTRY(stext)
    // 1. 配置异常向量表
    adr_l   x8, vectors
    msr     vbar_el1, x8

    // 2. 初始化MMU(内存管理单元)
    bl      __cpu_setup
    bl      __enable_mmu

    // 3. 清零BSS段以确保全局变量初始状态
    adr_l   x0, __bss_start
    adr_l   x1, __bss_stop
    sub     x1, x1, x0
    bl      __memzero

    // 4. 跳转至start_kernel函数,进入C代码主流程
    b       start_kernel
ENDPROC(stext)

第二层:设备树解析与sysfs映射

机制功能:在内核早期阶段解析Flattened Device Tree(FDT),并构建对应的/sys/firmware/devicetree虚拟文件系统结构,供后续驱动和用户空间使用。

相关数据结构大小:

  • struct device_node
    (200字节)——设备节点结构体
  • struct property
    (100字节)——属性结构体

关键函数实现:

// 文件路径:drivers/of/fdt.c
void __init early_init_dt_scan_nodes(void) {
    // 扫描设备树中的内存节点
    of_scan_flat_dt(early_init_dt_scan_memory, NULL);
    // 解析chosen节点以获取启动参数
    of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
    // 获取根节点信息(如#address-cells等)
    of_scan_flat_dt(early_init_dt_scan_root, NULL);
}
// 文件路径:drivers/of/base.c
int of_populate_sysfs(void) {
    struct device_node *np;

    // 遍历所有已解析的设备树节点
    for_each_of_allnodes(np) {
        // 在sysfs中创建对应目录
        of_node_create_sysfs(np);
        // 为每个属性生成可读文件
        of_node_create_attributes(np);
    }
    return 0;
}

/sys/firmware/devicetree/base 目录结构示例:

/sys/firmware/devicetree/base/
│
├── #address-cells        [属性文件]
├── #size-cells           [属性文件]
├── compatible            [属性文件]
├── model                 [属性文件]
├── cpus/                 [子目录]
│   ├── cpu@0/
│   │   ├── compatible
│   │   ├── device_type
│   │   └── reg
│   └── cpu@1/
│
├── memory@80000000/      [内存节点目录]
│   ├── device_type
│   └── reg
│
└── chosen/               [启动配置目录]
    ├── bootargs
    └── stdout-path

第三层:CPU拓扑结构初始化与sysfs暴露

机制功能:根据设备树中描述的CPU拓扑关系,在ARM64平台上初始化逻辑CPU组织结构,并将其导出到/sys/devices/system/cpu目录下,支持热插拔与调度策略配置。

涉及的数据结构大小:

  • struct cpu_topology
    (100字节)——通用CPU拓扑信息
  • struct cputopo_arm64
    (200字节)——ARM64平台专用拓扑扩展

关键初始化流程(topology.c):

// 文件路径:arch/arm64/kernel/topology.c
void __init init_cpu_topology(void) {
    // 从设备树中提取CPU层级结构(如cluster/core ID)
    parse_dt_topology();

    // 构建用于调度器的CPU域结构
    setup_cpu_domains();
}

该过程完成后,会在用户空间形成如下路径结构:

/sys/devices/system/cpu/
├── cpu0/
├── cpu1/
├── topology/
├── kernel_max
└── possible
set_sched_topology(arm64_topology);
cpu_topology_sysfs_init();

CPU sysfs属性的创建过程

在系统初始化过程中,通过调用register_cpu函数将每个CPU设备注册到内核设备模型中。该函数位于drivers/base/cpu.c,主要负责在/sys/devices/system/cpu/路径下创建对应的设备条目,并为其挂载一系列属性文件组。

int register_cpu(struct cpu *cpu, int num) {
    struct device *dev = &cpu->dev;
    int ret;

    dev->id = num;
    dev->bus = &cpu_subsys;

    ret = device_register(dev);
    if (ret)
        return ret;

    cpu_common_attr_groups[0] = &cpu_root_attr_group;
    ret = sysfs_create_groups(&dev->kobj, cpu_common_attr_groups);

    return ret;
}

ARM64平台下的/sys/devices/system/cpu/目录结构

该目录反映了系统中所有CPU的组织结构和运行时状态信息,具体层级如下:

/sys/devices/system/cpu/
|
+---> cpu0/
|     +---> topology/
|     |     +---> physical_package_id
|     |     +---> core_id
|     |     +---> core_siblings
|     |     +---> thread_siblings
|     |
|     +---> cpufreq/
|     |     +---> scaling_governor
|     |     +---> scaling_cur_freq
|     |
|     +---> cpuidle/
|     +---> online
|     +---> crash_notes
|
+---> cpu1/
+---> .../
+---> possible
+---> present
+---> online
+---> offline

第四层:内存管理与/sys/devices/system/memory

ARM64架构中,物理内存被划分为多个可热插拔的内存块(memory blocks),并通过sysfs接口暴露给用户空间,实现对内存状态的动态管理和监控。

核心数据结构与内存布局

struct memory_block

(300字节)表示一个完整的内存块结构。

struct mem_section

(64字节)描述的是内存段的基本单位。

关键源码分析与数据流转

ARM64内存子系统的初始化流程

系统启动早期,由arm64_memblock_init完成内存资源的初步扫描与分配器配置,相关代码位于arch/arm64/mm/init.c

void __init arm64_memblock_init(void) {
    early_init_fdt_scan_reserved_mem();

    memblock_enforce_memory_limit(memory_limit);

    memblock_reserve(__pa_symbol(_text), __pa_symbol(_end) - __pa_symbol(_text));
}

内存块在sysfs中的接口注册

每一个内存块作为一个设备注册到memory_subsys总线下,生成对应的kobject并创建属性文件。

int register_memory(struct memory_block *memory) {
    struct device *dev = &memory->dev;
    int ret;

    dev->id = memory->start_section_nr / sections_per_block;
    dev->bus = &memory_subsys;

    ret = device_register(dev);
    if (ret)
        return ret;

    ret = sysfs_create_group(&dev->kobj, &memory_memblk_attr_group);
    if (ret)
        device_unregister(dev);

    return ret;
}
/sys/devices/system/memory/ 目录结构说明

该目录用于管理系统中各个内存区域的属性与状态信息,其层级结构如下:

/sys/devices/system/memory/
|
+---> memory0/              [子目录]
|     +---> phys_index      [属性文件]
|     +---> state           [状态文件]
|     +---> removable       [可移除性标识]
|     +---> valid_zones     [有效内存区列表]
|
+---> memory1/
+---> .../
+---> block_size_bytes      [文件:内存块大小(字节)]
+---> auto_online_blocks    [文件:自动上线控制]

每个 memoryX 子目录对应一个物理内存块,通过 state 文件可查看或设置该内存块的状态(如 online 或 offline),removable 表示是否支持热插拔,phys_index 记录物理索引编号。

struct irq_desc
第五层:中断控制器与 /sys/kernel/irq 系统接口 ARM64 架构使用通用中断控制器(GICv3)进行中断管理。系统启动时完成 GIC 的初始化,并在 sysfs 中创建对应的接口节点,便于用户空间访问中断相关信息。 关键数据结构包括: - 中断描述符(irq_desc)——约 400 字节 - GIC 控制器私有数据结构 ——约 500 字节
struct gic_chip_data
核心源码流程解析: GIC 初始化过程主要在驱动文件 irq-gic-v3.c 中实现: // drivers/irqchip/irq-gic-v3.c int __init gic_init_bases(void __iomem *dist_base, struct fwnode_handle *handle) { // 配置GIC分发器寄存器 gic_dist_init(); // 初始化各CPU的接口部分 gic_cpu_init(); // 创建中断域,关联中断处理操作集 gic_irq_domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, gic_data); // 建立sysfs中的展示接口 gic_sysfs_init(); } 同时,在内核中断子系统中,为每个中断描述符添加 sysfs 节点: // kernel/irq/internals.h int irq_sysfs_add(struct irq_desc *desc) { struct kobject *kobj = &desc->dev->kobj; int ret; // 在 /sys/kernel/irq/ 下建立以中断号命名的目录 ret = kobject_init_and_add(&desc->kobj, &irq_kobj_type, kobj, "%d", desc->irq_data.irq); if (ret) return ret; // 添加一组属性文件 ret = sysfs_create_group(&desc->kobj, &irq_attr_group); if (ret) kobject_put(&desc->kobj); return ret; } /sys/kernel/irq/ 文件系统结构: /sys/kernel/irq/ | +---> 0/ [中断号目录] | +---> per_cpu_count [每CPU中断计数] | +---> chip_name [中断控制器名称] | +---> hwirq [硬件中断号] | +---> type [触发类型] | +---> wakeup [唤醒能力标志] | +---> name [中断源名称] | +---> 1/ +---> .../ +---> 1000/ 此路径下每个数字目录代表一个已注册的中断号,包含其运行时统计与配置信息。 第六层:时钟子系统与调试接口 /sys/kernel/debug/clk ARM64 平台依赖于通用时钟框架(Common Clock Framework)来管理 SoC 内部各类时钟信号。系统启动阶段完成时钟控制器的初始化,并通过 debugfs 提供详细的时钟树视图。 涉及的主要结构体: - clk_core:核心时钟对象,大小约为 400 字节 - clk_hw:硬件抽象层结构,约 100 字节
struct clk_core
struct clk_hw
初始化流程分析: 时钟框架入口函数定义于 clk.c: // drivers/clk/clk.c int __init clk_init(void) { // 初始化调试接口 clk_debug_init(); // 解析设备树中的时钟节点 of_clk_init(NULL); // 注册平台驱动以探测时钟控制器 platform_driver_register(&clk_driver); } 调试接口由 clk-debugfs.c 实现,用于动态生成时钟目录: // drivers/clk/clk-debugfs.c static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) { struct dentry *d; // 在 /sys/kernel/debug/clk 下为每个时钟创建子目录 d = debugfs_create_dir(core->name, pdentry);
if (!d) return -ENOMEM;
// 创建时钟属性文件
debugfs_create_file("rate", 0444, d, core, &clk_rate_fops);
debugfs_create_file("enable", 0444, d, core, &clk_enable_fops);
debugfs_create_file("prepare", 0444, d, core, &clk_prepare_fops);
return 0;
}

/sys/kernel/debug/clk/ 目录结构

/sys/kernel/debug/clk/
|
+---> osc24M/               [目录]
|     +---> rate            [文件]
|     +---> enable_count    [文件]
|     +---> prepare_count   [文件]
|
+---> pll_cpu/              [目录]
|     +---> rate
|     +---> enable_count
|
+---> cpu/                  [目录]
|     +---> rate
|     +---> enable_count
|
+---> axi/                  [目录]
+---> ahb/                  [目录]
+---> apb/                  [目录]

第一部分总结:数据流与跳转树形图

ARM64硬件启动
|
v
内核入口 (head.S)
-> 设置异常向量表
-> 初始化MMU
-> 清除BSS段
-> 跳转至start_kernel
|
v
设备树解析
-> early_init_dt_scan_nodes()
-> 构建 /sys/firmware/devicetree/base
-> 将设备树节点映射到sysfs目录结构
|
v
CPU拓扑初始化
-> init_cpu_topology() (ARM64专用)
-> 建立 /sys/devices/system/cpu/
-> 注册CPU核心及其拓扑信息
|
v
内存管理子系统初始化
-> arm64_memblock_init()
-> 创建 /sys/devices/system/memory/
-> 注册内存块及相关设备条目
|
v
中断控制器配置
-> gic_init_bases() (适用于GICv3)
-> 初始化 /sys/kernel/irq/
-> 建立中断描述符及属性接口
|
v
时钟框架启动
-> clk_init()
-> 生成 /sys/kernel/debug/clk/
-> 搭建时钟层级结构并启用调试访问

第二部分:设备驱动模型与sysfs集成

树根:设备驱动模型初始化

start_kernel() 中调用:driver_init()
  • 负责初始化设备模型组件,并构建sysfs基本目录体系

第一层:设备模型核心初始化

机制功能: 完成Linux设备模型的核心初始化工作,同时创建sysfs的顶层目录节点。 关键数据结构及其大小:
struct kobject
(200字节):表示内核对象的基类
struct kset
(300字节):用于组织内核对象的集合结构
struct kobj_type
(100字节):定义内核对象类型的元信息 源码关键函数与数据跳转路径(drivers/base/core.c):
设备模型初始化流程:
// drivers/base/core.c
void __init driver_init(void) {
    // 1. 初始化devtmpfs临时文件系统支持
    devtmpfs_init();

    // 2. 构建设备层级结构
    devices_init();

    // 3. 初始化总线管理系统
    buses_init();

    // 4. 初始化设备类体系
    classes_init();

    // 5. 启动固件相关模块
    firmware_init();

    // 6. 初始化虚拟化平台支持
    hypervisor_init();

    // 7. 建立/sys/devices下的系统设备目录
    sysfs_devices_system_init();
}
sysfs根目录创建过程:
// fs/sysfs/mount.c
int __init sysfs_init(void) {
    struct kernfs_node *kn;

    // 创建未激活状态的sysfs根节点
    sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_CREATE_DEACTIVATED);
    if (IS_ERR(sysfs_root))
        return PTR_ERR(sysfs_root);

    // 将sysfs挂载至 /sys 路径
}
kn = kernfs_get(sysfs_root->kn);
sysfs_mnt = kernfs_mount_ns(NULL, kn, sysfs_root->ns);
return 0;
}

第二层:ARM64平台设备发现与注册机制

功能概述:该层级主要负责在ARM64架构下识别并注册平台设备,通过解析设备树中的节点信息完成硬件资源的抽象和初始化。

核心数据结构及内存占用:

struct platform_device
(500字节):用于表示平台设备的数据结构
struct resource
(32字节):描述设备所使用的系统资源(如I/O地址、中断等)

关键源码流程分析

ARM64平台设备初始化函数:

// arch/arm64/kernel/setup.c
void __init arm64_device_init(void) {
    struct device_node *np;

    // 遍历设备树中所有节点
    for_each_of_allnodes(np) {
        // 判断是否为可展开的总线类型(如simple-bus或AMBA总线)
        if (of_device_is_compatible(np, "simple-bus") ||
            of_device_is_compatible(np, "arm,amba-bus")) {
            // 自动创建并注册子设备
            of_platform_populate(np, NULL, NULL, NULL);
        }
    }

    // 注册特定于ARM64 SOC的核心平台设备
    platform_device_register(&arm64_soc_device);
}

平台设备与sysfs系统的集成处理:

// drivers/base/platform.c
int platform_device_register(struct platform_device *pdev) {
    struct device *dev = &pdev->dev;
    int ret;

    // 绑定设备到平台总线类型
    dev->bus = &platform_bus_type;

    // 设置设备名称
    dev_set_name(dev, "%s", pdev->name);

    // 将设备加入内核设备模型
    ret = device_add(dev);
    if (ret)
        return ret;

    // 在sysfs中创建模块别名属性文件
    ret = device_create_file(dev, &dev_attr_modalias);
    if (ret)
        device_del(dev);

    return ret;
}

/sys/devices/platform/ 目录结构示例(基于ARM64系统)

/sys/devices/platform/
|
+---> soc/                  [目录]
|     +---> uevent          [文件]
|     +---> driver/         [符号链接]
|     +---> subsystem/      [符号链接]
|     +---> power/          [目录]
|
+---> 10000000.serial/      [目录]
|     +---> uevent
|     +---> driver -> ../../../../bus/platform/drivers/uart-pl011
|     +---> tty/            [目录]
|     +---> power/
|
+---> 10110000.rtc/         [目录]
|     +---> uevent
|     +---> driver -> ../../../../bus/platform/drivers/rtc-pl031
|     +---> power/
|
+---> 1c21000.watchdog/     [目录]
+---> .../

第三层:总线子系统与 /sys/bus 的构建

机制作用:实现总线类型的统一管理,并在sysfs虚拟文件系统中建立对应的层级目录结构,支持设备与驱动的动态绑定。

关键数据结构及其大小:

struct bus_type
(600字节):代表一种总线类型(如platform、PCI等)
struct device_driver
(400字节):描述设备驱动的基本信息与操作集

核心初始化逻辑

总线子系统启动流程:

// drivers/base/bus.c
int __init buses_init(void) {
    // 创建 /sys/bus 根目录
    bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
    if (!bus_kset)
        return -ENOMEM;

    // 创建 /sys/devices/system 目录用于系统级对象
    system_kset = kset_create_and_add("system", &bus_uevent_ops, NULL);

    return 0;
}

平台总线的典型注册过程(常用于ARM64环境):

// drivers/base/platform.c
struct bus_type platform_bus_type = {
    .name       = "platform",
    .dev_groups = platform_dev_groups,
    .match      = platform_match,
    .uevent     = platform_uevent,
    .pm         = &platform_dev_pm_ops,
};

该结构体定义了一个名为“platform”的总线类型,包含了设备匹配、用户空间事件通知、电源管理等操作的回调函数。其中,.match 字段指定了 platform 总线的设备与驱动匹配规则,.pm 提供了电源管理支持。

平台总线初始化函数如下:

int __init platform_bus_init(void) {
    int error;
    // 注册平台总线
    error = bus_register(&platform_bus_type);
    if (error)
        return error;

    // 在/sys/bus/platform下创建设备目录
    error = device_register(&platform_bus);
    if (error) {
        bus_unregister(&platform_bus_type);
    }

    return error;
}

此函数首先调用 bus_register 向内核注册 platform 总线类型,成功后在 sysfs 文件系统中创建对应的 /sys/bus/platform 目录。若 device_register 失败,则反向注销已注册的总线以避免资源泄漏。

/sys/bus/ 目录结构说明

在 Linux 的 sysfs 中,/sys/bus/ 是所有总线的根目录,其子目录代表不同的总线类型。以下是典型结构:

/sys/bus/
|
+---> platform/             [目录]
|     +---> devices/        [目录]
|     |     +---> soc/ -> ../../../devices/platform/soc
|     |     +---> 10000000.serial/ -> ../../../devices/platform/10000000.serial
|     |
|     +---> drivers/        [目录]
|     |     +---> uart-pl011/     [目录]
|     |     |     +---> bind       [文件]
|     |     |     +---> uevent     [文件]
|     |     |     +---> 10000000.serial -> ../../../../devices/platform/10000000.serial
|     |     |
|     |     +---> rtc-pl031/       [目录]
|     |     +---> .../
|     |
|     +---> uevent          [文件]
|
+---> amba/                 [目录] (ARM AMBA总线)
|     +---> devices/
|     +---> drivers/
|
+---> pci/                  [目录]
|     +---> devices/
|     +---> drivers/
|
+---> usb/                  [目录]
+---> i2c/                  [目录]
+---> spi/                  [目录]

每个总线下包含 devices 和 drivers 两个主要子目录,分别用于列出当前挂载的设备和注册的驱动程序,并通过符号链接关联实际设备路径。

第四层:设备类与 /sys/class

机制功能:为了方便用户空间按功能对设备进行分类管理,Linux 内核在 sysfs 中引入了设备类(class)的概念,并在 /sys/class 下为每种设备类建立独立目录。

核心数据结构大小信息

struct class

(400字节):设备类结构体占用内存大小
struct class_device

(300字节):类设备结构体占用内存大小

关键源码分析

类子系统的初始化工作由 classes_init 函数完成,其实现位于 drivers/base/class.c:

// drivers/base/class.c
int __init classes_init(void) {
    // 创建 /sys/class 目录
    class_kset = kset_create_and_add("class", NULL, NULL);
    if (!class_kset)
        return -ENOMEM;
    return 0;
}

该函数在系统启动阶段被调用,负责创建 sysfs 中的顶级 class 容器对象,后续所有设备类都将作为其子项存在。

ARM64 架构常见设备类注册示例

以下是一些典型的设备类定义:

// 块设备类
struct class block_class = {
    .name       = "block",
    .dev_uevent = block_uevent,
};

// 输入设备类
struct class input_class = {
    .name       = "input",
    .devnode    = input_devnode,
};

// TTY设备类
struct class tty_class = {
    .name       = "tty",
    .devnode    = tty_devnode,
};

这些类在各自模块初始化时注册到内核,从而在 /sys/class 下生成对应目录。

/sys/class/ 目录结构(ARM64 示例)

/sys/class/
|
+---> block/                [目录]
|     +---> mmcblk0/        [目录]

该结构展示了 block 类下的一个具体块设备实例 mmcblk0,用户可通过该路径获取设备属性或触发事件。

+---> gpio/                 [目录]
|     +---> gpiochip0/      [目录]
|     |     +---> base       [文件]
|     |     +---> label      [文件]
|     |     +---> ngpio      [文件]

+---> thermal/              [目录]
|     +---> thermal_zone0/  [目录]
|     |     +---> temp       [文件]
|     |     +---> type       [文件]
|     |     +---> mode       [文件]

+---> firmware/             [目录]
+---> net/                  [目录]
+---> graphics/             [目录]

+---> device/               [符号链接]
+---> power/                [目录]
+---> subsystem/            [符号链接]
+---> mmcblk0p1/            [目录] (分区1)
+---> mmcblk0p2/            [目录] (分区2)

+---> input/                [目录]
|     +---> input0/         [目录]
|     |     +---> name       [文件]
|     |     +---> capabilities [文件]
|     |     +---> device/    [符号链接]

+---> tty/                  [目录]
|     +---> ttyAMA0/        [目录]
|     |     +---> dev        [文件]
|     |     +---> power/     [目录]
|     |     +---> subsystem/ [符号链接]

+---> leds/                 [目录]
|     +---> led0/           [目录]
|     |     +---> brightness [文件]
|     |     +---> trigger    [文件]
|     |     +---> device/    [符号链接]

第五层:设备属性与sysfs文件操作

机制功能

实现设备在sysfs中属性文件的创建,并定义对应文件的操作接口,使得用户空间能够通过文件系统读取或控制设备状态。

数据结构与大小

包含以下核心数据结构及其内存占用:

struct attribute

(40字节):属性基类,用于描述通用属性的基本信息。

struct device_attribute

(80字节):设备属性结构,在基础之上扩展了设备相关的操作函数。

struct bin_attribute

(120字节):二进制属性结构,支持更复杂的数据读写,适用于非文本型设备数据传输。

源码关键函数与数据跳转

属性文件创建

通过调用内核API完成设备目录下属性文件的注册:

// drivers/base/core.c
int device_create_file(struct device *dev, const struct device_attribute *attr) {
    int error = 0;
    if (dev) {
        // 在设备对应的kobject下创建属性文件
        error = sysfs_create_file(&dev->kobj, &attr->attr);
    }
    return error;
}
ARM64 GPIO控制器属性示例

以GPIO子系统为例,展示如何定义只读属性并将其组织成属性组:

// drivers/gpio/gpiolib-sysfs.c
static DEVICE_ATTR(base, 0444, base_show, NULL);
static DEVICE_ATTR(label, 0444, label_show, NULL);
static DEVICE_ATTR(ngpio, 0444, ngpio_show, NULL);

static struct attribute *gpiochip_attrs[] = {
    &dev_attr_base.attr,
    &dev_attr_label.attr,
    &dev_attr_ngpio.attr,
    NULL,
};

static const struct attribute_group gpiochip_attr_group = {
    .attrs = gpiochip_attrs,
};
int gpiochip_sysfs_register(struct gpio_chip *chip) {
    struct device *dev = &chip->gpiodev->dev;
    int ret;

    ret = sysfs_create_group(&dev->kobj, &gpiochip_attr_group);
    if (ret) {
        dev_err(dev, "failed to create sysfs files\n");
        return ret;
    }
    return 0;
}

第六层:电源管理与 /sys/power

机制功能:负责电源管理子系统的初始化,并创建对应的 sysfs 接口,用于用户空间对系统电源状态进行控制和监控。

数据结构与大小:

struct dev_pm_info
(200字节):设备电源管理信息
struct dev_pm_ops
(300字节):电源管理操作

源码关键函数与数据跳转

电源管理初始化

// drivers/base/power/main.c

int __init pm_init(void) {
    // 创建 /sys/power 目录
    power_kobj = kobject_create_and_add("power", NULL);
    if (!power_kobj) return -ENOMEM;

    // 创建电源管理属性文件组
    sysfs_create_group(power_kobj, &attr_group);
    return 0;
}
ARM64 挂起/恢复支持

// arch/arm64/kernel/suspend.c

int arm64_suspend_init(void) {
    // 设置 ARM64 架构的挂起操作集
    suspend_set_ops(&arm64_suspend_ops);

    // 在 /sys/power 下创建 mem_sleep 控制文件
    sysfs_create_file(power_kobj, &dev_attr_mem_sleep.attr);
    return 0;
}

/sys/power/ 目录结构

/sys/power/
|
+---> state                 [文件] (控制电源状态)
+---> disk                  [文件] (指定挂起到磁盘模式)
+---> pm_test               [文件] (电源管理测试模式设置)
+---> wakeup_count          [文件] (获取或等待唤醒事件计数)
+---> wake_lock             [文件] (申请唤醒锁防止休眠)
+---> wake_unlock           [文件] (释放已持有的唤醒锁)
+---> mem_sleep             [文件] (配置 ARM64 内存睡眠模式)
+---> image_size            [文件] (设置休眠镜像最大大小)
+---> resume                [文件] (触发从休眠状态恢复)

第七层:DMA 与 IOMMU /sys/kernel/iommu_groups

机制功能:实现 ARM64 平台下 IOMMU 的初始化工作,并提供 DMA 映射相关的 sysfs 接口,用于管理和查看 IOMMU 组及设备关系。

数据结构与大小:

struct iommu_group
(400字节):IOMMU 组结构体,描述一组可被统一映射管理的设备
struct iommu_device
(200字节):IOMMU 设备结构体,表示一个接入 IOMMU 的硬件设备

源码关键函数与数据跳转

ARM64 SMMU 初始化

// drivers/iommu/arm-smmu-v3.c

static int arm_smmu_device_probe(struct platform_device *pdev) {
    struct arm_smmu_device *smmu;
    int ret;

    // 探测并初始化 SMMU 硬件寄存器
    ret = arm_smmu_device_hw_probe(smmu);
    if (ret) return ret;

    // 将 SMMU 添加到 sysfs,便于用户空间查看
    ret = iommu_device_sysfs_add(&smmu->iommu, &pdev->dev, NULL, "smmu3.%pa", &smmu->ioaddr);
    if (ret) return ret;

    // 注册 IOMMU 设备到核心框架,启用其操作接口
    ret = iommu_device_register(&smmu->iommu, &arm_smmu_ops, smmu->dev);
    return ret;
}
IOMMU sysfs 接口

// drivers/iommu/iommu-sysfs.c

int iommu_device_sysfs_add(struct iommu_device *iommu, struct device *dev,

const struct attribute_group **groups,

const char *fmt, ...) {

struct device *sysdev = &iommu->sysdev;

int ret;

// 初始化设备对象

device_initialize(sysdev);

sysdev->class = &iommu_class;

sysdev->parent = dev;

// 配置设备名称

dev_set_name(sysdev, fmt, args);

// 将设备添加到系统中

ret = device_add(sysdev);

if (ret) return ret;

// 建立对应的属性文件组

ret = sysfs_create_groups(&sysdev->kobj, groups);

return ret;

}

/sys/kernel/iommu_groups/ 结构说明

该路径展示了IOMMU组的层级组织方式:

/sys/kernel/iommu_groups/
|
+---> 0/                    
|     +---> name            
|     +---> devices/        
|     |     +---> 0000:00:00.0 -> ../../../../devices/pci0000:00/0000:00:00.0
|     |
|     +---> reserved_regions 
|
+---> 1/
+---> .../
    

第八层:调试与性能监控(/sys/kernel/debug)

功能概述:提供内核调试接口及ARM64架构下的性能分析支持。

关键数据结构与内存占用

struct dentry

(200字节):表示目录条目信息

struct debugfs_regset32

(100字节):用于保存寄存器状态集合

核心源码流程解析

调试文件系统初始化过程

// 文件路径:fs/debugfs/inode.c

static int __init debugfs_init(void) {

    int retval;

    // 挂载debugfs根节点

    debugfs_mount = kern_mount(&debugfs_fs_type);

    if (IS_ERR(debugfs_mount)) {

        retval = PTR_ERR(debugfs_mount);

        debugfs_mount = NULL;

        return retval;

    }

    return 0;

}

ARM64性能监控模块初始化

// 文件路径:arch/arm64/kernel/perf_event.c

static int arm64_pmu_init(struct arm64_pmu *arm64_pmu) {

    // 初始化PMU硬件单元

    armpmu_init(arm64_pmu);

    // 在debugfs中注册性能事件接口

    perf_pmu_register(&arm64_pmu->pmu, arm64_pmu->name, -1);

    return 0;

}

/sys/kernel/debug/ 目录结构(ARM64平台特有)

/sys/kernel/debug/
|
+---> tracing/              
|     +---> trace           
|     +---> trace_pipe      
|     +---> current_tracer  
|     +---> available_tracers 
|
+---> gpio/                 
|     +---> gpio            
|
+---> pmc/                  
|     +---> cpu0/           
|     |     +---> cycles    
|     |     +---> instructions 
|     +---> cpu1/
|
+---> regmap/               
|     +---> 10000000.serial/ 
|     |     +----> registers 
|
+---> wakeup_sources        
+----> dynamic_debug/       
    

第二部分总结:数据流动与调用关系图示

设备驱动模型启动流程:

设备驱动模型初始化
        |
        v
   driver_init()
    
第三部分:特定设备驱动与sysfs属性  
树根:平台设备驱动注册  
1. 进入device_initcall阶段,各类平台驱动完成注册流程  

|
v  
第一层:串口驱动与/sys/class/tty  

机制功能:  
初始化ARM64架构下的串口控制器驱动,并将tty类设备进行系统注册,实现串行通信支持。  

数据结构与大小:  
struct uart_driver
(200字节):串口驱动结构体信息
struct uart_port
(500字节):串口端口相关数据结构
struct tty_driver
(400字节):tty驱动结构体描述 源码关键函数与数据跳转: PL011串口驱动初始化(广泛应用于ARM64平台) // drivers/tty/serial/amba-pl011.c static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; struct vendor_data *vendor = id->data; int portnr, ret; // 动态分配uart_amba_port结构内存 uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); if (!uap) return -ENOMEM; // 配置端口基本参数 uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = ioremap(dev->res.start, resource_size(&dev->res)); uap->port.irq = dev->irq[0]; uap->port.fifosize = vendor->fifosize; uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; // 注册当前串口端口到UART核心层 portnr = pl011_find_free_port(); uap->port.line = portnr; ret = uart_add_one_port(&amba_reg, &uap->port); if (ret) goto free; // 在sysfs中创建设备属性文件 ret = device_create_file(&dev->dev, &dev_attr_clock_source); if (ret) dev_warn(&dev->dev, "failed to create clock source attr\n"); return 0; free:
调试与性能监控阶段处理  
-> 初始化debugfs文件系统接口  
-> 完成ARM64平台性能监控单元的设置  
-> 建立用于调试和性能分析的相关访问路径  

|
v  
电源管理集成操作  
-> 调用pm_init()完成电源子系统初始化  
-> 在/sys/目录下生成power子目录  
-> 支持ARM64架构的挂起与恢复机制  
-> 提供用户空间可访问的电源状态控制接口  

|
v  
设备类系统集成  
-> 注册包括块设备、输入设备、TTY等在内的多种设备类别  
-> 在/sys/class/路径下建立对应的功能分类目录  
-> 实现按功能组织的设备视图结构,便于管理和访问  

|
v  
总线系统的初始化与整合  
-> platform_bus_init():初始化平台总线  
-> amba_bus_init():启动AMBA总线支持  
-> 在/sys/bus/目录中创建各总线对应的子目录  
-> 构建设备符号链接以实现跨目录统一访问  

|
v  
ARM64平台上的设备发现流程  
-> 调用arm64_device_init()启动设备初始化  
-> 解析设备树(Device Tree)获取平台设备信息  
-> 在/sys/devices/platform/路径下创建相应的设备节点  
-> 建立设备与驱动之间的绑定关系,触发匹配过程  

|
v  
sysfs目录结构的构建过程  
-> 创建/sys/基础目录体系  
    -> /sys/devices/:反映物理设备的层级拓扑  
    -> /sys/bus/:按照总线类型组织设备展示  
    -> /sys/class/:依据设备功能进行归类显示  
    -> /sys/firmware/:提供固件交互接口  
    -> /sys/kernel/:暴露内核内部参数与配置项  
    -> /sys/power/:支撑系统级电源管理功能  

|
v  
核心初始化函数调用序列  
-> devtmpfs_init():初始化设备临时文件系统,支持动态设备节点创建  
-> devices_init():初始化设备模型核心组件  
-> buses_init():搭建总线管理系统框架  
-> classes_init():准备设备类管理结构  
-> firmware_init():初始化固件加载与交互机制  
kfree(uap);
return ret;
}

tty类设备注册:
在TTY子系统中,通过调用`tty_register_driver`函数完成驱动的注册。该函数位于`drivers/tty/tty_io.c`,主要负责将指定的TTY驱动加入内核,并在sysfs中创建相应的设备节点和类入口。

// drivers/tty/tty_io.c
int tty_register_driver(struct tty_driver *driver) {
    struct device *dev;
    int error;
    dev_t devt;

    // 在 /sys/class/tty 下注册tty类
    error = class_register(&tty_class);
    if (error)
        return error;

    // 遍历所有次设备,为每个设备创建对应的设备节点
    for (unsigned i = 0; i < driver->num; i++) {
        devt = MKDEV(driver->major, driver->minor_start + i);
        dev = tty_register_device(driver, i, NULL);
        if (IS_ERR(dev)) {
            error = PTR_ERR(dev);
            goto err;
        }
    }
    return 0;

err:
    class_unregister(&tty_class);
    return error;
}

/sys/class/tty/ttyAMA0/ 目录结构说明:
该路径表示一个具体的TTY设备在sysfs中的层次结构,用于暴露设备属性、链接关系及电源管理信息。

/sys/class/tty/ttyAMA0/
|
+---> dev                   [文件] —— 包含设备主次号(如:204:64)
+---> device/               [符号链接] 指向硬件平台设备 ../../../10000000.serial
+---> power/                [目录] —— 电源管理相关接口
|     +---> async           [文件]
|     +---> control         [文件]
|     +---> runtime_active_time [文件]
|     +---> runtime_status  [文件]
|     +---> runtime_suspended_time [文件]
|
+---> subsystem/            [符号链接] 指向tty类 ../../../../class/tty
+---> uevent                [文件] —— 用户态事件通知接口

第二层:MMC/SD控制器驱动与 /sys/class/mmc_host
机制功能描述:
ARM64架构下的MMC/SD控制器驱动在初始化阶段完成资源映射、时钟配置以及块设备的注册。同时,在sysfs中创建`mmc_host`类设备节点,供用户空间查询和控制SD卡状态。

数据结构及其大小:
struct mmc_host
(2KB):代表MMC主机控制器的数据结构实例
struct mmc_card
(800字节):描述已插入的MMC卡的信息结构
struct gendisk
(600字节):通用磁盘结构体,用于块设备抽象 源码关键流程与数据流转分析: ARM64平台上的SDHCI控制器驱动实现(以Arasan控制器为例): // drivers/mmc/host/sdhci-of-arasan.c static int sdhci_arasan_probe(struct platform_device *pdev) { struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_arasan_data *sdhci_arasan; int ret; // 初始化SDHCI平台主机结构 host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, sizeof(*sdhci_arasan)); if (IS_ERR(host)) return PTR_ERR(host); // 获取私有数据指针 pltfm_host = sdhci_priv(host); sdhci_arasan = sdhci_pltfm_priv(pltfm_host); // 获取并保存AHB和XIN时钟句柄 sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); sdhci_arasan->clk_xin = devm_clk_get(&pdev->dev, "clk_xin"); // 启用所需时钟 clk_prepare_enable(sdhci_arasan->clk_ahb); clk_prepare_enable(sdhci_arasan->clk_xin); // 将主机添加到MMC核心层 ret = sdhci_add_host(host); if (ret) goto err_clk_disable; // 在设备上创建clock_rate属性文件,用于调试或动态调节 ret = device_create_file(&pdev->dev, &dev_attr_clock_rate);
int register_blkdev(unsigned int major, const char *name) {
    struct blk_major_name **n, *p;
    int index, ret = 0;

    // 注册块设备类,创建 /sys/class/block 目录
    ret = class_register(&block_class);
    if (ret)
        return ret;

    // 分配内存用于保存主设备号与名称映射
    p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
    if (!p)
        return -ENOMEM;

    p->major = major;
    strlcpy(p->name, name, sizeof(p->name));
    p->next = NULL;

    // 计算主设备号对应哈希索引
    index = major_to_index(major);

    // 将新项插入全局链表 blk_major_names
    n = &blk_major_names[index];
    while (*n)
        n = &(*n)->next;
    *n = p;

    return 0;
}

上述代码实现了块设备的注册功能。通过调用 class_register 在 sysfs 中创建 /sys/class/block 类目录,并将指定主设备号和设备名记录到全局链表中,供后续设备节点创建使用。

/sys/class/mmc_host/mmc0/ 目录结构说明

该路径展示了 MMC 主机控制器在 sysfs 中的设备信息布局:

/sys/class/mmc_host/mmc0/
|
+---> device/               [符号链接] -> ../../../10000000.mmc
+---> power/                [目录]
|     +---> control         [文件]
|     +---> runtime_status  [文件]
|
+---> subsystem/            [符号链接] -> ../../../../class/mmc_host
+---> uevent                [文件]
|
+---> mmc0:0001/            [目录] (代表已识别的SD卡设备)
+---> block/                [目录]
|     +---> mmcblk0/        [目录]
|     |     +---> dev       [文件] - 包含主次设备号
|     |     +---> device/   [符号链接] -> ../../../../mmc0:0001
|     |     +---> power/    [电源管理子系统]
|     |     +---> mmcblk0p1/[目录] - 第一个分区
|     |     +---> mmcblk0p2/[目录] - 第二个分区
|
+---> cid                   [文件] - 卡身份标识
+---> csd                   [文件] - 卡特定数据寄存器
+---> date                  [文件] - 制造日期
+---> enhanced_area_offset  [文件] - 增强区域偏移量
+---> enhanced_area_size    [文件] - 增强区域大小
+---> erase_size            [文件] - 擦除块大小
+---> fwrev                 [文件] - 固件版本
+---> hwrev                 [文件] - 硬件版本
+---> manfid                [文件] - 制造商ID
+---> name                  [文件] - 产品名称
+---> oemid                 [文件] - OEM/ODM 标识
+---> preferred_erase_size  [文件] - 推荐擦除大小
+---> raw_rpmb_size_mult    [文件] - RPMB 区域大小倍数
+---> rel_sectors           [文件] - 相对地址扇区数
+---> serial                [文件] - 序列号
+---> ssr                   [文件] - SD状态寄存器值
struct proc_info_list

第三层:GPIO控制器驱动与 /sys/class/gpio 机制功能

在 ARM64 架构中,GPIO 控制器驱动负责管理系统通用输入输出引脚。初始化过程中会注册相应的平台设备和驱动,并导出接口至用户空间。

通过 sysfs 提供的 /sys/class/gpio 路径,用户可以在不编写内核模块的情况下,直接通过 shell 命令控制 GPIO 引脚的状态(如设置方向、读写电平),实现简单的硬件交互。

核心数据结构与内存占用

GPIO 子系统依赖于关键数据结构来维护引脚状态、方向及所属控制器信息。这些结构通常包括:

  • struct gpio_chip:描述一个物理 GPIO 控制器,包含操作函数集(如 get/set)、基地址、引脚数量等;
  • struct gpio_desc:每个 GPIO 引脚的运行时描述符,记录方向、使用状态、中断能力等属性;
  • 相关缓存和映射表:用于快速查找引脚编号与芯片间的对应关系。

整体内存开销取决于系统中支持的 GPIO 总数以及启用的功能选项,但单个 gpio_chip 和描述符结构体大小通常在几十到上百字节之间。

struct machine_desc

GPIO描述符

struct gpio_desc

在Linux内核中,GPIO子系统通过统一的抽象层实现对通用输入输出引脚的管理。其中,核心组件包括GPIO控制器、GPIO设备以及GPIO描述符。这些模块协同工作,完成从硬件寄存器映射到用户空间接口的完整链路。

GPIO设备

struct gpio_device

每个GPIO控制器对应一个gpio_chip结构体实例,该结构体封装了操作底层硬件的基本方法,如方向设置、电平读写等。以ARM64架构下的PL061 GPIO控制器为例,其驱动实现位于drivers/gpio/gpio-pl061.c文件中。函数pl061_probe负责探测并初始化该控制器。

在该函数中,首先通过devm_kzalloc分配控制器私有数据结构内存,并初始化gpio_chip中的关键字段:指定引脚数量(ngpio)、设置标签名称(label)、绑定父设备及所属模块。同时,将具体的硬件操作函数指针赋值,例如输入/输出方向控制、电平获取与设置函数。

随后,使用devm_ioremap_resource对设备寄存器地址空间进行映射,以便后续直接访问硬件寄存器。完成资源配置后,调用devm_gpiochip_add_data将GPIO芯片注册进内核GPIO管理系统,使其具备被全局索引和调度的能力。

最后,为了向用户空间暴露接口,执行gpiochip_sysfs_register函数,在/sys/class/gpio目录下创建对应的sysfs条目。若注册失败,则通过警告提示导出异常,但不中断整体流程。

GPIO控制器

struct gpio_chip

当GPIO被请求并导出时,系统会触发gpiod_export函数,其实现位于drivers/gpio/gpiolib-sysfs.c。此函数的作用是在sysfs文件系统中为指定的GPIO描述符建立设备节点及其属性文件。

具体而言,它首先调用sysfs_create_group在对应GPIO设备的kobject下创建一组标准属性。接着依次添加方向(direction)、数值(value)和低电平有效标志(active_low)等可读写文件。若任一文件创建失败,则执行回滚操作,移除已创建的文件,确保系统状态一致性。

源码关键函数与数据跳转

static int dw_i2c_plat_probe(struct platform_device *pdev) {
    struct dw_i2c_dev *dev;
    struct i2c_adapter *adap;
    int ret;

    // 分配I2C设备结构体内存
    dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;

    // 初始化I2C适配器
    adap = &dev->adapter;
    adap->owner = THIS_MODULE;
    adap->class = I2C_CLASS_DEPRECATED;
    adap->algo = &i2c_dw_algo;
    adap->dev.parent = &pdev->dev;
    i2c_set_adapdata(adap, dev);

    // 映射控制器寄存器地址空间
    dev->base = devm_platform_ioremap_resource(pdev, 0);
    if (IS_ERR(dev->base))
        return PTR_ERR(dev->base);

    // 获取并使能时钟资源
    dev->clk = devm_clk_get(&pdev->dev, NULL);
    if (IS_ERR(dev->clk))
        return PTR_ERR(dev->clk);
    clk_prepare_enable(dev->clk);

    // 设置平台特定数据
    platform_set_drvdata(pdev, dev);

    // 添加I2C适配器到系统
    ret = i2c_add_numbered_adapter(adap);
    if (ret) {
        clk_disable_unprepare(dev->clk);
        return ret;
    }

    return 0;
}

// 移除函数清理资源
static int dw_i2c_plat_remove(struct platform_device *pdev) {
    struct dw_i2c_dev *dev = platform_get_drvdata(pdev);

    i2c_del_adapter(&dev->adapter);
    clk_disable_unprepare(dev->clk);

    sysfs_remove_group(&pdev->dev.kobj, &dw_i2c_attr_group);
    return 0;
}

/sys/class/gpio/ 目录结构说明

Linux系统中,通过sysfs接口暴露GPIO控制能力,其根目录位于 /sys/class/gpio/,主要包含以下组成部分:

/sys/class/gpio/
|
+---> export                [文件] 用于导出指定编号的GPIO以进行用户空间操作
+---> unexport              [文件] 取消已导出的GPIO控制权
|
+---> gpiochip0/            [目录] 表示第一个GPIO控制器实例
|     +---> base            [文件] 记录该控制器管理的第一个GPIO编号(例如:0)
|     +---> label           [文件] 控制器名称标识,如 "10000000.gpio"
|     +---> ngpio           [文件] 当前控制器支持的GPIO总数(例如:32)
|     +---> device/         [符号链接] 指向具体的设备路径 ../../../10000000.gpio
|     +---> power/          [目录] 电源管理相关子系统接口
|     +---> subsystem/      [符号链接] 关联到GPIO总线类 ../../../../class/gpio
|
+---> gpiochip1/            [目录] 第二个GPIO控制器
|     +---> base            [文件] 起始编号为32
|     +---> label           [文件] 标签为 "10001000.gpio"
|     +---> ngpio           [文件] 管理16个GPIO引脚
|
+---> gpio10/               [目录] 用户已导出的GPIO 10号引脚
      +---> direction       [文件] 配置方向:输入(in)或输出(out)
      +---> value           [文件] 当前电平状态:0(低)或1(高)
      +---> edge            [文件] 触发中断的边沿类型:none/rising/falling/both
      +---> active_low      [文件] 是否启用低电平有效模式
      +---> device/         [符号链接] 指向所属控制器 ../../../gpiochip0
      +---> power/          [目录] 电源状态控制
      +---> subsystem/      [符号链接] 关联回GPIO类 ../../../../class/gpio

第四层:I2C控制器驱动与 /sys/bus/i2c 机制功能

在ARM64架构下,I2C控制器驱动负责初始化硬件模块,并完成与内核I2C子系统的绑定。同时,通过 /sys/bus/i2c/ 接口实现设备与驱动的动态注册和属性展示。

struct i2c_adapter

(600字节):表示 I2C 适配器(i2c_adapter)结构体,代表一个物理I2C总线控制器。

struct i2c_client

(400字节):描述 I2C 客户端(i2c_client),即挂载在总线上的从设备节点。

struct i2c_driver

(300字节):体现 I2C 驱动(i2c_driver)结构体,封装了匹配规则和操作函数集。

关键源码流程与数据跳转关系

I2C控制器驱动通常基于平台设备模型实现,以下是核心初始化逻辑:

  • 调用 devm_kzalloc 为控制器私有数据分配内存;
  • 初始化 i2c_adapter 结构体,设置算法指针、所属模块等字段;
  • 通过 devm_platform_ioremap_resource 映射控制器寄存器区域;
  • 获取并使能时钟资源,确保硬件处于工作状态;
  • 使用 i2c_add_numbered_adapter 将适配器注册进内核,生成对应的 /dev/i2c-X 设备节点;
  • 移除时调用 i2c_del_adapter 并释放时钟资源。

整个过程实现了从设备树节点到I2C总线适配器的完整映射,使得上层应用可通过标准接口访问外接I2C设备。

// 分配并初始化SPI主控制器
struct dw_spi *dws;
struct spi_controller *master;

master = spi_alloc_master(&pdev->dev, sizeof(*dws));
if (!master) return -ENOMEM;

dws = spi_controller_get_devdata(master);
dws->master = master;
dws->dev = &pdev->dev;

// 配置SPI操作函数集
struct spi_driver
// 获取平台资源与寄存器映射 ret = dw_spi_probe_of(pdev, dws); if (ret) goto err_put_master; // 请求中断处理 ret = devm_request_irq(&pdev->dev, dws->irq, dw_spi_irq, 0, dev_name(&pdev->dev), dws); if (ret) goto err_put_master; // 添加SPI控制器到系统 ret = spi_register_controller(master); if (ret) goto err_put_master; return 0; err_put_master: spi_controller_put(master); return ret;

SPI控制器驱动与/sys/bus/spi 机制说明

在ARM64架构中,SPI控制器驱动的初始化过程涉及平台设备探测、控制器内存分配、硬件资源配置以及最终的控制器注册。通过spi_alloc_master分配主控制器结构,并将私有数据区域用于存放控制器特定信息。

完成基本初始化后,从设备树获取相关配置参数,进行寄存器地址映射和中断请求设置。关键步骤包括:

  • 调用dw_spi_probe_of解析设备树节点
  • 使用devm_request_irq注册中断服务程序
  • 最后通过spi_register_controller将SPI主控制器注册至核心层

数据结构大小概览

各核心组件占用内存如下:

struct spi_controller
(1KB):SPI控制器实例
struct spi_device
(400字节):SPI设备描述符
struct spi_driver
(300字节):SPI驱动结构体

/sys/bus/i2c/devices/ 目录结构说明

该路径展示了系统中已注册的I2C设备与适配器的层次布局,每个子目录对应一个实际存在的设备或总线实例。

/sys/bus/i2c/devices/
|
+---> 0-0050/               [目录] (I2C总线0,设备地址0x50)
|     +---> name            [文件] 内容: "eeprom"
|     +---> modalias        [文件] 模块匹配标识
|     +---> power/          [目录] 电源管理接口
|     +---> subsystem/      [符号链接] 指向I2C总线系统
|     +---> driver/         [符号链接] 关联at24驱动模块
|     +---> eeprom          [文件] 可读写的EEPROM数据节点
|
+---> 1-001c/               [目录] (I2C总线1,设备地址0x1c)
|     +---> name            [文件] 内容: "lm75"
|     +---> modalias        [文件]
|     +---> temp1_input     [文件] 当前温度采样值(单位: 毫摄氏度)
|     +---> driver/         [符号链接] 指向lm75驱动
|
+---> i2c-0/                [目录] (I2C适配器0)
|     +---> name            [文件] 名称: "Synopsys DesignWare I2C adapter"
|     +---> device/         [符号链接] 指向底层平台设备
|     +---> power/          [目录]
|     +---> subsystem/      [符号链接] 回连至I2C总线
|
+---> i2c-1/                [目录] (I2C适配器1)

I2C适配器初始化流程

以下代码段实现对I2C控制器时钟的获取与使能,并完成适配器的探测与属性创建:

dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(dev->clk)) {
    ret = clk_prepare_enable(dev->clk);
    if (ret) return ret;
}

// 探测并注册I2C适配器功能
ret = i2c_dw_probe(dev);
if (ret) goto err_clk_disable;

// 向设备对象添加SCL频率属性文件
ret = device_create_file(&pdev->dev, &dev_attr_scl_frequency);
if (ret)
    dev_warn(&pdev->dev, "failed to create SCL frequency attr\n");

return 0;

err_clk_disable:
    if (!IS_ERR(dev->clk))
        clk_disable_unprepare(dev->clk);
return ret;
// 配置SPI控制器的模式位,启用CPOL、CPHA和LOOP模式
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;

// 设置支持的每字长度掩码,允许8位和16位传输
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);

// 指定总线编号,使用平台设备ID作为SPI总线编号
master->bus_num = pdev->id;

// 绑定控制器的操作函数
master->setup = dw_spi_setup;
master->transfer_one = dw_spi_transfer_one;
master->handle_err = dw_spi_handle_err;

// 映射硬件寄存器地址空间
dws->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dws->regs)) {
    ret = PTR_ERR(dws->regs);
    goto err_free_master;
}

// 向内核注册SPI控制器
ret = devm_spi_register_controller(&pdev->dev, master);
if (ret)
    goto err_free_master;

return 0;

err_free_master:
    spi_controller_put(master);
    return ret;

/sys/bus/spi/devices/ 目录结构说明

该路径展示了系统中已注册的SPI设备在sysfs中的层次布局:

/sys/bus/spi/devices/
|
+---> spi0.0/                       [目录] —— SPI总线0,片选0设备
|     +---> modalias                [文件] —— 模块别名信息
|     +---> of_node/                [符号链接] —> ../../../../firmware/devicetree/base/soc/spi@10010000/mcp2515@0
|     +---> power/                  [目录] —— 电源管理相关接口
|     +---> subsystem/              [符号链接] —> ../../../../bus/spi
|     +---> driver/                 [符号链接] —> ../../../../bus/spi/drivers/mcp251x
|     +---> uevent                  [文件] —— 用户空间事件触发接口
|
+---> spi0.1/                       [目录] —— SPI总线0,片选1设备
|     +---> modalias                [文件]
|     +---> driver/                 [符号链接] —> ../../../../bus/spi/drivers/spidev
|     +---> dev                     [文件] —— 对应的设备节点号
|
+---> spi1.0/                       [目录] —— SPI总线1,片选0设备
|
+---> spi1/                         [目录] —— SPI控制器1的设备表示
      +---> device/                 [符号链接] —> ../../../10010000.spi
      +---> power/                  [目录]
      +---> subsystem/              [符号链接] —> ../../../../bus/spi

第六层:网络设备驱动与 /sys/class/net

机制功能:
实现ARM64架构下网络控制器驱动的初始化流程,并完成网络设备的注册操作。通过标准内核框架将硬件抽象为可操作的网络接口。

数据结构及其大小:

struct net_device

(3KB):描述网络设备的核心结构体实例
struct net_device_ops

(1KB):定义网络设备操作集的结构体(如open、stop、xmit等)

源码关键函数与数据流转:

ARM64 网络控制器驱动初始化

源文件路径:drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c

static int stmmac_pltfr_probe(struct platform_device *pdev)
{
    struct plat_stmmacenet_data *plat_dat;
    struct stmmac_resources stmmac_res;
    struct net_device *ndev;
    int ret;

    // 获取平台资源,包括中断、内存区域等
    ret = stmmac_get_platform_resources(pdev, &stmmac_res);
    if (ret)
        return ret;

    // 分配以太网设备结构,包含私有数据空间
    ndev = alloc_etherdev(sizeof(struct stmmac_priv));
if (!ndev) 
    return -ENOMEM;

// 配置网络设备的操作函数集
ndev->netdev_ops = &stmmac_netdev_ops;
SET_ETHTOOL_OPS(ndev, &stmmac_ethtool_ops);
ndev->base_addr = stmmac_res.addr;
ndev->irq = stmmac_res.irq;

// 执行驱动探测流程
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret) 
    goto err_free_netdev;

// 向系统注册网络设备
ret = register_netdev(ndev);
if (ret) 
    goto err_dvr_remove;

return 0;

err_dvr_remove:
    stmmac_dvr_remove(&pdev->dev);
err_free_netdev:
    free_netdev(ndev);
    return ret;
}

在 Linux 系统中,/sys/class/net/ 目录用于展示当前系统中存在的所有网络接口设备。该目录以类文件结构的方式暴露网络设备的属性和状态信息,便于用户空间程序进行读取与配置。

以下是 /sys/class/net/ 的典型目录结构示例:

/sys/class/net/
|
+---> eth0/                 [目录] (以太网设备0)
|     +---> address         [文件] (MAC地址: 00:11:22:33:44:55)
|     +---> addr_assign_type [文件] (地址分配类型)
|     +---> broadcast       [文件] (广播地址)
|     +---> carrier         [文件] (载波状态)
|     +---> dev_id          [文件] (设备ID)
|     +---> device/         [符号链接] -> ../../../10001000.ethernet
|     +---> dormant         [文件] (休眠状态)
|     +---> duplex          [文件] (双工模式)
|     +---> flags           [文件] (标志位)
|     +---> ifindex         [文件] (接口索引)
|     +---> iflink          [文件] (接口链接)
|     +---> mtu             [文件] (最大传输单元)
|     +---> name_assign_type [文件] (名称分配类型)
|     +---> netdev_group    [文件] (网络设备组)
|     +---> operstate       [文件] (操作状态)
|     +---> power/          [目录]
|     +---> proto_down      [文件] (协议关闭)
|     +---> queues/         [目录]
|     |     +---> rx-0/     [目录]
|     |     +---> tx-0/     [目录]
|     +---> speed           [文件] (连接速度)
|     +---> statistics/     [目录]
|     |     +---> rx_bytes  [文件]
|     |     +---> tx_bytes  [文件]
|     |     +---> rx_errors [文件]
|     |     +---> tx_errors [文件]
|     +---> subsystem/      [符号链接] -> ../../../../class/net
|     +---> tx_queue_len    [文件] (发送队列长度)
|     +---> type            [文件] (接口类型)
|     +---> uevent          [文件]
|
+---> wlan0/                [目录] (无线设备0)
|     +---> address         [文件]
|     +---> device/         [符号链接] -> ../../../mmc0:0001:1

每个子目录代表一个已注册的网络接口(如 eth0 表示第一个有线网卡,wlan0 表示第一个无线网卡)。目录中的各项内容提供了设备的硬件信息、运行状态、统计计数等关键参数,常被 ifconfig、ip、ethtool 等工具所使用。

通过读取这些虚拟文件,可以实时获取网络接口的状态变化,例如链路是否连通(carrier)、当前速率(speed)、双工模式(duplex)以及数据收发字节数(rx_bytes / tx_bytes)等。

第七层:输入设备驱动与/sys/class/input

机制功能
ARM64架构下的输入设备驱动在系统启动时完成初始化,并通过内核的输入子系统注册具体的输入设备。该过程使得触摸屏、按键等外设能够被操作系统识别并处理用户交互事件。

数据结构与大小
struct input_dev
(1KB):表示一个输入设备的核心数据结构,包含设备名称、总线类型、能力位图及关联的硬件参数。
struct input_handler
(400字节):描述输入处理器的相关信息,用于管理和分发来自输入设备的事件流。 源码关键函数与数据跳转 ARM64输入设备驱动示例(基于 edt-ft5x06 触摸控制器) 以下代码片段展示了 I2C 接口触摸屏驱动的 probe 函数实现,主要完成设备资源分配、输入能力配置和设备注册: // drivers/input/touchscreen/edt-ft5x06.c static int edt_ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct edt_ft5x06_ts_data *tsdata; struct input_dev *input; int error; // 动态分配输入设备结构 input = devm_input_allocate_device(&client->dev); if (!input) return -ENOMEM; // 设置设备基本信息 input->name = "edt-ft5x06"; input->id.bustype = BUS_I2C; input->dev.parent = &client->dev; // 配置支持的事件类型 __set_bit(EV_ABS, input->evbit); __set_bit(EV_KEY, input->evbit); __set_bit(BTN_TOUCH, input->keybit); // 设置多点触摸坐标参数 input_set_abs_params(input, ABS_MT_POSITION_X, 0, MAX_SUPPORT_POINTS, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, MAX_SUPPORT_POINTS, 0, 0); input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0); // 向输入子系统注册设备 error = input_register_device(input); if (error) { dev_err(&client->dev, "Failed to register input device: %d\n", error); return error; } return 0; } /sys/class/input/ 目录结构说明 此目录是 Linux 输入设备在 sysfs 中的统一展示路径,每个注册成功的输入设备都会在此生成对应子目录: /sys/class/input/ | +---> input0/ [目录] (编号为0的输入设备实例) | +---> capabilities/ [目录] | | +---> abs [文件] (绝对坐标能力描述) | | +---> key [文件] (按键事件支持情况) | | +---> rel [文件] (相对位移能力) | | +---> sw [文件] (开关类事件能力) | | | +---> device/ [符号链接] -> ../../../0-0038 (指向具体设备) | +---> id/ [目录] | | +---> bustype [文件] (总线类型标识) | | +---> product [文件] (产品ID) | | +---> vendor [文件] (厂商ID) | | +---> version [文件] (固件或驱动版本号) | | | +---> name [文件] (设备名称,如"edt-ft5x06") | +---> phys [文件] (物理连接路径) | +---> power/ [目录] (电源管理相关接口)
+---> subsystem/      [符号链接] -> ../../../../class/input
+---> uevent          [文件]

+---> input1/               [目录] (输入设备1)
|     +---> name            [文件] (设备名称: "gpio-keys")
|     +---> device/         [符号链接] -> ../../../gpio-keys
|     +---> capabilities/   [目录]
|     +---> id/             [目录]

+---> event0/               [目录] (输入事件0)
|     +---> dev             [文件] (主次设备号: 13:64)
|     +---> device/         [符号链接] -> ../input0
|     +---> power/          [目录]
|     +---> subsystem/      [符号链接] -> ../../../../class/input
|     +---> uevent          [文件]

+---> event1/               [目录] (输入事件1)
      +---> dev             [文件] (主次设备号: 13:65)
      +---> device/         [符号链接] -> ../input1
      +---> power/          [目录]
      +---> subsystem/      [符号链接] -> ../../../../class/input
      +---> uevent          [文件]

第三部分总结:数据流与跳转树形图

平台设备驱动注册过程启动后,依次进行多个核心外设子系统的初始化工作。整个流程如下:

  • 串口驱动初始化
    • 调用 pl011_probe() 函数(适用于 ARM64 架构的 PL011 串口控制器)
    • 在 /sys/class/tty/ 路径下创建对应的设备节点
    • 生成 tty 设备相关的属性文件
  • MMC/SD 驱动初始化
    • 执行 sdhci_arasan_probe() 初始化函数(用于 ARM64 的 MMC 控制器)
    • 在 /sys/class/mmc_host/ 目录中注册设备
    • 同时在 /sys/class/block/ 下建立块设备接口
    • 创建 SD 卡相关属性文件以支持用户空间访问
  • GPIO 驱动初始化
    • 触发 pl061_probe() 函数(针对 ARM64 GPIO 控制器)
    • 在 /sys/class/gpio/ 中创建设备条目
    • 提供 export/unexport 接口用于控制 GPIO 使能状态
    • 建立方向设置和电平值读写的属性文件
  • I2C 驱动初始化
    • 进入 dw_i2c_plat_probe() 函数(DesignWare I2C 控制器)
    • 在 /sys/bus/i2c/ 下注册设备信息
    • 创建适配器及从设备的属性节点
    • 完成 I2C 从设备的注册流程
  • SPI 驱动初始化
    • 调用 dw_spi_probe() 函数(DesignWare SPI 控制器)
    • 在 /sys/bus/spi/ 路径下创建设备结构
    • 生成控制器和外设的属性文件
    • 注册连接到该总线的 SPI 从设备
  • 网络驱动初始化
    • 运行 stmmac_pltfr_probe() 函数(以太网控制器驱动)
    • 在 /sys/class/net/ 中创建网络设备入口
    • 生成统计信息与配置参数的属性文件
  • 输入驱动初始化
    • 启动 edt_ft5x06_ts_probe()(触摸屏驱动探测函数)
    • 在 /sys/class/input/ 下建立输入设备节点
    • 设置输入设备的能力属性
    • 创建对应的 event 设备用于事件上报

第四部分:电源管理、热管理与系统监控

树根:电源管理子系统初始化

在系统启动过程中,init_main() 函数内调用 pm_init() 完成电源管理模块的初始化。

主要动作:

  • 完成电源管理框架的初始化
  • 构建 /sys/power/ 文件系统目录结构,供用户空间进行电源策略配置

第一层:CPUfreq 与 CPUIDLE 子系统

机制功能:
实现 ARM64 架构下的 CPU 频率调节(CPUfreq)以及处理器空闲状态管理(CPUIDLE),优化功耗与性能平衡。

关键数据结构及其大小:

struct cpufreq_policy

(800字节):表示 CPU 频率策略结构体(cpufreq_policy)
struct cpuidle_device

(400字节):描述 CPU 空闲设备(cpuidle_device)
struct cpuidle_driver

(300字节):定义 CPU 空闲驱动(cpuidle_driver)

源码关键函数与数据跳转:

ARM64 CPUfreq 初始化流程:
// drivers/cpufreq/arm_big_little.c

ARM64 CPUIDLE 初始化过程:

static int arm64_cpuidle_probe(struct platform_device *pdev) {
    struct cpuidle_driver *drv;
    int ret;

    // 分配用于CPU空闲的驱动结构
    drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
    if (!drv)
        return -ENOMEM;

    // 设置ARM64平台空闲驱动的基本信息
    drv->name = "arm64_idle";
    drv->owner = THIS_MODULE;

    // 定义第一个空闲状态:WFI(等待中断)
    drv->states[0].enter = arm64_enter_idle;
    drv->states[0].exit_latency = 1;
    drv->states[0].target_residency = 1;
    drv->states[0].power_usage = UINT_MAX;
    strcpy(drv->states[0].name, "WFI");
    strcpy(drv->states[0].desc, "ARM64 WFI state");

    // 定义第二个空闲状态:CPU挂起
    drv->states[1].enter = arm64_enter_idle;
    drv->states[1].exit_latency = 10;
    drv->states[1].target_residency = 100;
    drv->states[1].power_usage = UINT_MAX;
    strcpy(drv->states[1].name, "CPU_SUSPEND");
    strcpy(drv->states[1].desc, "ARM64 CPU suspend state");

    // 指定支持的空闲状态数量
    drv->state_count = 2;

    // 注册空闲驱动
    ret = cpuidle_register_driver(drv);
    if (ret)
        return ret;

    // 将设备注册到空闲框架中
    return cpuidle_register_device(&pdev->dev);
}
    
struct proc_info_list

big.LITTLE 架构下的 CPU 频率控制器初始化函数:

static int bL_cpufreq_probe(struct platform_device *pdev) {
    struct cpufreq_dt_platform_data *data = dev_get_platdata(&pdev->dev);
    int ret;

    // 初始化适用于 big.LITTLE 的频率调节驱动
    bL_cpufreq_driver = cpufreq_dt_platform_data;
    bL_cpufreq_driver.driver_data = data;

    // 向系统注册cpufreq驱动
    ret = cpufreq_register_driver(&bL_cpufreq_driver);
    if (ret) {
        dev_err(&pdev->dev, "failed to register cpufreq driver: %d\n", ret);
        return ret;
    }

    // 在sysfs中创建对应的属性文件节点
    ret = cpufreq_sysfs_create();
    if (ret) {
        cpufreq_unregister_driver(&bL_cpufreq_driver);
        return ret;
    }

    return 0;
}
    
struct machine_desc

/sys/devices/system/cpu/cpufreq/ 路径下的目录组织结构如下:

/sys/devices/system/cpu/cpufreq/
|
+---> policy0/                      [目录] (CPU频率调控策略0)
      +---> affected_cpus           [文件] (受此策略影响的CPU列表: 0)
      +---> cpuinfo_cur_freq        [文件] (当前运行频率: 1800000 kHz)
      +---> cpuinfo_max_freq        [文件] (硬件支持的最大频率: 2200000 kHz)
      +---> cpuinfo_min_freq        [文件] (硬件支持的最小频率: 600000 kHz)
      +---> cpuinfo_transition_latency [文件] (频率切换延迟时间)
      +---> related_cpus            [文件] (共享同一频率策略的CPU核心)
    
/sys/devices/system/cpu/cpuidle/
|
+---> current_driver        [文件] (当前空闲驱动: arm64_idle)
+---> current_governor_ro   [文件] (当前空闲调节器)
+---> available_governors   [文件] (可用空闲调节器)
|
+---> cpu0/                 [目录] (CPU0空闲状态)
|     +---> name            [文件] (CPU0名称)
|     +---> power/          [目录]
|     +---> subsystem/      [符号链接] -> ../../../../class/cpuidle
|
+---> cpu1/                 [目录] (CPU1空闲状态)

/sys/devices/system/cpu/cpu0/cpufreq/ 目录结构:
|
+---> policy0/              [目录] (CPU频率策略0)
|     +---> affected_cpus   [文件] (受影响的CPU: 0)
|     +---> scaling_available_governors [文件] (可用调节器)
|     +---> scaling_cur_freq [文件] (当前调节频率)
|     +---> scaling_driver  [文件] (频率驱动: arm_big_little)
|     +---> scaling_governor [文件] (当前调节器: interactive)
|     +---> scaling_max_freq [文件] (最大调节频率)
|     +---> scaling_min_freq [文件] (最小调节频率)
|     +---> scaling_setspeed [文件] (设置速度)
|
+---> policy1/              [目录] (CPU频率策略1)
      +---> affected_cpus   [文件] (受影响的CPU: 1)
      +---> ... (结构与policy0类似)

第二层:热管理子系统(Thermal)

机制功能:
实现对ARM64架构SoC的温度监控与动态热管理,确保系统在安全温度范围内运行。

数据结构与大小:
struct thermal_zone_device
(600字节):温区设备
struct thermal_cooling_device
(500字节):冷却设备
struct thermal_governor
(200字节):热管理调节器 源码关键函数与数据跳转: ARM64热管理初始化流程: // drivers/thermal/thermal_core.c static int __init thermal_init(void) { int result; // 创建并添加热管理类 thermal_class = kset_create_and_add("thermal", NULL, NULL); if (!thermal_class) return -ENOMEM; // 注册所有内置的热调节器 result = thermal_register_governors(); if (result) goto out_unregister_class; // 解析设备树并注册各个温区 result = of_thermal_register_thermal_zones(); if (result) goto out_unregister_governors; return 0; out_unregister_governors: thermal_unregister_governors(); out_unregister_class: kset_unregister(thermal_class); return result; } ARM64温区设备注册过程: // drivers/thermal/thermal_of.c int thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data, const struct thermal_zone_of_device_ops *ops) { struct device_node *np = dev->of_node; struct thermal_zone_device *tzd; // 通过设备树中的 phandle 获取传感器节点 np = of_parse_phandle(np, "thermal-sensors", sensor_id); if (!np) return -ENODEV; // 注册温区设备 tzd = thermal_zone_of_device_register(dev, sensor_id, data, ops);
if (IS_ERR(tzd)) return PTR_ERR(tzd);
thermal_zone_device_enable(tzd);
return 0;

sys/class/thermal 目录结构说明

Linux内核中的热管理子系统通过 sysfs 文件系统暴露接口,其根目录位于 /sys/class/thermal/。该目录下包含多个子目录和符号链接,分别对应不同的温区(thermal zones)与冷却设备(cooling devices),用于实时监控和调节设备温度。

  • thermal_zone0/ —— 温度区域0
    • temp:当前温度值,单位为毫摄氏度(例如:45000 表示 45°C)
    • type:温区类型标识,如 "soc_thermal"
    • mode:运行模式,可为 enabled 或 disabled
    • policy:当前启用的温控策略,例如 step_wise
    • available_policies:支持的所有策略列表
    • trip_point_0_temp:第一个触发点的温度阈值(如85000,即85°C)
    • trip_point_0_type:该触发点动作类型,如 critical(临界)
    • trip_point_1_temp:第二个触发点温度(如75000,即75°C)
    • trip_point_1_type:该触发点类型,如 passive(被动降温)
    • device/:指向具体硬件设备的符号链接,如 ../../../1000c000.thermal-sensor
    • power/:电源控制相关目录
    • subsystem/:指向 thermal 类的子系统链接
  • thermal_zone1/ —— 温度区域1
    • temp:当前温度,如 55000(55°C)
    • type:温区类型,如 "gpu_thermal"
    • 其余文件结构与 thermal_zone0 类似
  • cooling_device0/ —— 冷却设备0
    • cur_state:当前冷却状态,数值表示强度级别(如0)
    • max_state:最大可调状态值(如10)
    • type:冷却方式类型,如 "cpufreq"
    • device/:关联的底层设备链接,如 ../../../policy0
    • power/subsystem/:标准电源与类链接目录
  • cooling_device1/ —— 冷却设备1
    • cur_state:当前状态,如0
    • max_state:最大状态值,如3
    • type:设备类型,如 "fan"(风扇)
    • device/:指向实际硬件节点,如 ../../../10008000.fan

第三层:电源供应子系统(Power Supply)

电源供应子系统负责管理系统中各类电源设备,包括电池、AC适配器、USB电源等,提供统一的注册接口与用户空间交互机制。

主要功能

实现对电池电量、充电状态、电压电流、健康状况等信息的采集与上报,并支持动态响应充电事件或外部电源切换。

关键数据结构及其大小

struct power_supply

约600字节 —— 描述电源供应设备的核心结构体(如 struct power_supply)

struct power_supply_info

约300字节 —— 存储具体的电源信息字段(如电压、容量、状态等)

核心源码流程:电源供应类初始化

在内核启动阶段,调用以下函数完成电源供应类的创建:

// drivers/power/supply/power_supply_core.c
static int __init power_supply_class_init(void) {
    // 创建名为 "power_supply" 的设备类
    power_supply_class = class_create(THIS_MODULE, "power_supply");
    if (IS_ERR(power_supply_class))
        return PTR_ERR(power_supply_class);

    // 注册相关的属性文件,供用户空间读取
    // (后续代码会添加 device attributes)
}
// 初始化电源供应属性
power_supply_init_attrs();

// 执行电源供应系统的注册初始化
return power_supply_sysfs_init();

电池设备的探测与注册过程

在 Linux 内核的电源管理子系统中,电池设备通常通过 I2C 接口进行通信。以下代码展示了 bq27xxx 系列电池驱动在探测阶段完成的主要操作:

// 文件路径:drivers/power/supply/bq27xxx_battery.c

static int bq27xxx_battery_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct bq27xxx_device_info *di;
    struct power_supply_config psy_cfg = {};
    int ret;

    // 为设备信息结构体分配内存
    di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
    if (!di)
        return -ENOMEM;

    // 设置设备基本信息
    di->name = "bq27xxx-battery";
    di->dev = &client->dev;
    di->chip = id->driver_data;

    // 配置电源供应描述符
    di->desc.name = di->name;
    di->desc.type = POWER_SUPPLY_TYPE_BATTERY;
    di->desc.properties = bq27xxx_battery_props;
    di->desc.num_properties = ARRAY_SIZE(bq27xxx_battery_props);
    di->desc.get_property = bq27xxx_battery_get_property;
    di->desc.set_property = bq27xxx_battery_set_property;
    di->desc.property_is_writeable = bq27xxx_battery_property_is_writeable;

    // 向系统注册电池设备
    di->psy = power_supply_register(&client->dev, &di->desc, &psy_cfg);
    if (IS_ERR(di->psy)) {
        ret = PTR_ERR(di->psy);
        dev_err(&client->dev, "failed to register battery: %d\n", ret);
        return ret;
    }

    return 0;
}
struct proc_info_list

/sys/class/power_supply/ 目录结构说明

Linux 内核通过 sysfs 提供用户空间接口,用于查看和控制电源设备状态。该目录下包含各类电源设备的虚拟文件节点,每个文件对应一个可读或可写的属性值。

/sys/class/power_supply/
|
+---> battery/                  [目录] — 表示电池设备
|     +---> capacity            [文件] — 当前电量百分比(例如:85),单位为 %
|     +---> capacity_level      [文件] — 容量等级(如:Normal)
|     +---> current_now         [文件] — 实时电流值(如:-500000),负数表示放电,单位为微安 (μA)
|     +---> health              [文件] — 电池健康状况(如:Good)
|     +---> present             [文件] — 是否检测到电池(1 表示存在)
|     +---> status              [文件] — 充电状态(如:Discharging)
|     +---> technology          [文件] — 电池化学类型(如:Li-ion)
|     +---> temp                [文件] — 当前温度(如:320),单位为 0.1°C(即 32.0°C)
|     +---> type                [文件] — 设备类型(固定为 Battery)
|     +---> voltage_now         [文件] — 当前电压(如:3800000),单位为微伏 (μV)
|     +---> device/             [符号链接] — 指向底层硬件设备路径(如:../../../0-0055)
|     +---> power/              [目录] — 电源管理相关接口
|     +---> subsystem/          [符号链接] — 指向 power_supply 类定义位置
|
+---> ac/                       [目录] — 交流电源适配器设备

此结构允许用户通过标准文件操作(如 cat、echo)获取或修改电源相关信息,是用户空间与内核电源管理系统交互的重要通道。

/sys/devices/platform/gpio-charger/power/
|
+---> async                 [文件] (异步挂起: disabled)
+---> autosuspend_delay_ms  [文件] (自动挂起延迟: -1) [单位: 毫秒]
+---> control               [文件] (控制: on)
+---> runtime_active_time   [文件] (活动时间: 567890123) [单位: 纳秒]
+---> runtime_status        [文件] (运行时状态: active)
+---> runtime_suspended_time [文件] (挂起时间: 123456789) [单位: 纳秒]
+---> runtime_usage         [文件] (使用计数: 1)

struct dev_pm_info
/sys/devices/platform/1-001a/power/ | +---> async [文件] (异步挂起: enabled) +---> autosuspend_delay_ms [文件] (自动挂起延迟: 2000) [单位: 毫秒] +---> control [文件] (控制: auto) +---> runtime_active_time [文件] (活动时间: 456789012) [单位: 纳秒] +---> runtime_status [文件] (运行时状态: suspended) +---> runtime_suspended_time [文件] (挂起时间: 321098765) [单位: 纳秒] +---> runtime_usage [文件] (使用计数: 0)
struct dev_pm_domain
设备电源管理目录结构(整合示例): /sys/devices/platform/gpio-charger/power/ 和 /sys/devices/platform/1-001a/power/ 分别展示了不同设备在运行时电源管理下的状态信息。其中包含异步挂起设置、自动挂起延迟时间、控制策略、当前运行状态及累计活动与挂起时间等关键参数。 机制功能: 运行时电源管理(Runtime PM)用于在设备未被使用时自动将其挂起,以降低功耗,并在需要时恢复设备运行。该机制支持精细化的电源控制,适用于各类外设如串口、USB设备等。 数据结构大小说明: - 设备电源管理信息结构体占用约200字节; - 电源管理域结构体大小约为300字节。 源码关键函数与执行流程: 运行时PM子系统初始化: // drivers/base/power/runtime.c int __init pm_runtime_init(void) { // 创建用于电源管理事件等待的队列 init_waitqueue_head(&pm_wait_queue); // 建立可冻结且具备内存回收属性的工作队列 pm_wq = alloc_workqueue("pm", WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); if (!pm_wq) return -ENOMEM; return 0; } 设备级运行时PM初始化操作: // drivers/base/power/runtime.c void pm_runtime_init(struct device *dev) { // 初始状态设为已挂起 dev->power.runtime_status = RPM_SUSPENDED; // 关闭空闲通知标志 dev->power.idle_notification = false; // 禁用深度计数初始值为1,防止意外挂起 dev->power.disable_depth = 1; // 清除错误状态 dev->power.runtime_error = 0; // 自动挂起延迟未启用 dev->power.autosuspend_delay = -1; // 记录最后一次活跃时间戳 dev->power.last_busy = ktime_get_mono_fast_ns(); // 设置统计起始时刻 dev->power.accounting_timestamp = jiffies; // 配置定时器用于挂起超时处理 timer_setup(&dev->power.suspend_timer, pm_suspend_timer_fn, 0); // 初始化工作项用于异步执行电源状态切换 INIT_WORK(&dev->power.work, pm_runtime_work); } 第五层:系统挂起与恢复(Suspend/Resume) 机制功能: 实现整个系统的低功耗挂起以及后续唤醒恢复功能,涵盖设备冻结、上下文保存、CPU停机和硬件唤醒响应等全过程。 数据结构与内存占用:
struct platform_suspend_ops
(300字节):平台相关的挂起操作结构体
struct platform_freeze_ops
(200字节):平台冻结操作的数据结构 源码关键函数跳转点: ARM64架构下的系统挂起操作注册入口:
static const struct platform_suspend_ops arm64_suspend_ops = {
    .enter = arm64_suspend_enter,
    .valid = suspend_valid_only_mem,
};

static int __init arm64_pm_init(void) {
    // 注册ARM64平台的挂起操作函数集
    suspend_set_ops(&arm64_suspend_ops);
    // 在 /sys/power 路径下创建用于控制内存睡眠模式的属性文件
    return sysfs_create_file(power_kobj, &dev_attr_mem_sleep.attr);
}
arch_initcall(arm64_pm_init);

struct kernel_stat
static int arm64_suspend_enter(suspend_state_t state) { int ret; // 调用 cpu_suspend 进入低功耗状态,指定恢复后执行的完成函数 ret = cpu_suspend(0, arm64_suspend_finisher); if (ret) return ret; // 验证当前CPU是否仍在在线状态,若已离线则说明挂起失败 if (!cpu_online(smp_processor_id())) { pr_crit("Failed to suspend system\n"); return -EINVAL; } return 0; }
struct vm_event_state
/sys/power/ 文件系统结构说明: 该目录是用户空间与内核电源管理机制交互的核心接口,主要包含以下条目: - state 控制系统的电源状态切换(如:mem、standby、disk) - disk 指定休眠后的行为模式(可选:platform、shutdown、reboot等) - pm_test 启用不同层级的电源管理测试(none/core/processors/device/platform) - wakeup_count 显示或等待特定数量的唤醒事件 - wake_lock 创建命名唤醒锁,防止系统挂起 - wake_unlock 释放对应的唤醒锁 - mem_sleep 配置内存睡眠深度(支持 s2idle、shallow、deep 模式) - image_size 设置生成的休眠镜像大小 - resume 指定从休眠恢复时使用的块设备 - pm_trace 启用电源管理过程中的异常跟踪 - pm_trace_dev_match 记录最后唤醒系统的设备信息 - pm_print_times 输出每次挂起和恢复操作所消耗的时间 - pm_async 开启异步设备挂起功能 第六层:系统监控与资源统计机制 功能概述: 提供对系统运行时性能指标和资源使用情况的持续监控能力。通过虚拟文件系统暴露关键统计数据,便于调试与性能分析。 相关数据结构大小信息: - 内核级统计信息结构体:约占用 1KB 空间 - VM 子系统事件计数器状态:约占 400 字节 核心初始化流程: // kernel/fs/proc/stat.c static int __init proc_stat_init(void) { // 在 /proc 文件系统中注册 stat 接口,供用户读取全局统计 proc_create("stat", 0, NULL, &proc_stat_operations); // 在 debugfs 中建立 stat 调试目录,用于扩展监控功能 debugfs_create_dir("stat", NULL); return 0; } fs_initcall(proc_stat_init); /sys/kernel/debug/ 下的监控子系统布局: 此路径为开发者提供了深入观测内核行为的能力,特别是跟踪机制的相关内容: /sys/kernel/debug/ | +---> tracing/ [目录] (ftrace 跟踪框架主目录) +---> trace [文件] (当前跟踪缓冲区内容) +---> trace_pipe [文件] (实时流式跟踪输出) +---> current_tracer [文件] (当前激活的跟踪器名称) +---> available_tracers [文件] (支持的所有跟踪器列表) +---> events/ [目录] (可跟踪事件的配置与开关)
+---> pmc/                  [目录] (性能监控计数器)
|     +---> cpu0/           [目录]
|     |     +---> instructions [文件] (指令计数)
|     |     +---> cycles    [文件] (CPU周期计数)
|     |     +---> cache-misses [文件] (缓存未命中)
|     +---> cpu1/
|
+---> wakeup_sources        [文件] (唤醒源信息)
+---> suspend_stats         [文件] (挂起统计)
+---> regmap/               [目录] (寄存器映射调试)
|     +---> 10000000.serial/ [目录]
|     |     +---> registers [文件] (串口寄存器)
|
+---> dynamic_debug/        [目录] (动态调试控制)
|     +---> control         [文件] (调试控制)
|
+---> block/                [目录] (块设备调试)
|     +---> mmcblk0/        [目录]
|     |     +---> queue/    [目录]
|     |     |     +---> scheduler [文件] (调度器)
|     |     |     +---> nr_requests [文件] (请求数)
|
+---> gpio                  [文件] (GPIO状态)
|
+---> sched/                [目录] (调度事件)
+---> irq/                  [目录] (中断事件)
+---> power/                [目录] (电源事件)

第七层:ARM64架构下的电源管理机制

该层级主要实现针对ARM64平台的电源状态控制与管理功能,通过标准化接口协调系统在不同功耗模式间的切换,确保低功耗运行的同时维持核心功能的可恢复性。

关键数据结构及其内存占用

struct arm64_cpu_capabilities

(200字节) 描述ARM64 CPU的能力信息,包括支持的电源操作和特性位。

struct psci_operations

(150字节) 表示PSCI(Power State Coordination Interface)相关操作的数据结构,用于跨固件与操作系统协作进行电源控制。

核心源码逻辑与函数调用流程

ARM64平台PSCI模块初始化过程

位于 drivers/firmware/psci/psci.c 中的初始化函数负责探测并配置PSCI服务:

static int __init psci_init(void) {
    // 查询并适配PSCI规范版本
    psci_0_1_init();
    // 获取底层PSCI操作集
    psci_ops = get_psci_ops();
    // 绑定CPU挂起处理函数
    cpu_suspend = psci_cpu_suspend;
    cpu_ops[cpu]->cpu_suspend = psci_cpu_suspend;
    return 0;
}

CPU挂起操作的具体实现

实现在 arch/arm64/kernel/suspend.c 文件中,完成上下文保存与用户回调执行:

int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) {
    struct sleep_stack_data state;
    int ret;

    // 进入挂起前保存当前CPU上下文
    ret = __cpu_suspend_enter(&state);
    if (!ret) {
        // 执行指定的挂起动作
        ret = fn(arg);
        // 恢复CPU运行环境
        __cpu_suspend_exit();
    }
    return ret;
}

ARM64空闲状态目录结构示例

路径:/sys/devices/system/cpu/cpu0/cpuidle/

+---> state0/               [目录] (空闲状态0)
|     +---> name            [文件] (状态名称: "WFI")
|     +---> desc            [文件] (状态描述: "ARM64 WFI state")
|     +---> disable         [文件] (是否禁用: 0)
|     +---> latency         [文件] (退出延迟: 1) [单位: 微秒]
|     +---> power           [文件] (功耗: 4294967295)
|     +---> residency       [文件] (目标驻留时间: 1) [单位: 微秒]
|     +---> time            [文件] (总时间: 123456789)
第四部分总结(数据流与跳转树形图):

电源管理子系统初始化
|
v
CPUfreq子系统
-> bL_cpufreq_probe() [ARM64 big.LITTLE]
-> 在/sys/devices/system/cpu/cpufreq/创建策略目录
-> 创建频率调节器和统计属性
|
v
CPUIDLE子系统
-> arm64_cpuidle_probe() [ARM64空闲状态]
-> 在/sys/devices/system/cpu/cpuidle/创建设备
-> 创建空闲状态和统计属性
|
v
热管理子系统
-> thermal_init() [热管理核心]
-> 在/sys/class/thermal/创建温区和冷却设备
-> 创建温度监控和热策略属性
|
v
电源供应子系统
-> power_supply_class_init() [电源供应类]
-> 在/sys/class/power_supply/创建设备
-> 创建电池和电源适配器属性
|
v
运行时电源管理
-> pm_runtime_init() [运行时PM核心]
-> 在每个设备下创建power/目录
-> 创建运行时状态和控制属性
|
v
系统挂起恢复
-> arm64_pm_init() [ARM64挂起操作]
-> 在/sys/power/创建状态控制文件
-> 注册ARM64特定挂起函数
|
v
系统监控统计
-> proc_stat_init() [系统统计]
-> 在/sys/kernel/debug/创建监控目录
-> 创建性能计数器和跟踪接口
|
v
ARM64特定电源状态
-> psci_init() [PSCI固件接口]
-> 实现ARM64 CPU挂起和恢复
-> 创建CPU空闲状态属性

第五部分:系统完全运行与用户空间交互

树根:用户空间初始化完成
1. 系统启动完成后进入多用户运行级别
|
+---> 用户登录,应用程序开始通过sysfs与内核进行交互

第一层:udev设备节点管理

机制功能:
基于sysfs提供的设备信息,动态生成相应的设备节点。

数据结构与大小:
struct udev_device
(300字节):udev设备
struct udev_rules
(500字节):udev规则 源码关键函数与数据跳转(systemd-udev): udev事件处理流程: // systemd/src/udev/udevd.c static int event_process(struct event *event) { struct udev_device *dev = NULL; int r; // 从sysfs路径构建设备对象 dev = udev_device_new_from_syspath(event->udev, event->devpath); if (!dev) { log_error("Failed to create device from syspath '%s'", event->devpath); return -ENODEV; } // 执行udev规则匹配与应用 r = udev_rules_apply(event->udev, dev); if (r < 0) { log_error("Failed to apply rules for device '%s'", event->devpath); goto cleanup; } // 添加设备节点到文件系统 r = udev_node_add(dev); if (r < 0) {
// systemd/src/udev/udev-device.c
const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) {
    char filename[UTIL_PATH_SIZE];
    char *value = NULL;
    FILE *f;

    // 构造对应设备在sysfs中的属性文件路径
    snprintf(filename, sizeof(filename), "%s/%s", udev_device->devpath, sysattr);

    // 打开并读取该属性文件的内容
    f = fopen(filename, "re");
    if (!f) return NULL;
    value = fread_string(f, NULL);
    fclose(f);
    return value;
}

log_error("Failed to create node for device '%s'", event->devpath);
goto cleanup;

cleanup:
    udev_device_unref(dev);
    return r;

udev 规则配置示例(位于 /etc/udev/rules.d/)

# 针对串口设备的匹配规则 SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", SYMLINK+="ttyArduino" # 网络接口添加时的命名规则 SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="00:11:22:33:44:55", NAME="eth_primary" # GPIO控制器检测到时执行脚本记录信息 SUBSYSTEM=="gpio", KERNEL=="gpiochip*", PROGRAM="/bin/sh -c 'echo gpiochip%n > /tmp/gpio_chips'" # 存储块设备分区创建符号链接 SUBSYSTEM=="block", KERNEL=="mmcblk0p1", SYMLINK+="boot_partition"

第二层:systemd 服务与 sysfs 的集成机制

systemd 利用 sysfs 文件系统实现对底层硬件状态的监控和响应控制。通过监听设备路径变化,触发相应的服务单元运行或配置调整。

struct unit
(500字节):systemd单元
struct service
(400字节):服务单元

核心源码逻辑与函数跳转(来自 systemd)

// systemd/src/core/device.c
static int device_setup_unit(Device *d) {
    Unit *u;
    int r;

    // 根据设备的 sysfs 路径初始化一个新的设备单元
    u = unit_new(&d->manager->unit_cache, sizeof(Device));
    if (!u) return -ENOMEM;

    // 设置设备对应的 sysfs 路径及所属子系统
    device_set_syspath(d, d->syspath);
    device_set_subsystem(d, d->subsystem);

    // 激活与此设备相关联的服务单元
    r = device_trigger_units(d);
    if (r < 0) return r;

    return 0;
}
// systemd/src/core/path.c
static int path_arm_timer(Path *p) {
    struct inotify_event *e;
    int r;

    // 向 inotify 添加监控,追踪指定 sysfs 目录的创建、删除和修改事件
    r = inotify_add_watch(p->inotify_fd, p->directory, IN_CREATE|IN_DELETE|IN_MODIFY);
    if (r < 0) return -errno;

    // 注册一个基于时间的事件处理器,用于周期性检查路径状态
    r = sd_event_add_time(p->manager->event, &p->timer_event,
                          CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + p->interval,
                          p->accuracy, path_timer_handler, p);
    return r;
}

systemd 服务单元文件示例

# /etc/systemd/system/gpio-service.service [Unit] Description=GPIO Control Service After=sys-devices-platform-gpio.device Requires=sys-devices-platform-gpio.device

[Service]
Type=exec
ExecStart=/usr/bin/gpio-control
Environment=SYSFS_GPIO_PATH=/sys/class/gpio
WatchdogSec=30
[Install]
WantedBy=multi-user.target

第三层:应用程序与sysfs的交互机制

用户空间中的应用程序通过sysfs接口实现与内核的数据通信。该机制允许应用在无需直接调用系统调用的情况下,对硬件设备进行配置和状态读取。

数据结构及其内存占用

  • 文件描述符:每个打开的sysfs文件对应一个4字节的整型值。
  • 数据缓冲区:大小可变,用于临时存储读写的数据内容。

典型的应用访问模式

GPIO控制程序示例

以下代码展示了如何在用户空间中通过sysfs导出并设置GPIO引脚的方向:

// 用户空间GPIO控制 #include <stdio.h> #include <fcntl.h> #include <unistd.h> int gpio_export(int pin) { int fd, len; char buf[16]; // 打开export文件 fd = open("/sys/class/gpio/export", O_WRONLY); if (fd < 0) return -1; // 写入GPIO编号 len = snprintf(buf, sizeof(buf), "%d", pin); write(fd, buf, len); close(fd); return 0; } int gpio_set_direction(int pin, const char *direction) { char path[64]; int fd; // 构建方向文件路径 snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin); fd = open(path, O_WRONLY); if (fd < 0) return -1; write(fd, direction, strlen(direction)); close(fd); return 0; }
LED亮度调节应用

通过sysfs接口可以动态调整LED的亮度级别:

// LED亮度控制 int led_set_brightness(const char *led_name, int brightness) { char path[128]; char buf[16]; int fd; // 构建亮度文件路径 snprintf(path, sizeof(path), "/sys/class/leds/%s/brightness", led_name); fd = open(path, O_WRONLY); if (fd < 0) return -1; snprintf(buf, sizeof(buf), "%d", brightness); write(fd, buf, strlen(buf)); close(fd); return 0; }

sysfs在用户空间的访问行为统计

对/sys目录下的操作主要分为读取与写入两大类:

  • 读取操作(约占总访问量的60%)
    • 查询设备运行状态(如温度、电压、频率等)
    • 获取配置信息(包括设备能力、固件版本等)
    • 收集统计信息(性能计数器、错误日志等)
  • 写入操作(约占总访问量的40%)
    • 执行设备控制命令(如操作GPIO、LED、风扇等)
    • 修改系统配置参数(如调整频率、电压、工作模式)
    • 设置运行状态(如电源管理、设备使能/禁用)

第四层:性能监控工具与sysfs的集成

系统级监控工具利用sysfs提供的标准化接口来采集底层硬件和内核的性能指标,从而实现资源使用情况的可视化与分析。

涉及的数据结构及大小

  • 性能数据结构:根据具体设备类型而定,大小可变。
  • 统计计数器:每个计数器占用8字节,通常为无符号长整型。

常见工具集成案例 —— sysstat

sysstat是一套广泛使用的系统性能监控工具集,其核心组件通过解析/proc和/sys文件系统获取CPU、I/O等关键指标。

// sysstat数据收集 int read_cpu_stat(struct stats_cpu *st_cpu) { FILE *fp; char line[1024]; // 读取/proc/stat fp = fopen("/proc/stat", "r"); if (!fp) return -1; while (fgets(line, sizeof(line), fp)) { if (strncmp(line, "cpu ", 4) == 0) { sscanf(line + 4, "%llu %llu %llu %llu %llu %llu %llu %llu", &st_cpu->cpu_user, &st_cpu->cpu_nice, &st_cpu->cpu_sys, &st_cpu->cpu_idle, &st_cpu->cpu_iowait, &st_cpu->cpu_steal,
struct proc_info_list
); } } fclose(fp); return 0; }
// 传感器数据读取函数
int read_thermal_data(void) {
    DIR *dir;
    struct dirent *entry;
    char path[256];
    FILE *fp;
    int temp;

    // 打开 thermal 类别目录以扫描温度区域
    dir = opendir("/sys/class/thermal");
    if (!dir) return -1;

    while ((entry = readdir(dir))) {
        // 匹配名称以 thermal_zone 开头的子项
        if (strncmp(entry->d_name, "thermal_zone", 12) == 0) {
            // 构建具体温度文件路径
            snprintf(path, sizeof(path),
                     "/sys/class/thermal/%s/temp", entry->d_name);
            fp = fopen(path, "r");
            if (fp) {
                fscanf(fp, "%d", &temp);
                fclose(fp);
                // 输出当前区域温度,单位转换为摄氏度
                printf("Zone %s: %d°C\n", entry->d_name, temp / 1000);
            }
        }
    }
    closedir(dir);
    return 0;
}

// CPU中断统计读取代码段
fclose(fp);
return 0;
}

性能监控体系结构

内核空间采集的性能指标

通过 sysfs 和 procfs 接口暴露数据

用户态监控工具链处理数据:

  • sysstat — 提供系统级统计信息
  • lm-sensors — 实现硬件健康状态监测
  • perf — 进行深度性能剖析
  • iostat — 分析输入输出设备负载
  • mpstat — 统计多核CPU使用情况

数据整合与应用阶段:

  • 实时动态监控界面展示
  • 长期历史数据归档存储
  • 异常阈值触发告警机制
  • 资源调度优化建议生成

第五层:调试与故障诊断支持

核心功能说明: 开发人员及系统管理员可借助 sysfs 接口实现运行时系统行为观察与问题排查。

关键数据结构及其容量范围:

  • 调试缓冲区大小:介于 4KB 至 64KB 之间
  • 跟踪日志数据:根据配置动态调整占用空间

ftrace 跟踪机制使用示例

# 启动函数调用轨迹记录
echo 1 > /sys/kernel/debug/tracing/tracing_on
echo function > /sys/kernel/debug/tracing/current_tracer
echo "gpio_*" > /sys/kernel/debug/tracing/set_ftrace_filter

# 导出跟踪结果到日志文件
cat /sys/kernel/debug/tracing/trace > /tmp/trace.log

动态调试功能启用方式

# 开启特定驱动源码文件的调试输出
echo 'file gpio_pl061.c +p' > /sys/kernel/debug/dynamic_debug/control
echo 'file irq_chip.c +p' > /sys/kernel/debug/dynamic_debug/control

GPIO 相关调试操作命令

# 查看当前所有 GPIO 引脚状态
cat /sys/kernel/debug/gpio

# 每隔一秒刷新一次 GPIO 状态变化
watch -n 1 cat /sys/kernel/debug/gpio

调试数据流动路径

内核预设的调试触发点

debugfs 与 tracefs 文件系统接口暴露数据

各类调试工具访问原始信息:

  • ftrace — 函数级执行流追踪
  • perf — 性能事件采样分析
  • systemtap — 动态探针注入检测
  • crash — 内核崩溃后内存分析

最终实现的问题定位与修复方向:

  • 识别系统性能瓶颈环节
  • 检测线程死锁或竞争条件
  • 发现并定位内存泄漏源头
  • 辅助判断硬件模块故障原因

第六层:容器化与虚拟化环境集成

作用机制描述: 在容器和虚拟机环境中,通过 sysfs 接口完成对物理设备的状态查询与控制管理。

主要数据结构及典型尺寸:

struct cgroup
(1KB):用于控制组(cgroup)配置信息
struct namespace
(400字节):命名空间相关元数据

Docker 容器中设备访问配置

# docker-compose.yml 中设备映射设置
version: '3'
services:
  gpio-app:
    image: arm64-gpio-app
    devices:
      - "/dev/gpiochip0:/dev/gpiochip0"
    volumes:
      - "/sys/class/gpio:/sys/class/gpio:ro"
    privileged: true

Kubernetes 设备插件配置示例

# Kubernetes Pod 配置文件片段
apiVersion: v1
kind: Pod
metadata:
  name: gpio-pod
spec:
  containers:
    - name: gpio-container
      image: arm64-gpio-app
      resources:
        limits:
static int vfio_platform_realize(DeviceState *dev, Error **errp) {
    VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev);
    char *syspath = g_strdup_printf("/sys/bus/platform/devices/%s", vdev->compat);

    // 通过sysfs接口查找指定设备
    if (access(syspath, F_OK) < 0) {
        error_setg(errp, "Device %s not found in sysfs", vdev->compat);
        g_free(syspath);
        return -ENODEV;
    }

    // 初始化并配置VFIO平台设备的透传功能
    vfio_setup_device(vdev, syspath);
    g_free(syspath);
    return 0;
}

apiVersion: v1
kind: Pod
spec:
  nodeSelector:
    kubernetes.io/arch: arm64

第七层:安全与访问控制

机制功能:实现对 sysfs 文件系统的访问权限管理与安全策略控制,确保系统资源不被未授权访问或修改。

数据结构与内存占用

  • struct inode
    —— 索引节点(约 600 字节)
  • struct dentry
    —— 目录项(约 200 字节)

文件系统权限模型

/sys/ 目录下的典型权限设置如下:

+---> /sys/devices/ (0755)
|     +---> 设备目录 (0755)
|     +---> 属性文件 (0644 或 0444,只读属性为 0444)
|     +---> power/ 子目录中的控制文件 (0644,需特权写入)

+---> /sys/class/ (0755)
|     +---> 各类设备目录 (0755)
|     +---> 设备相关属性文件 (0644)

+---> /sys/bus/ (0755)
|     +---> 总线设备目录 (0755)
|     +---> 驱动程序目录 (0755)

+---> /sys/kernel/ (0755)
|     +---> debug/ 调试接口目录 (0755,通常需显式挂载debugfs)
|     +---> security/ 安全模块接口 (0755)

+---> /sys/power/ (0755)
      +---> state 文件 (0644,写操作仅限 root 权限)

SELinux 安全策略配置

针对 sysfs 的强制访问控制规则示例:

type sysfs_t;
type sysfs_device_t;

# 允许普通用户空间进程读取 sysfs 基本信息
allow user_t sysfs_t:dir { search read };
allow user_t sysfs_device_t:file { read getattr };

# 屏蔽对电源和调试接口的非必要审计日志(降低日志噪音)
dontaudit user_t sysfs_power_t:file write;
dontaudit user_t sysfs_debug_t:dir search;

# 授权初始化及系统服务进程进行写操作
allow init_t sysfs_t:file write;
allow systemd_t sysfs_power_t:file write;

内核级访问权限校验实现

位于 fs/sysfs/file.c 中的核心权限检查函数:

static int sysfs_perm(struct inode *inode, int mask) {
    struct kobject *kobj = sysfs_get_kobject(inode);
    const struct sysfs_ops *ops;
    umode_t mode;
    int error;

    if (!kobj) return -EINVAL;

    ops = kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
    if (!ops) {
        error = -EINVAL;
        goto out;
    }

    mode = inode->i_mode;

    // 写权限检测:若请求写且无写位,则拒绝
    if ((mask & MAY_WRITE) && !(mode & S_IWUSR)) {
        error = -EACCES;
        goto out;
    }

    // 读权限检测:若请求读且无读位,则拒绝
    if ((mask & MAY_READ) && !(mode & S_IRUSR)) {
        error = -EACCES;
        goto out;
    }

    error = 0;
out:
    kobject_put(kobj);
    return error;
}

第八层:sysfs 性能优化

机制功能:提升 sysfs 在高并发访问、大量设备注册场景下的响应效率与内存使用效能,减少用户态与内核态交互开销。

性能优化策略与数据结构分析

在 sysfs 的实现中,合理的数据结构设计和内存使用对整体性能有显著影响。每个 kernfs 节点占用约 300 字节,而打开的文件结构体大小约为 400 字节,构成了 sysfs 文件系统的基本运行单元。

struct kernfs_node

kernfs 节点作为核心数据结构之一,支撑着 sysfs 的层级组织形式。同时,打开文件结构则用于维护当前活动的文件操作状态。

struct kernfs_open_file

属性缓存机制优化

为了减少重复读取开销,sysfs 在文件读取过程中引入了属性缓存策略。以下代码展示了二进制属性读取时如何利用缓存提升性能:

// fs/sysfs/file.c - 属性缓存
static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
size_t count, loff_t pos) {
struct bin_attribute *battr = of->kn->priv;
struct kobject *kobj = of->kn->parent->priv;
void *base;

// 首次读取时调用驱动提供的 read 函数并缓存结果
if (pos == 0) {
base = battr->read(kobj, battr, buf);
if (IS_ERR(base)) return PTR_ERR(base);
of->priv = base;  // 缓存数据指针
} else {
base = of->priv;  // 后续读取直接使用缓存
}

return memory_read_from_buffer(buf, count, &pos, base, battr->size);
}

该机制有效避免了每次读取都触发底层硬件访问或复杂计算,显著降低延迟。

批量属性操作支持

针对多属性访问场景,可通过批量读取接口减少路径解析和系统调用开销:

int read_multiple_attrs(struct kobject *kobj, const char **attrs,
char **values, int num_attrs) {
int i, ret;
char *path;

for (i = 0; i < num_attrs; i++) {
path = kasprintf(GFP_KERNEL, "%s/%s",
kobject_name(kobj), attrs[i]);
if (!path) return -ENOMEM;

ret = sysfs_read_file(path, &values[i]);
if (ret) {
kfree(path);
return ret;
}
kfree(path);
}
return 0;
}

此方法适用于需要集中获取设备多个配置项或状态信息的应用场景,提升整体 I/O 效率。

sysfs 性能监控关键指标

  • 读取延迟
    • 简单属性:低于 10 微秒
    • 复杂属性:10 至 100 微秒
    • 二进制属性:100 至 1000 微秒
  • 写入延迟
    • 简单设置:低于 20 微秒
    • 复杂操作:20 至 200 微秒
  • 并发访问能力
    • 最大并发读取:超过 1000
    • 最大并发写入:超过 100
  • 内存使用情况
    • 每个属性文件:1–4 KB
    • 每个目录节点:4–16 KB
    • 整个 sysfs 内存占用:10–100 MB

系统运行时的数据流与模块交互图

在系统完全运行状态下,sysfs 作为内核与用户空间的重要桥梁,参与多个关键流程:

  1. udev 设备管理
    • 监听 sysfs 中的设备事件
    • 执行预定义 udev 规则
    • 动态创建设备节点
    • 设置适当的设备权限
  2. systemd 服务集成
    • 基于设备状态触发服务启动
    • 监控特定 sysfs 路径变化
    • 管理系统服务依赖关系
    • 与 cgroup 进行资源联动控制
  3. 应用程序交互
    • 实现 GPIO 和 LED 控制
    • 读取传感器实时数据
    • 进行电源管理模式切换
    • 访问性能监控接口
  4. 性能监控工具链
    • 通过 sysstat 收集系统统计信息
    • 利用 lm-sensors 监控硬件温度与电压
    • 结合 perf 工具进行性能剖析
    • 支持实时系统状态监控
  5. 调试与诊断功能
    • 启用 ftrace 进行函数级跟踪
    • 动态调整内核调试级别
    • 检查 GPIO 当前电平状态
    • 辅助定位系统异常问题
  6. 容器与虚拟化集成
    • Docker 利用设备映射暴露硬件
    • Kubernetes 使用设备插件管理加速器
    • QEMU 实现设备透传给虚拟机
    • 统一管理虚拟化环境下的设备资源
  7. 安全访问控制机制
    • 基于传统文件权限模型进行访问限制
    • 集成 SELinux 安全策略
    • 执行细粒度权限校验
    • 生成安全审计日志记录
  8. 性能优化策略实施
    • 启用属性值缓存机制
    • 优化批量属性操作路径
    • 控制高并发访问行为
    • 精简内存分配与使用

系统关闭与资源回收流程

当系统进入关机流程时,由用户发起的关机命令将触发一系列有序的清理动作。

树根:系统关闭触发

常见用户空间关机指令包括:shutdownpoweroffsystemctl poweroffinit 0

第一层:关机信号传递与处理

关机信号从用户空间传入内核,正式启动系统停机流程,确保各子系统有机会完成资源释放和状态保存。

struct reboot_notifier_list

内核维护一个重启通知列表,用于登记需在关机前执行回调的模块。

struct sys_off_handler
// kernel/reboot.c
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)
{
    struct pid_namespace *pid_ns = task_active_pid_ns(current);
    char buffer[256];
    int ret = 0;

    if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
        return -EPERM;

    if (magic1 != LINUX_REBOOT_MAGIC1 ||
        (magic2 != LINUX_REBOOT_MAGIC2 &&
         magic2 != LINUX_REBOOT_MAGIC2A &&
         magic2 != LINUX_REBOOT_MAGIC2B &&
         magic2 != LINUX_REBOOT_MAGIC2C))
        return -EINVAL;

    switch (cmd) {
    case LINUX_REBOOT_CMD_POWER_OFF:
        kernel_power_off();
        break;
    case LINUX_REBOOT_CMD_RESTART:
        kernel_restart(buffer);
        break;
    case LINUX_REBOOT_CMD_HALT:
        kernel_halt();
        break;
    default:
        ret = -EINVAL;
        break;
    }

    return ret;
}

关机系统调用处理:
该系统调用负责处理用户空间发起的重启、关机或停机操作。首先进行权限校验,确保调用进程具备CAP_SYS_BOOT能力。随后验证传入的“魔数”是否匹配预定义常量,以防止误操作。根据命令类型,分别触发内核级别的关机、重启或 halt 操作。

struct device
// arch/arm64/kernel/process.c void machine_power_off(void) { blocking_notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); arm64_pm_cleanup(); if (pm_power_off) pm_power_off(); } ARM64特定关机准备: 在ARM64架构下,关机前需执行一系列平台相关清理工作。函数首先通知所有注册在重启通知链上的子系统即将进入断电状态,然后调用ARM64专用的电源管理清理例程,最后尝试调用由平台提供的关机回调函数(pm_power_off),实现硬件层面的断电控制。 设备驱动关闭顺序机制功能: 系统在关机过程中按照设备之间的依赖关系逆序关闭设备驱动,确保父设备不会在子设备仍运行时被提前关闭,从而避免资源访问异常或数据损坏。
struct device_link
// drivers/base/core.c static void __device_release_driver(struct device *dev, struct device *parent) { struct device_driver *drv; drv = dev->driver; if (drv) { if (drv->shutdown) drv->shutdown(dev); if (drv->remove) drv->remove(dev); device_remove_file(dev, &dev_attr_uevent); device_remove_groups(dev, drv->dev_groups); driver_sysfs_remove(dev); dev->driver = NULL; } } 设备关闭回调: 此函数用于解绑设备与其驱动程序,并依次调用驱动的 shutdown 和 remove 回调函数,完成设备的最后清理动作。同时移除sysfs中对应的属性文件和组信息,解除系统模型中的链接关系,确保设备状态完全释放。 // drivers/of/platform.c void of_platform_depopulate(struct device *parent) { struct device *dev, *tmp; struct device_node *np; list_for_each_entry_safe_reverse(&parent->kobj.children, dev, tmp, kobj.entry) { np = dev->of_node; if (np && of_node_check_flag(np, OF_POPULATED)) { of_platform_device_destroy(dev, NULL); } } } 设备树顺序关闭: 基于设备树构建的平台设备,在关机时需按启动顺序的逆序进行销毁。通过遍历父设备的子设备链表(反向),逐个判断其是否由设备树动态生成,若是则调用销毁接口释放对应资源,保证设备卸载顺序符合依赖层级。 设备关闭序列(逆启动顺序): +---> 1. 用户空间设备 +---> 输入设备(键盘、鼠标、触摸屏) +---> 音频设备 +---> 显示设备

第三层:sysfs属性清理

机制功能:负责清除sysfs文件系统中的设备属性及相关目录结构,确保设备注销时相关节点被正确移除。

数据结构与大小:

  • struct kernfs_node
    (300字节):kernfs节点
  • struct attribute
    (40字节):属性结构

源码关键函数与数据跳转

属性组清理:

// fs/sysfs/group.c
void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)
{
    struct kernfs_node *kn = kobj->sd;
    struct attribute *const *attr;

    // 移除属性组中定义的每个普通属性
    if (grp->attrs) {
        for (attr = grp->attrs; *attr; attr++) {
            kernfs_remove_by_name(kn, (*attr)->name);
        }
    }

    // 清理二进制属性项
    if (grp->bin_attrs) {
        struct bin_attribute *const *bin_attr;
        for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
            kernfs_remove_by_name(kn, (*bin_attr)->attr.name);
        }
    }

    // 若存在命名的属性组目录,则一并移除
    if (grp->name)
        kernfs_remove_by_name(kn, grp->name);
}

kobject清理:

// lib/kobject.c
void kobject_del(struct kobject *kobj)
{
    struct kernfs_node *kn;

    if (!kobj)
        return;

    // 从sysfs中删除对应的节点
    kn = kobj->sd;
    if (kn) {
        sysfs_remove_dir(kobj);
        kobj->sd = NULL;
    }

    // 减少父kobject的引用计数
    if (kobj->parent)
        kobj_put(kobj->parent);
}

sysfs清理顺序

  • 1. 移除设备属性文件
    • 移除设备专属的属性条目
    • 清除电源管理相关的属性
    • 删除统计类属性文件
  • 2. 移除类设备链接
    • 删除 /sys/class/ 目录下的符号链接
    • 移除 /sys/bus/ 中的设备连接项
  • 3. 移除设备目录
    • 清理 /sys/devices/ 下的对应设备路径
    • 平台设备所创建的目录
    • 总线设备相关的目录节点
  • 4. 移除子系统目录
    • 设备所属的类目录(如 /sys/class/<class>)
    • 总线类型对应的目录结构
  • 5. 清理内核对象
    • 处理kobject的引用计数释放
    • 完成相关内存资源的回收

第四层:电源管理状态保存

机制功能:在系统可能进入低功耗状态前,保存当前设备的电源管理运行状态,为后续休眠或恢复提供上下文支持。

数据结构与大小:

  • struct dev_pm_info
    (200字节):设备电源管理信息
  • struct pm_subsys_data
    (150字节):电源管理子系统内部数据

源码关键函数与数据跳转

运行时PM状态保存:

// drivers/base/power/runtime.c
void pm_runtime_cleanup(struct device *dev)
{
    struct dev_pm_info *power = &dev->power;

    // 同步取消所有待执行的运行时PM工作项
    cancel_work_sync(&power->work);

    // 停止并等待挂起定时器结束
    del_timer_sync(&power->suspend_timer);

    // 重置并清理当前运行时电源状态
    // (包括状态标志、使用计数等)
}
// arch/arm64/include/asm/suspend.h
struct cpu_suspend_ctx {
    // 通用寄存器
    u64     x19;
    u64     x20;
    u64     x21;
    u64     x22;
    u64     x23;
    u64     x24;
    u64     x25;
    u64     x26;
    u64     x27;
    u64     x28;
    u64     x29;    // 帧指针 FP
    u64     lr;     // 链接寄存器 LR
    // 栈指针
    u64     sp;
    // 系统寄存器
    u64     sp_el0;
    u64     tpidr_el0;
    u64     tpidrro_el0;
};

struct cpu_suspend_ctx
(200字节):CPU挂起上下文 ARM64 CPU状态保存流程: // arch/arm64/kernel/suspend.c int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) { struct sleep_stack_data state; int ret; ret = __cpu_suspend_enter(&state); if (!ret) { ret = fn(arg); __cpu_suspend_exit(); } return ret; }
struct sleep_stack_data
(4KB):睡眠栈数据 ARM64特定资源清理机制: 该层级主要负责在系统挂起前对ARM64架构特有的硬件单元进行状态清理和资源释放,确保低功耗模式下的系统稳定性。 关键操作包括: - 性能监控单元(PMU)的去初始化 - 调试寄存器OSLAR的清除 - 全局缓存刷新 - TLB(转换旁路缓冲区)清空 源码实现如下: // arch/arm64/kernel/process.c void arm64_pm_cleanup(void) { arm64_pmu_cleanup(); clear_oslar_el1(); flush_cache_all(); flush_tlb_all(); } 第六层:内存与缓存一致性维护 功能说明: 在进入深度休眠前,确保所有脏页写回存储,内存视图一致,防止数据丢失或不一致。 涉及的数据结构:
struct page
(64字节):页结构
struct address_space
(400字节):地址空间 核心处理函数: 文件系统同步过程: // fs/sync.c void sync_filesystems(int wait) { struct file_system_type *fs; for (fs = file_systems; fs; fs = fs->next) { if (!(fs->fs_flags & FS_REQUIRES_DEV)) continue; __sync_filesystem(fs, wait); } } ARM64平台缓存全面清理: // arch/arm64/mm/cache.S ENTRY(flush_cache_all) dsb sy bl __flush_dcache_all ic ialluis dsb ish // TLB 清理由后续代码完成 END(flush_cache_all) 设备级电源状态管理: 以下代码用于设置设备进入挂起状态后的运行参数。 // drivers/base/power/main.c static int device_suspend(struct device *dev) { pm_callback_t callback = NULL; const char *info = NULL; int error = 0; if (dev->power.syscore) goto Complete; if (dev->power.op && dev->power.op->suspend) { info = "suspend "; callback = dev->power.op->suspend; } if (callback) { error = callback(dev); if (error) goto End; } Complete: dev->power.is_suspended = true; End: return error; } // 挂起完成后状态重置 power->runtime_status = RPM_SUSPENDED; power->runtime_error = 0; power->idle_notification = false; power->request_pending = false; power->request = RPM_REQ_NONE; power->deferred_resume = false;

内存清理流程

系统在执行关机或重启操作时,需按特定顺序进行内存资源的清理与同步,以确保数据一致性与硬件安全。该过程主要包括以下四个阶段:

  • 1. 文件系统同步
    • 将所有脏页(dirty pages)写入持久化存储设备
    • 等待写入操作完成,防止数据丢失
    • 刷新文件系统的元数据信息
  • 2. 页面缓存管理
    • 释放干净的页面缓存内容
    • 回收可被重新分配的内存区域
    • 清除块设备相关的缓存数据
  • 3. 处理器缓存处理
    • 清空数据缓存(DCache)
    • 清空指令缓存(ICache)
    • 刷新转换查找缓冲区(TLB)
  • 4. 内存映射结构清理
    • 解除已建立的内存映射关系
    • 释放页表项所占用的空间
    • 重置MMU内部状态寄存器

第七层:中断与时钟资源释放

为确保系统稳定关闭,必须有序地停用中断和时钟子系统。

主要功能机制:关闭各类中断源与时钟驱动,终止系统周期性任务和事件响应。

涉及核心数据结构及大小:

struct irq_desc

(400字节) —— 中断描述符表项

struct clock_event_device

(500字节) —— 时钟事件设备控制结构

关键源码实现分析

中断控制器停用逻辑:

// drivers/irqchip/irq-gic-v3.c
static void gic_shutdown(struct irq_data *d)
{
    // 关闭指定中断线
    gic_poke_irq(d, GICD_INT_ENABLE_CLEAR);
    // 恢复默认优先级设置
    gic_irq_set_prio(d, GICD_INT_DEF_PRI);
    // 清除中断组配置
    gic_irq_set_igroup(d, 0);
}

时钟事件设备关闭流程:

// kernel/time/clockevents.c
void clockevents_shutdown(struct clock_event_device *dev)
{
    // 进入关机状态
    clockevents_set_state(dev, CLOCK_EVT_STATE_SHUTDOWN);
    // 调用底层关闭接口
    if (dev->set_state_shutdown)
        dev->set_state_shutdown(dev);
    else if (dev->set_mode)
        dev->set_mode(CLOCK_EVT_MODE_SHUTDOWN, dev);
}

中断与时钟关闭顺序

  • 1. 定时器服务停止
    • 高精度定时器(hrtimers)停用
    • 时钟事件设备(clock events)关闭
    • 定时器轮询机制退出
  • 2. 外设中断禁用
    • 网络接口中断屏蔽
    • 存储控制器中断关闭
    • 输入设备中断停用
  • 3. 系统级中断处理关闭
    • IPI(处理器间中断)禁用
    • 核间通信中断通道关闭
  • 4. 中断控制器整体下电
    • GIC 分发器模块关闭
    • GIC CPU 接口单元断电

第八层:最终硬件断电操作

此阶段负责触发实际的物理关机信号,完成从软件到硬件的彻底关闭。

功能说明:调用平台专用接口执行系统断电命令。

相关数据结构与硬件支持:

struct power_ops

(64字节) —— 电源操作函数指针结构体

底层依赖架构特定寄存器配置,通过固件接口访问电源控制单元。

核心代码路径

基于PSCI标准的ARM64关机实现:

// drivers/firmware/psci/psci.c
static void psci_sys_poweroff(void)
{
    invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}

设备树匹配与初始化:

// arch/arm64/kernel/psci.c
static const struct of_device_id psci_of_match[] = {
    { .compatible = "arm,psci-0.2", .data = &psci_0_2_ops },
    { .compatible = "arm,psci-1.0", .data = &psci_1_0_ops },
    { }
};

void __init psci_dt_init(void)
{
    struct device_node *np;
    const struct of_device_id *matched_np;

    np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
    if (!np)
        return;

    pm_power_off = psci_sys_poweroff;
}

ARM64平台关机方式概览

ARM64架构采用标准化固件接口实现关机控制,主要依赖PSCI(Power State Coordination Interface)协议完成系统级断电动作。

1. PSCI系统调用(适用于现代ARMv8架构)

  • 执行SYSTEM_OFF功能调用
  • 通过SMC指令切换至EL3异常级别
  • 由可信固件(如TF-A)接管并处理关机流程

2. 平台相关关机机制

  • 向特定系统控制寄存器写入关机命令
  • 配置电源管理IC以进入低功耗或断电状态
  • 向硬件模块发送明确的关机指令

3. 备选关机方案

  • 利用看门狗定时器超时触发自动断电
  • 通过硬件复位线路强制重启或关闭系统

第九层:关机状态反馈机制

核心功能:实现对关机过程的状态监控、异常检测与错误响应,确保系统能够安全、可控地终止运行。

关键数据结构及其大小

struct completion

(32字节) 表示一个完成量(completion),用于同步关机过程中各组件的完成状态。

struct timer_list

(100字节) 定时器列表结构体,支撑关机超时机制的实现。

核心源码逻辑与函数跳转关系

关机超时处理函数:

// kernel/reboot.c
static void timeout_shutdown(struct timer_list *unused)
{
    pr_emerg("Shutdown timeout, forcing power off\n");
    // 超时后强制执行底层关机操作
    machine_power_off();
}

主关机流程入口:

void kernel_power_off(void)
{
    // 启动定时器,防止关机流程无限挂起
    mod_timer(&power_off_timer, jiffies + POWER_OFF_TIMEOUT);

    // 准备内核关机环境
    kernel_shutdown_prepare(SYSTEM_POWER_OFF);

    // 尝试正常关机
    if (!pm_power_off_force) {
        pr_emerg("Power down\n");
        machine_power_off();
    }

    // 若关机失败,则启动恢复策略:重启系统
    pr_emerg("Power off failed, rebooting\n");
    machine_restart(NULL);
}

关机状态码分类

  • 成功状态
    • 正常关机:所有设备有序关闭,资源释放完整
    • 快速关机:跳过部分清理步骤,迅速断电
    • 强制关机:在超时或故障情况下强行切断电源
  • 警告状态
    • 设备关闭超时:个别驱动未及时响应shutdown请求
    • 文件系统同步失败:存在未写入磁盘的数据
    • 资源清理不完整:某些内存或句柄未能完全释放
  • 错误状态
    • 关键设备关闭失败:如存储控制器无法停止
    • 内存清理失败:存在不可回收的内存区域
    • 硬件关机失败:PSCI或平台接口返回错误
  • 恢复操作策略
    • 自动重启系统以尝试恢复正常运行
    • 进入紧急维护模式供调试分析
    • 维持当前运行状态避免进一步风险

第六部分总结:系统关闭数据流与执行跳转图

以下为ARM64平台上Linux系统关机过程的完整流程分解:

  1. 关机触发
    • 接收reboot系统调用
    • 进行权限校验与参数合法性检查
    • 执行ARM64架构特有的关机前置准备
  2. 设备驱动关闭阶段
    • 按照设备依赖关系逆序关闭
    • 逐个调用各驱动的shutdown回调函数
    • 释放设备专属资源
    • 反初始化设备树中注册的节点
  3. sysfs文件系统清理
    • 删除设备对应的属性文件
    • 清除类设备之间的符号链接
    • 移除设备在/sys下的目录结构
    • 清理内核对象引用计数
  4. 电源管理状态持久化
    • 完成运行时PM的最后清理
    • 保存各设备的电源状态信息
    • 执行PM框架中的回调函数
    • 更新全局电源状态标记
  5. ARM64架构专属资源回收
    • 保存CPU上下文状态
    • 关闭性能监控单元(PMU)
    • 清除调试寄存器设置
    • 刷新并失效缓存和TLB条目
  6. 内存子系统清理
    • 同步所有挂载的文件系统
    • 清空页面缓存(page cache)
    • 清理处理器各级缓存
    • 解除不必要的内存映射关系
  7. 中断与时钟系统停用
    • 停止所有活动定时器
    • 禁用外设中断请求
    • 关闭全局中断(IRQ/FIQ)
    • 关闭中断控制器(如GIC)
  8. 最终硬件断电执行
    • 发起PSCI系统调用请求关机
    • 调用平台定制化的关机方法
    • 启用备用关机手段(如看门狗)
    • 实现物理层面的电力切断
  9. 关机结果反馈与处理
    • 处理可能发生的关机超时事件
    • 根据错误类型执行恢复动作
    • 返回最终关机状态码
    • 确认系统已完全停止运行

ARM64平台sysfs生命周期总览

启动流程:
硬件加电 → ATF(ARM Trusted Firmware)执行 → U-Boot引导加载 → Linux内核启动 → 设备树解析 → 驱动程序初始化 → sysfs节点创建 → 用户空间进程启动

运行期间行为:
用户交互操作 → 应用程序访问设备 → 动态设备控制 → 性能数据采集 → 系统日常维护 → 电源状态调节 → 温度监控与调节

关闭流程:
关机命令触发 → 逐级关闭设备 → 清理sysfs结构 → 保存运行状态 → 释放系统资源 → 清除各类缓存 → 执行最终硬件关机

上述完整树形结构清晰呈现了ARM64架构下Linux系统的全生命周期管理。从启动到运行再到关闭,每一阶段均体现了与sysfs的高度协同,展示了内核在设备管理、电源控制和资源调度方面的精细化设计。整体架构遵循高内聚、低耦合原则,保障系统稳定性与可维护性。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Linux Sys Lin CAPABILITIES Coordination
相关内容:Linux文件目录分析

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-5 23:17