devicetree和启动参数解析流程

news2024/11/20 21:28:55

devicetree和启动参数解析流程


文章目录

  • devicetree和启动参数解析流程
    • 一、设备树解析概述
    • 二、early device tree 解析流程
    • 三、device node节点创建流程
    • 四、bootargs参数解析
      • 4.1 bootargs参数配置
      • 4.2 early param参数解析
      • 4.3 常规参数解析
      • 4.4 kernel param注册
      • 4.5 setup接口注册


本文基于以下软硬件假定:
架构:AARCH64
内核版本:5.14.0-rc5

一、设备树解析概述

AARCH64架构下内核可以通过设备树或acpi方式获取设备信息,其中acpi主要用于服务器领域,而设备树用于嵌入式领域。在设备树方式中,bootloader启动之前将设备树拷贝到内存中,并将地址通过x2寄存器传递给kernel,kernel启动时从设备树中读取启动参数和设备配置节点。

由于内存配置信息是由device tree传入的,而将device tree解析为device node的流程中需要为node和property分配内存。因此在device node创建之前需要先从device tree中解析出memory信息,故内核通过early_init_dt_scan接口实现了early的设备树信息扫描接口,以解析memory以及bootargs等一些启动早期需要使用的信息。

在memory节点解析完成并被加入memblock之后,即可通过memblock为device node分配内存,从而可将完整的device tree信息解析到device node结构中。由于device node包含了设备树的所有节点以及它们之间的连接关系,因此此后内核就可以通过device node快速地索引设备节点。

二、early device tree 解析流程

在AARCH64架构下,early device tree解析流程如下图:

在这里插入图片描述

其主要包括:

  1. 解析chosen节点中的initrd、bootargs和rng-seed属性,其中initrd包含其地址和size信息,rng-seed作为随机数种子添加到内核的随机数池中
  2. 获取root节点的size-cells和address-cells值
  3. 遍历memory节点的内存region,并将合法的region加入memblock中。若设备树中含有hotplug属性,则在内存flag中加上hotplug标志,以标识该内存是可热插拔的

三、device node节点创建流程

内核通过unflatten_device_tree接口解析device tree中的node和property信息,并为解析到的每个节点创建device node,以及将解析到的属性添加到对应node中。其主要流程如下图:

在这里插入图片描述

  1. __unflatten_device_tree:解析设备树的所有节点和属性,根据解析到的信息创建和填充device node信息。device node通过父节点、子节点和兄弟节点三个指针来维护各节点之间的关系。如以下是一个含有六个节点的节点关系示意图:在这里插入图片描述
  2. of_alias_scan:扫描device tree中的所有别名并填充别名信息,如名字,其对应的device node等。内核通过一个名为aliases_lookup全局链表维护所有扫描到的别名
  3. unittest_unflatten_overlay_base:解析unit test的device tree overlay,其解析完成的root device node保存在overlay_base_root中,并被用于其后的device tree 测试流程。其目的是为了尽量模拟实际设备树的行为,以测试功能的正确性。该测试流程由late_initcall(of_unittest)完成

四、bootargs参数解析

4.1 bootargs参数配置

bootargs用于向内核传递启动参数,内核启动时解析这些参数并从特定的section中查找并执行参数处理函数,以实现对相关功能的配置。AARCH64架构的bootargs配置方式较灵活,主要有以下几种:

  1. 通过devicetree配置
  2. 通过内核配置选项配置
  3. 通过bootconfig方式配置

通过devicetree配置是使用较多的方式,若对于使用uboot引导的内核,它又可以有以下配置方法:

  1. 直接在devicetree的chosen节点中定义bootargs
  2. 在uboot代码中通过环境变量的方式定义默认的bootargs
  3. 通过uboot的命令行修改bootargs环境变量。其中后两种方式在启动内核之前,uboot都会将环境变量中的bootargs值设置到devicetree中

内核也可以通过CONFIG_CMDLINE配置选项设置bootargs,由该选项指定的bootargs参数在内核启动时有三种处理方式:

  1. 若设置了CONFIG_CMDLINE_EXTEND选项,则将该参数拼接到由device tree中解析出的参数后面
  2. 若设置了CONFIG_CMDLINE_FORCE选项,则用该参数替换从device tree中解析出的参数
  3. 未设置以上两个选项,则在device tree未设置bootargs时将该参数作为默认的bootargs,否则丢弃该参数

