第一部分:ARM64系统启动与设备树初始化
树根:ARM64硬件启动流程
在ARM64架构中,系统的启动过程遵循一系列有序的引导阶段:
BootROM → ATF (ARM Trusted Firmware) → U-Boot → Linux内核
第一层:内核入口点(ARM64架构特定)
机制功能:负责处理ARM64平台的内核启动初始流程,包括异常向量设置、内存管理单元初始化以及跳转至C语言环境。
关键数据结构大小:
(64字节)——处理器信息结构struct proc_info_list
(128字节)——机器描述符结构struct machine_desc
核心源码分析(位于 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虚拟文件系统结构,供后续驱动和用户空间使用。
相关数据结构大小:
(200字节)——设备节点结构体struct device_node
(100字节)——属性结构体struct property
关键函数实现:
// 文件路径: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目录下,支持热插拔与调度策略配置。
涉及的数据结构大小:
(100字节)——通用CPU拓扑信息struct cpu_topology
(200字节)——ARM64平台专用拓扑扩展struct cputopo_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 记录物理索引编号。第五层:中断控制器与 /sys/kernel/irq 系统接口 ARM64 架构使用通用中断控制器(GICv3)进行中断管理。系统启动时完成 GIC 的初始化,并在 sysfs 中创建对应的接口节点,便于用户空间访问中断相关信息。 关键数据结构包括: - 中断描述符(irq_desc)——约 400 字节 - GIC 控制器私有数据结构 ——约 500 字节struct irq_desc核心源码流程解析: 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 gic_chip_datastruct clk_core初始化流程分析: 时钟框架入口函数定义于 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);struct clk_hw
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类设备进行系统注册,实现串行通信支持。 数据结构与大小:(200字节):串口驱动结构体信息struct uart_driver(500字节):串口端口相关数据结构struct uart_port(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:struct tty_driver
调试与性能监控阶段处理
-> 初始化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卡状态。 数据结构及其大小:(2KB):代表MMC主机控制器的数据结构实例struct mmc_host(800字节):描述已插入的MMC卡的信息结构struct mmc_card(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);struct gendisk
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_descGPIO描述符
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操作函数集// 获取平台资源与寄存器映射 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;struct spi_driver
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架构下的输入设备驱动在系统启动时完成初始化,并通过内核的输入子系统注册具体的输入设备。该过程使得触摸屏、按键等外设能够被操作系统识别并处理用户交互事件。 数据结构与大小(1KB):表示一个输入设备的核心数据结构,包含设备名称、总线类型、能力位图及关联的硬件参数。struct input_dev(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/ [目录] (电源管理相关接口)struct input_handler
+---> 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 或 disabledpolicy:当前启用的温控策略,例如 step_wiseavailable_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-sensorpower/:电源控制相关目录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/:关联的底层设备链接,如 ../../../policy0power/和subsystem/:标准电源与类链接目录
- cooling_device1/ —— 冷却设备1
cur_state:当前状态,如0max_state:最大状态值,如3type:设备类型,如 "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)/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_info设备电源管理目录结构(整合示例): /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 dev_pm_domain(300字节):平台相关的挂起操作结构体struct platform_suspend_ops(200字节):平台冻结操作的数据结构 源码关键函数跳转点: ARM64架构下的系统挂起操作注册入口:struct platform_freeze_ops
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提供的设备信息,动态生成相应的设备节点。 数据结构与大小:(300字节):udev设备struct udev_device(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) {struct udev_rules
// 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 文件系统的访问权限管理与安全策略控制,确保系统资源不被未授权访问或修改。
数据结构与内存占用
—— 索引节点(约 600 字节)struct inode
—— 目录项(约 200 字节)struct dentry
文件系统权限模型
/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 作为内核与用户空间的重要桥梁,参与多个关键流程:
- udev 设备管理
- 监听 sysfs 中的设备事件
- 执行预定义 udev 规则
- 动态创建设备节点
- 设置适当的设备权限
- systemd 服务集成
- 基于设备状态触发服务启动
- 监控特定 sysfs 路径变化
- 管理系统服务依赖关系
- 与 cgroup 进行资源联动控制
- 应用程序交互
- 实现 GPIO 和 LED 控制
- 读取传感器实时数据
- 进行电源管理模式切换
- 访问性能监控接口
- 性能监控工具链
- 通过 sysstat 收集系统统计信息
- 利用 lm-sensors 监控硬件温度与电压
- 结合 perf 工具进行性能剖析
- 支持实时系统状态监控
- 调试与诊断功能
- 启用 ftrace 进行函数级跟踪
- 动态调整内核调试级别
- 检查 GPIO 当前电平状态
- 辅助定位系统异常问题
- 容器与虚拟化集成
- Docker 利用设备映射暴露硬件
- Kubernetes 使用设备插件管理加速器
- QEMU 实现设备透传给虚拟机
- 统一管理虚拟化环境下的设备资源
- 安全访问控制机制
- 基于传统文件权限模型进行访问限制
- 集成 SELinux 安全策略
- 执行细粒度权限校验
- 生成安全审计日志记录
- 性能优化策略实施
- 启用属性值缓存机制
- 优化批量属性操作路径
- 控制高并发访问行为
- 精简内存分配与使用
系统关闭与资源回收流程
当系统进入关机流程时,由用户发起的关机命令将触发一系列有序的清理动作。
树根:系统关闭触发
常见用户空间关机指令包括:shutdown、poweroff、systemctl poweroff 和 init 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文件系统中的设备属性及相关目录结构,确保设备注销时相关节点被正确移除。
数据结构与大小:
(300字节):kernfs节点struct kernfs_node
(40字节):属性结构struct attribute
源码关键函数与数据跳转
属性组清理:
// 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的引用计数释放
- 完成相关内存资源的回收
第四层:电源管理状态保存
机制功能:在系统可能进入低功耗状态前,保存当前设备的电源管理运行状态,为后续休眠或恢复提供上下文支持。
数据结构与大小:
(200字节):设备电源管理信息struct dev_pm_info
(150字节):电源管理子系统内部数据struct pm_subsys_data
源码关键函数与数据跳转
运行时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系统关机过程的完整流程分解:
- 关机触发
- 接收reboot系统调用
- 进行权限校验与参数合法性检查
- 执行ARM64架构特有的关机前置准备
- 设备驱动关闭阶段
- 按照设备依赖关系逆序关闭
- 逐个调用各驱动的shutdown回调函数
- 释放设备专属资源
- 反初始化设备树中注册的节点
- sysfs文件系统清理
- 删除设备对应的属性文件
- 清除类设备之间的符号链接
- 移除设备在/sys下的目录结构
- 清理内核对象引用计数
- 电源管理状态持久化
- 完成运行时PM的最后清理
- 保存各设备的电源状态信息
- 执行PM框架中的回调函数
- 更新全局电源状态标记
- ARM64架构专属资源回收
- 保存CPU上下文状态
- 关闭性能监控单元(PMU)
- 清除调试寄存器设置
- 刷新并失效缓存和TLB条目
- 内存子系统清理
- 同步所有挂载的文件系统
- 清空页面缓存(page cache)
- 清理处理器各级缓存
- 解除不必要的内存映射关系
- 中断与时钟系统停用
- 停止所有活动定时器
- 禁用外设中断请求
- 关闭全局中断(IRQ/FIQ)
- 关闭中断控制器(如GIC)
- 最终硬件断电执行
- 发起PSCI系统调用请求关机
- 调用平台定制化的关机方法
- 启用备用关机手段(如看门狗)
- 实现物理层面的电力切断
- 关机结果反馈与处理
- 处理可能发生的关机超时事件
- 根据错误类型执行恢复动作
- 返回最终关机状态码
- 确认系统已完全停止运行
ARM64平台sysfs生命周期总览
启动流程:
硬件加电 → ATF(ARM Trusted Firmware)执行 → U-Boot引导加载 → Linux内核启动 → 设备树解析 → 驱动程序初始化 → sysfs节点创建 → 用户空间进程启动
运行期间行为:
用户交互操作 → 应用程序访问设备 → 动态设备控制 → 性能数据采集 → 系统日常维护 → 电源状态调节 → 温度监控与调节
关闭流程:
关机命令触发 → 逐级关闭设备 → 清理sysfs结构 → 保存运行状态 → 释放系统资源 → 清除各类缓存 → 执行最终硬件关机
上述完整树形结构清晰呈现了ARM64架构下Linux系统的全生命周期管理。从启动到运行再到关闭,每一阶段均体现了与sysfs的高度协同,展示了内核在设备管理、电源控制和资源调度方面的精细化设计。整体架构遵循高内聚、低耦合原则,保障系统稳定性与可维护性。


雷达卡


京公网安备 11010802022788号







