设备树插件基础必备

一个初学者对于一个新知识点很难接收和理解,即使文档和视频也很难理解。 这种情况一般各方面原因吧:

  • 此知识点相关内容本身自己知道少,是个新的知识点;
  • 此知识点关联的基础也不知道,相关阐述说明基础知识点也在自己认知范围外

个人始终认为:基础很重要,千万别囫囵吞枣,不然后面接收起来更难,没法成为自己的知识体系。


设备树知识点概要

这里分三部分整理知识点内容:

  • 一些目录 /sys/kernel/config/device-tree/overlays/ /proc/filesystems 是做什么的,设备树插件实操演示
  • 虚拟文件系统ConfigFS 介绍
  • ConfigFS 的核心数据结构

这里整理基础必备知识点目的:打好基础,理解部分核心基础点。

参考资料

Linux驱动开发(速记版)–设备树插件
proc文件系统简介及/proc目录介绍
Linux 下的 /proc 目录介绍
RK3568驱动指南|第八篇 设备树插件-第74章 虚拟文件系统ConfigFS介绍
configfs — 用户空间控制的内核对象配置
备树插件-第75章ConfigFS的核心数据结构

一、 关联目录介绍-device-tree/overlays/ - filesystems

目录 /proc/filesystems 介绍

这里需要了解指令:`cat /proc/filesystems
cat /proc/filesystems 命令用于 列出当前 Linux 内核支持的文件系统类型。
作用如下:

  • 显示已注册的文件系统:
    输出包含内核编译时支持或运行时动态加载的所有文件系统类型(如 ext4, xfs, btrfs, proc, tmpfs 等)。
  • 区分内核原生支持与模块加载的文件系统:
    如果一行开头有 nodev,表示该文件系统不需要物理设备(如虚拟文件系统 proc, sysfs, tmpfs)。
    没有 nodev 的文件系统(如 ext4)通常需要块设备(如硬盘分区

示例如下:

在这里插入图片描述

`这里看到 挂载了一个configfs 文件,并不是所有的Linux 目录挂载了这个configfs , 只有支持了设备数插件功能的kernel 才有这个虚拟文件节点的。

所以在设备树插件相关资料中,开篇都会让 cat /proc/filesystems ,看是否有configfs 节点,目的就是确认你的Linux 内核支持设备树插件的功能。

知识点 configfs

如上获取到的 /proc/filesystems 目录下的 nodev configfs 表示内核支持 configfs 文件系统,并且它是一个 不依赖于物理设备(nodev) 的虚拟文件系统。

configfs 的作用

动态配置内核子系统

  • 某些内核模块(如 USB Gadget、SCSI Target、设备树等)允许通过 configfs 动态调整参数,而无需重新加载模块或重启系统。
    例如,Android 的 adb(USB 调试)功能就依赖 configfs 来动态切换 USB 模式。

  • 替代 sysfs 进行更灵活的对象管理
    sysfs(/sys)主要用于展示内核对象(如设备、驱动),而 configfs 允许 用户主动创建和管理对象(类似 “mkdir” 和 “echo” 操作)。

  • 常见使用场景
    USB Gadget(g_ether, g_mass_storage 等):动态配置 USB 设备模式(如模拟 U 盘、网卡)。
    SCSI Target(LIO):iSCSI 或光纤通道存储目标配置。
    Android 的 functionfs:配置 USB 功能(如 MTP、PTP、MIDI)。

如何使用 configfs?

configfs 通常挂载在 /sys/kernel/config/(不同发行版可能略有不同),例如如下:
在这里插入图片描述

这里我们用之前设备树语法插件里面的.ko 文件来实验下,理解基本使用:
在这里插入图片描述
继续看 生产的device-tree目录和该目录下面的子目录的情况:
在这里插入图片描述

我们在目录 overlays 目录下 mkdir test 命令,结果如下:在test 目录下面多出了 dtbo 和 status
在这里插入图片描述

然后把我们前面写的设备树插件 写入到 dtbo 里面去,同事写入1 到 status 里面去:
在这里插入图片描述

见证奇迹的时候: 我们在设备树下面就看到了rk-485-ctl 对应新增的动态节点了。
在这里插入图片描述

这里对比一下之前我们写的设备树插件原始内容是什么:Linux驱动-设备树插件语法

/dts-v1/;
/plugin/;

&{/rk-485-ctl}{
    overlay_node{
        status = "okay";
    };
};

那个status 节点不就是动态新增过来的嘛 。我们看看实际这个status 值:
在这里插入图片描述
这不就是实际设备树插件里面新增的字段值嘛 。 如果我们修改config 文件系统设备树下面的节点属性值,那么映射到设备树节点下的值也会改变:

/sys/kernel/config/device-tree/overlays/test]# echo 1 > status

/sys/firmware/devicetree/base/rk-485-ctl/overlay_node]# cat status

这样就是实现了修改用户空间的指,映射修改了内核空间设备树的值。