bootconfig方式将启动参数以key=value的形式写到xbc(extra boot config)文件中,然后通过bootconfig工具将该文件追加到initrd的末尾,并随initrd一起被加载到内核。内核启动时通过bootconfig.c解析这些参数,并将其拼接到上面解析出参数的前面

4.2 early param参数解析

内核bootargs参数解析也包含两个阶段,eraly参数解析和常规参数解析。顾名思义,early参数解析位于常规参数解析之前,其流程如下:

在这里插入图片描述

  1. 遍历bootargs中的所有参数,并逐一处理
  2. 对特定参数判断其是属于kernel param类型还是setup类型参数
  3. early参数解析中不处理kernel param参数,因此不会执行这个分支
  4. 该流程执行实际的early param解析,其代码如下:
static int __init do_early_param(char *param, char *val,
                                 const char *unused, void *arg)
{
        const struct obs_kernel_param *p;

        for (p = __setup_start; p < __setup_end; p++) {
                if ((p->early && parameq(param, p->str)) ||
                    (strcmp(param, "console") == 0 &&
                     strcmp(p->str, "earlycon") == 0)
                ) {
                        if (p->setup_func(val) != 0)
                                pr_warn("Malformed early option '%s'\n", param);
                }
        }
        /* We accept everything at this stage. */
        return 0;
}

其会遍历setup section,查找与给定bootargs参数匹配且带有eraly标志,以及参数名为console或earlycon的entry,然后执行其对应的setup函数

4.3 常规参数解析

常规参数解析流程与early参数解析类似,也是通过调用parse args接口解析相关参数。其解析流程如下:

在这里插入图片描述

由于带early标志的参数已经在early参数解析中处理,因此不需要再次处理。但其需要处理所有剩余的参数,参数匹配方式有两种:

  1. 内核通过setup方式注册的参数处理接口
  2. 内核通过kernel param方式注册的参数处理接口

4.4 kernel param注册

kernel param用于设置或获取模块的参数,其主要是向系统注册一个参数相关的变量,并提供获取和修改该变量的get和set回调函数。参数可以通过module_param或module_param_cb宏定义,其定义如下:

#define module_param(name, type, perm)                               \
        module_param_named(name, name, type, perm)

其中参数含义如下:

  1. name:参数名
  2. type:参数类型
  3. perm:由sysfs使用的权限

对于module param接口,使用内核定义的通用set和get方法操作该参数的值。而module_param_cb可以为用户提供自定义的set和get回调函数,其定义如下:

#define module_param_cb(name, ops, arg, perm)                                    \
        __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0)

它们最终都会调用到以下所示的__module_param_call宏,即定义并初始化一个struct kernel_param结构,并将其链接到__param section中。内核中定义的所有module param都会被链接进该section中,并保存在代码段__start___param到__stop___param之间的位置。

  #define __module_param_call(prefix, name, ops, arg, perm, level, flags)     \
        /* Default value instead of permissions? */                     \
        static const char __param_str_##name[] = prefix #name;          \
        static struct kernel_param __moduleparam_const __param_##name   \
        __used __section("__param")                                     \
        __aligned(__alignof__(struct kernel_param))                     \
        = { __param_str_##name, THIS_MODULE, ops,                       \
            VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } }

上面的常规参数解析流程即是遍历__start___param和__stop___param之间的所有kernel param,并执行相应的set处理

4.5 setup接口注册

__setup的原理与kernel param类似,也是通过定义并初始化一个链接到特殊段中的结构体,在内核启动处理常规参数解析时遍历该段中定义的entry,逐个与bootargs中解析到的参数比较,若找到匹配的entry则执行其相应的回调函数。

与kernel param不同的是,kernel param回调的目的是设置或获取一个变量的值,而__setup宏的回调是可以任意定义的,它可以根据bootargs的输入参数执行用户自定义的操作。该宏的定义如下:

  #define __setup_param(str, unique_id, fn, early)                       \
        static const char __setup_str_##unique_id[] __initconst         \
                __aligned(1) = str;                                     \
        static struct obs_kernel_param __setup_##unique_id              \
                __used __section(".init.setup")                         \
                __aligned(__alignof__(struct obs_kernel_param))         \
                = { __setup_str_##unique_id, fn, early }

#define __setup(str, fn)                                                \
        __setup_param(str, fn, fn, 0)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/191156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker - 2. Docker 工作原理

目录 1. Docker入门图解 2. Docker 整体架构和底层通讯原理 1. Docker入门图解 (1) Docker是一个Client-Server结构的系统&#xff0c;Docker守护进程(图中Docjer daemon)运行在主机上&#xff0c;然后通过Socket链接客户端往返&#xff0c;守护进程从客户端接收命令并管理在…

PySpark 之 SparkSQL 编程

1. DataFrame 的创建 1.1 RDD 和 DataFrame 的区别 RDD 是一种弹性分布式数据集&#xff0c;Spark中的基本抽象。表示一种不可变的、分区储存的集合&#xff0c;可以进行并行操作DataFrame是一种以列对数据进行分组表达的分布式集合&#xff0c; DataFrame等同于Spark SQL中的…

jvm宏观上类的加载机制整体和微观上通过类加载器进行加载的过程

说到一个词“类的加载”其实含有歧义&#xff0c;因为在jvm中可以说有一个宏观的&#xff0c;即整体上的类的加载&#xff0c;还有一个微观上的加载&#xff0c;也就是狭隘的通过类加载器的加载class文件的过程&#xff0c;这里介绍这两种“类的加载”。 类的整体加载过程(类加…

Windows C盘清理的正确方式,从此你告别红色烦恼

前言 伴随着电脑工作的时间越久&#xff0c;C盘常常会提示显示其内存已不足。 C盘容量不足将会极大影响系统的运行速度&#xff0c;电脑会变卡、死机。 今天&#xff0c;就给大家分享一个C盘空间清理终极解决方案&#xff1a; 1、利用Windows自己附带的磁盘清理工具 1&…

[oeasy]python0068_ 字体样式_正常_加亮_变暗_控制序列

字体样式 回忆上次内容 上次了解了一个新的转义模式 \33 逃逸控制字符 esc esc 让输出 退出标准输出流 进行控制信息的设置 可以清屏也可以设置光标输出的位置 还能做什么呢&#xff1f; 可以设置字符的颜色吗&#xff1f;&#xff1f;&#xff1f;&#x1f914; 查看细节…

BIC-2022-BDT:区块链和基于数字双胞胎的智能制造高效数据处理安全框架

摘要工业物联网具有智能连接、数据实时处理、协同监测、信息自动处理等特点&#xff0c;是物联网时代的重要组成部分之一。异构工业物联网设备对高数据速率、高可靠性、高覆盖、低延迟的要求&#xff0c;已成为信息安全领域的一大挑战。工业物联网中的智能制造产业需要多方协同…

(02)Cartographer源码无死角解析-(53) 2D后端优化→位姿图优化理论讲解、

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文末…

【ardunio+sx1268】与【esp32+sx1268】实现不同主控单片机lora通讯

2023.21 在前文 esp32 sx1268 的 spi 驱动调通之后&#xff0c;又尝试 ardunio sx1268 驱动&#xff0c;实现不同主控对于lora模块 sx1268 的控制 文章目录1. 实验结果2.硬件描述2.1 sx12682.2 ardunio ATmega3283.接线实物图5.开发环境6.代码实现关于esp32sx1268 的驱动以及代…

爆款制作获1200w播放,B站UP主+品牌如何迈入2023

1月13日&#xff0c;bilibili 2022年度百大UP主已经揭开帷幕&#xff0c;今年延续2021年的评审标准&#xff0c;依然从专业性、影响力、创新性三个维度进行评选。来源-B站这套评审标准已经实施两年&#xff0c;早期的百大评选上榜的更多是来自知名度高、影响力广的UP主&#xf…

2.关系数据库

学习过程参考&#xff08;后续章节同&#xff09; 【公开课】数据库系统概论&#xff08;王珊老师&#xff09;&#xff08;完结&#xff09; 《数据库系统概论》思维导图 【专栏必读】数据库系统概论第五版&#xff08;王珊&#xff09;专栏学习笔记目录导航及课后习题答案详…

中国电子学会2021年09月份青少年软件编程Scratch图形化等级考试试卷三级真题(含答案)

2021-09 Scratch三级真题 分数&#xff1a;100 题数&#xff1a;38 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 1. 程序中要使用不确定的数值&#xff0c;这时要用到的是&#xff1f;&#xff08;D &#xff09; A、图章 …

Github如何使用详细介绍(保姆级教学)

前言 &#x1f4dc; “ 作者 久绊A ” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴 目录 一、Github如何搜索 二、如何判断一个项目好不好呢&#xff1f…

yolov5 模型输出的格式解析

工作需要&#xff0c; 又需要对yolov5 输出的模型进行转onnx 再用c进行后续处理。 两个问题。 yolov5 的模型输出的是个啥啊&#xff1f;转成onnx后输出的和yolov5输出的处理是否一样呢&#xff1f; 关于第一个问题&#xff0c;yolov5 的模型输出的是个啥啊&#xff1f; 以前…

【Rust】14. Rust 中的函数式语言功能:迭代器与闭包

14.1 闭包&#xff1a;捕获环境的匿名函数 14.1.1 闭包会捕获其环境 14.1.2 闭包类型推断和注解 闭包并不总是要求像 fn 函数那样在参数和返回值上注明类型闭包通常很短&#xff0c;并只关联于小范围的上下文而非任意情境如果尝试对同一闭包使用不同类型则就会得到类型错误&am…

selenium自动化测试框架

一、Selenium自动化测试&#xff08;基于python&#xff09; 1、Selenium简介&#xff1a; 1.1 Selenium是一款主要用于Web应用程序自动化测试的工具集合。Selenium测试直接运行在浏览器中&#xff0c;本质是通过驱动浏览器&#xff0c;模拟浏览器的操作&#xff0c;比如跳转…

测试碎碎念(基础篇_2)

一、软件测试的基础概念1.1 需求在企业中&#xff0c;需求 主要分为 用户需求 和 软件需求~用户需求&#xff1a;可以简单理解为甲方提出的需求&#xff0c;如果没有甲方&#xff0c;那么就是终端用户使用产品时必须要完成的任务&#xff1b;用户需求 一般是比较简略的&#xf…

Flink官方例子解析:带窗口的WordCount

1. 简介 本篇介绍的是带窗口的WordCount&#xff0c;使用窗口函数countWindow。 countWindow是一种计数窗口&#xff0c;有固定窗口和滑动窗口两种用法。 1.1 固定窗口 countWindow(windowSize) , windowSize指的是窗口大小。 例如countWindow(5)&#xff0c; 说明一个窗口可…

零基础机器学习做游戏辅助第七课--模型的保存与加载

一、保存模型 当我们训练好模型后将它保存下来,这样下次使用时就可以直接加载模型进行工作了。 常见的保存模型有三种: 只保存权重文件:model.save_weights(num_weights) 当我们使用save_weights保存权重文件时,没有指定后缀名,则会保存三个文件在指定目录下

linux 下ARC的中断机制

linux 下ARC的中断机制 一、Idu 中断控制器初始化 Idu 是arc 处理器内部中断控制模块&#xff0c; 类似于arm 内部的gic 中断控制模块 首先&#xff0c;Idu中断控制器在初始化时, 会解析DTS信息中定义了几个idu控制器&#xff0c;每个Idu控制器注册一个struct irq_domain数据…

嵌入式Linux系统开发笔记(十三)

U-Boot烧写验证测试 正点原子专门编写了一个软件来将编译出来的.bin 文件烧写到 SD 卡中&#xff0c;这个软件叫做“imxdownload” 【1】将 imxdownload 拷贝到工程根目录下 【2】给予 imxdownload 可执行权限 我们直接将软件 imxdownload 从 Windows 下复制到 Ubuntu 中以…