nodev 的含义
  • nodev 表示该文件系统 不需要块设备(如硬盘、U 盘),而是纯内存或内核管理的虚拟文件系统(如 procfs、sysfs、tmpfs)。
  • 没有 nodev 的文件系统(如 ext4、xfs)需要挂载到实际的存储设备(如 /dev/sda1)
configfs 小结
  • configfs 是一个 动态配置内核对象 的虚拟文件系统,主要用于 USB Gadget、SCSI Target 等场景。
  • 它在 /proc/filesystems 中标记为 nodev,表示它不依赖物理设备。
  • 通常挂载在 /sys/kernel/config/,用户可以通过文件操作(mkdir/echo)动态管理内核配置。

这里通过 device-tree/overlays/ - filesystems 两个目录,了解了设备树插件通过configfs 实现用户空间层修改内核层的逻辑,也初步了解了nodev、挂载相关知识点。

目录 device-tree/overlays 介绍

这个目录是 Linux 设备树(Device Tree)动态覆盖(Overlay)功能的用户空间接口,主要用于在运行时动态修改设备树配置。

功能概述

  • 设备树覆盖(Device Tree Overlay):允许在不重新编译内核或重启系统的情况下,动态添加、修改或删除设备树节点和属性。

  • 运行时配置:特别适用于嵌入式系统,可以在运行时根据硬件配置变化调整设备树

目录结构和使用

典型的目录结构如下:

/sys/kernel/config/device-tree/overlays/
    ├── overlay_0/
    ├── overlay_1/
    └── ...

主要操作方式

  • 创建新覆盖:
mkdir /sys/kernel/config/device-tree/overlays/my_overlay
  • 应用覆盖
# 将设备树blob(.dtbo)写入path属性
cat my_overlay.dtbo > /sys/kernel/config/device-tree/overlays/my_overlay/path
  • 检查状态
cat /sys/kernel/config/device-tree/overlays/my_overlay/status

二、虚拟文件系统 ConfigFS

在 Linux 系统中,设备树插件(Device Tree Overlays)选择使用 ConfigFS(Configuration File System,简称 CFS) 作为其虚拟文件系统的原因,主要与 ConfigFS 的设计特性及其在动态设备树管理中的优势有关。以下是详细分析:

ConfigFS 的核心特性

ConfigFS 是一个基于内存的虚拟文件系统,专门用于用户态与内核态的动态配置交互。其核心特点包括:

  • 动态对象管理:允许用户态程序通过文件系统接口(创建/删除目录或文件)动态创建、配置和销毁内核对象。

  • 与 sysfs 的区别:

sysfs 主要用于展示内核对象的当前状态(如设备信息),通常是只读或有限写入。

configfs 则专注于配置内核对象(如创建设备、加载模块),支持完整的生命周期管理(创建、修改、删除)。
  • 事件驱动机制:文件操作(如 mkdir)会直接触发内核中的回调函数,实现配置的实时生效。

设备树插件为何选择 ConfigFS

设备树插件(Overlays)的目的是在运行时动态修改设备树(Device Tree),而 ConfigFS 的设计完美匹配这一需求:
动态加载与卸载

  • 传统设备树:需在启动时通过 Bootloader 静态加载,无法运行时修改。

  • 设备树插件:通过 ConfigFS 可以动态加载(.dtbo 文件)或卸载,无需重启系统。
    示例命令:

mkdir /config/device-tree/overlays/my_overlay  # 创建配置节点
cat example.dtbo > /config/device-tree/overlays/my_overlay/dtbo  # 加载插件
rmdir /config/device-tree/overlays/my_overlay   # 卸载插件

ConfigFS 的 mkdir/rmdir 操作直接对应插件加载/卸载的内核动作。

  • 用户态友好接口
    ConfigFS 通过标准的文件操作(cat、echo、mkdir)实现配置,无需专用工具或内核模块编程。
    用户态工具(如 dtc 编译的 .dtbo)可直接与 ConfigFS 交互,简化开发流程。

  • 安全的并发控制
    ConfigFS 提供内核级别的锁机制,避免多进程同时修改设备树导致的冲突。

  • 与设备树解耦
    ConfigFS 作为通用配置框架,不依赖设备树的具体实现。设备树插件仅是其中一种应用场景,未来可扩展其他配置功能。

虚拟文件系统对比

文件系统主要用途数据存储动态性典型挂载点
procfs进程/内核信息无(动态生成)/proc
sysfs设备/驱动管理无(动态生成)/sys
devtmpfs设备文件管理内存动态创建设备节点/dev
tmpfs临时文件存储内存可读写/tmp、/run
cgroupfs资源限制(cgroups)无(配置接口)/sys/fs/cgroup
debugfs内核调试无(动态生成)/sys/kernel/debug
configfs内核对象配置无(动态生成)/sys/kernel/config

三、 ConfigFS 的核心数据结构

这里重点了解ConfigFS 几个结构体,每个结构体是如何关联的,这里给出迅为有个图,方便理解:

在这里插入图片描述

在这里插入图片描述

核心数据结构

config_group(配置组)

  • 作用:表示 ConfigFS 中的一个逻辑分组(目录),可以包含子组或配置项
  • 成员
struct config_group {
    struct config_item cg_item;          // 继承自 config_item,表示组本身也是一个项
    struct list_head cg_children;        // 子项(item)链表
    struct list_head default_groups;     // 默认子组(group)链表
};
  • 用途: 设备树插件的根目录 /config/device-tree/overlays/ 就是一个 config_group

config_item(配置项)

  • 作用:表示 ConfigFS 中的一个可配置对象(文件或子目录)。
  • 成员
struct config_item {
    char *ci_name;                      // 项的名称(文件名)
    struct config_group *ci_group;      // 所属的父组
    struct list_head ci_entry;          // 在父组中的链表节点
    struct kref ci_kref;               // 引用计数
    const struct config_item_type *ci_type; // 项的类型(操作回调)
};
  • 用途: 例如,加载一个设备树插件时,会在 /config/device-tree/overlays/ 下创建一个 config_item(如 my_overlay)。

config_item_type(项类型)

  • 作用:定义 config_item 的操作回调(如创建、销毁、属性访问)
  • 成员
struct config_item_type {
    struct module *ct_owner;            // 所属模块
    const struct configfs_item_operations *ct_item_ops;  // 项操作回调
    const struct configfs_group_operations *ct_group_ops; // 组操作回调
    struct configfs_attribute **ct_attrs; // 属性(文件)列表
};
  • 回调示例:
 ct_item_ops->release():当用户态删除项(rmdir)时触发。
 ct_attrs:定义可通过文件读写访问的属性(如设备树插件的 dtbo 文件)。

configfs_attribute(属性)

  • 作用:表示一个可读写的文件属性。
  • 成员
struct configfs_attribute {
    char *ca_name;                      // 属性文件名(如 `dtbo`)
    struct module *ca_owner;            // 所属模块
    umode_t ca_mode;                    // 文件权限(如 0644)
};
  • **操作:**需实现 show() 和 store() 方法(类似 sysfs 的属性操作)

configfs_subsystem(子系统)

  • **作用:**管理顶级 ConfigFS 组(如 /config/device-tree/)。

  • 关键成员:

struct configfs_subsystem {
    struct config_group su_group;       // 顶级组
    struct mutex su_mutex;             // 互斥锁(保护并发访问)
};

数据结构的交互流程

用户态操作

mkdir /config/device-tree/overlays/my_overlay

内核响应

  • 触发 config_group_operations->make_group(),创建一个新的 config_item。
  • 为新项关联 config_item_type,指定其操作回调(如 dtbo 文件的读写)。

加载插件

cat example.dtbo > /config/device-tree/overlays/my_overlay/dtbo

触发 configfs_attribute->store(),将 .dtbo 数据传递给内核解析。

关键设计模式

组合模式(Composite)

  • config_group 可以包含其他 config_item 或 config_group,形成树状结构。

  • 例如:/config/device-tree/overlays/ 是组,my_overlay 是项,其下的 dtbo 是属性。

回调驱动

  • 所有用户态操作(mkdir/rmdir/read/write)均通过 config_item_type 中的回调函数转发到内核模块。

动态生命周期

  • 用户态的 mkdir/rmdir 直接对应内核对象的创建和销毁(通过 kref 引用计数管理)。

代码示例(简化版)

以下是一个简单的 ConfigFS 模块示例,展示如何注册一个组和项:

#include <linux/configfs.h>

static struct configfs_attribute my_attr = {
    .ca_name = "value",
    .ca_mode = 0644,
    .show = my_attr_show,  // 实现读回调
    .store = my_attr_store, // 实现写回调
};

static struct configfs_attribute *my_attrs[] = {
    &my_attr,
    NULL,
};

static struct config_item_type my_item_type = {
    .ct_attrs = my_attrs,
    .ct_owner = THIS_MODULE,
};

static struct config_group my_group = {
    .cg_item = {
        .ci_name = "my_config",
        .ci_type = &my_item_type,
    },
};

static struct configfs_subsystem my_subsystem = {
    .su_group = my_group,
    .su_mutex = __MUTEX_INITIALIZER(my_subsystem.su_mutex),
};

// 注册子系统
configfs_register_subsystem(&my_subsystem);

用户态操作

mkdir /config/my_config
echo 123 > /config/my_config/value

ConfigFS小结

  • 这里熟悉了整个ConfigFS 体系,涉及到的几个数据结构,以及每个数据结构是做什么的,之间关联关系
  • ConfigFS 的核心数据结构围绕动态配置设计:
config_group 和 config_item 构建层级关系。

config_item_type 提供操作回调。

configfs_attribute 实现具体属性文件。

设备树插件通过这套结构实现动态加载,是 ConfigFS 的典型应用场景。

总结

  • 虚拟文件系统的了解
  • ConfigFS 关联的基础是指,ConfigFS 里面的几个数据结构
  • 设备树插件是如何写属性的流程

最重要的是 夯实基础,基础概念、数据结构、流程 千万不能模棱两可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值