0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

设备树的传递及kernel 对设备树的解析

Linux爱好者 来源:Linux与SoC 作者:spy_os 2021-07-29 11:19 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

当 U-Boot 将设备树加载到内存指定位置后,ARM 内核的 SoC 以通用寄存器 r2 来传递 dtb 在内存中的地址。kernel 获取到该地址后对 dtb 文件做进一步的处理。

设备树的传递

当使用 bootm 加载 kernel 镜像时(bootz 是对 bootm 的一种封装以及功能扩展,实质一样)。U-Boot 跳转到 kernel 的入口函数是 boot_jump_linux

这个函数的 C 文件在 arch/arm/lib 下,说明设备树的传递的方式是与 SoC 架构相关的。不同的 SoC 在 bring-up 时,这个函数格外重要,这是 U-Boot 与 kernel 之间衔接、交互信息的一个关键 API。U-Boot 的这个函数执行结束后,将 CPU 的控制权完整的交给 kernel。

/* Subcommand: GO */static void boot_jump_linux(bootm_headers_t *images, int flag)

{

。。。

debug(“## Transferring control to Linux (at address %08lx)”

“。。。

”, (ulong) kernel_entry);

bootstage_mark(BOOTSTAGE_ID_RUN_OS);

announce_and_cleanup(fake);

if (IMAGE_ENABLE_OF_LIBFDT && images-》ft_len)

r2 = (unsigned long)images-》ft_addr;

else

r2 = gd-》bd-》bi_boot_params;

。。。

}

r2 作为存放设备树地址的寄存器,其取值有两种方式,分别是例化 bootm_header_t 这个数据结构的 ft_addr,以及利用 U-Boot 的板级启动参数作为设备树的地址。

bootm_header_t 方式

数据结构 bootm_header_t 的定义如下,供各种内核的 SoC 使用,每家厂商根据自己 CPU 的特点对各个成员进行不同的例化。

/*

* Legacy and FIT format headers used by do_bootm() and do_bootm_《os》()

* routines.

*/typedef struct bootm_headers {

。。。

char *ft_addr; /* flat dev tree address */

ulong ft_len; /* length of flat device tree */

。。。

} bootm_headers_t;

用 bootm_header_t 的方式,U-Boot 需支持设备树以及文件非空。

ft_len 以及 ft_addr 属于 bootm_header_t,在 U-Boot 解析镜像文件时,实例化这两个成员。函数调用栈如下:

do_bootz(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])

-bootz_start()

--bootm_find_images(int flag, int argc, char *const argv[], ulong start,ulong size)

---boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,&images.ft_addr, &images.ft_len);

u-boot-v2021.04/common/image-fdt.c

gd-》bd-》bi_boot_params 方式

这种属于比较古老的一种方式了,目前基本不会采用。bi_boot_params 是一个存放内核启动参数的地址,通常是在板级初始化中进行指定。

代码执行到此处,r2 是否为预期的值,一是可以通过打印的方式、再有使用调试工具连上去确认。

kernel 对设备树的解析

解析分两个阶段,第一阶段进行校验以及启动参数的再调整;第二阶段完成设备树的解压,也就是将设备树由 FDT 变成 EDT,创建 device_node。

第一阶段

kernel 启动日志中与设备树相关的第一条打印如下,也就是打印出当前硬件设备的模型名,“OF: fdt: Machine model: V2P-CA9”

Booting Linux on physical CPU 0x0

Linux version 5.4.124 (qemu@qemu) (gcc version 6.5.0 (Linaro GCC 6.5-2018.12)) #3 SMP Fri Jun 25 1502 CST 2021

CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d

CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache

OF: fdt: Machine model: V2P-CA9

这个模型名是在设备树文件的头部定义的,定义当前设备的总体名称。

// SPDX-License-Identifier: GPL-2.0/*

* ARM Ltd. Versatile Express

*

* CoreTile Express A9x4

* Cortex-A9 MPCore (V2P-CA9)

*

* HBI-0191B

*/

/dts-v1/;

#include “vexpress-v2m.dtsi”

/ {

model = “V2P-CA9”;

。。。

}

但这并不是 kernel 对设备树第一次进行处理的地方。在此之前已有其他的操作。函数调用栈如下:

setup_arch(char **cmdline_p) arch/arm/kernel/setup.c

atags_vaddr = FDT_VIRT_BASE(__atags_pointer);

setup_machine_fdt(void *dt_virt) arch/arm/kernel/devtree.c

early_init_dt_verify()

of_flat_dt_match_machine() drivers/of/fdt.c

early_init_dt_scan_nodes();

__machine_arch_type = mdesc-》nr;

第 2 行、__atags_pointer 是 dtb 在内存中的地址,这个地址在汇编阶段(若镜像为 zImage,那么在解压缩阶段就完成了)便获取到了。由于执行到 setup_arch 时 mmu 已经使能并且 4K 的段页表也已经完成了映射,而 U-Boot 传递给 kernel 的设备树 fdt 地址属于物理地址,因此需要将物理地址转换成虚拟地址。

head-common.S

.align 2

.type __mmap_switched_data, %object

__mmap_switched_data:

#ifdef CONFIG_XIP_KERNEL#ifndef CONFIG_XIP_DEFLATED_DATA

.long _sdata @ r0

.long __data_loc @ r1

.long _edata_loc @ r2

#endif

.long __bss_stop @ sp (temporary stack in .bss)

#endif

.long __bss_start @ r0

.long __bss_stop @ r1

.long init_thread_union + THREAD_START_SP @ sp

.long processor_id @ r0

.long __machine_arch_type @ r1

.long __atags_pointer @ r2

第一阶段对设备树的配置主要包括:

A 对 dtb 文件进行 crc32 校验,检测设备树文件是否合法 early_init_dt_verify()

B early_init_dt_scan_nodes()

/* Retrieve various information from the /chosen node */

of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);

/* Initialize {size,address}-cells info */

of_scan_flat_dt(early_init_dt_scan_root, NULL);

/* Setup memory, calling early_init_dt_add_memory_arch */

of_scan_flat_dt(early_init_dt_scan_memory, NULL);

C 更新__machine_arch_type

D 更新 chosen

上面这个 chosen 信息可以在 kernel 起来后再次查看做了哪些修改。

第二阶段

第二阶段单纯的是将设备树 ABI 文件进行解压缩,由 FDT 变成 EDT,生成相应的 device_node 结点。这个阶段的函数调用栈如下:

unflatten_device_tree();

*__unflatten_device_tree()

/* First pass, scan for size */

size = unflatten_dt_nodes(blob, NULL, dad, NULL);

/* Second pass, do actual unflattening */

unflatten_dt_nodes(blob, mem, dad, mynodes);

unflatten_dt_nodes()

populate_node()

device_nodes 结点如下:

354e808e-ee05-11eb-a97a-12bb97331649.png

device_node 创建完成后,kernel 创建 platform_device 时依据这个阶段完成的工作情况进行对应的设备注册,供驱动代码使用。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Kernel
    +关注

    关注

    0

    文章

    50

    浏览量

    12141

原文标题:Linux 设备树的传递以及 kernel 中对设备树的解析

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    UniStore正式全面开放

    5月7日,宇科技正式宣布,全球首个人形机器人任务动作应用商店——宇UniStore官方共享应用平台即日起面向全球用户全面开放。用户可通过该平台开发和下载机器人应用,像安装手机App一样简单,无需任何底层编程能力。
    的头像 发表于 05-09 11:22 887次阅读

    RT-Thread 新一代驱动框架 DM 揭秘:从设备到动态加载,彻底告别硬编码 | 技术集结

    在传统的RTOS驱动开发中,硬件资源往往靠硬编码、设备与驱动强耦合,导致移植难、复用低、维护成本高。如今,RT-Thread推出了新一代DM(DeviceManager)驱动框架,引入设备
    的头像 发表于 04-24 18:05 7060次阅读
    RT-Thread 新一代驱动框架 DM 揭秘:从<b class='flag-5'>设备</b><b class='flag-5'>树</b>到动态加载,彻底告别硬编码 | 技术集结

    科技,IPO申请获受理

    电子发烧友网综合报道 3月20日,上交所网站显示,宇科技股份有限公司科创板IPO申请已受理,成为又一家科创板IPO“预先审阅”落地项目。此次IPO,宇科技拟募资42.02亿元。   招股书显示
    的头像 发表于 03-20 18:33 4359次阅读
    宇<b class='flag-5'>树</b>科技,IPO申请获受理

    RK3576平台PCA9548 I2C开关设备配置与生效全解析

    中广泛应用。本文结合实际设备配置,从 配置解析 、 生效全流程 、 开发关键要点 三个维度,讲透PCA9548在Linux系统中的落地实现,嵌入式开发人员可直接对标实操。 一、先看懂:PCA9548
    的头像 发表于 02-28 11:18 1879次阅读
    RK3576平台PCA9548 I2C开关<b class='flag-5'>设备</b><b class='flag-5'>树</b>配置与生效全<b class='flag-5'>解析</b>

    Linux设备到底是啥?一张图看懂硬件适配的「翻译官」

    你有没有想过:同一份 Linux 内核镜像,为啥能在不同型号的开发板上跑起来?比如一块 ARM 架构的开发板,今天换个显示屏、明天加个传感器,内核不用重新编译就能识别新硬件 —— 这背后,设备(Devicetree) 功不可没。
    的头像 发表于 02-09 17:01 1390次阅读
    Linux<b class='flag-5'>设备</b><b class='flag-5'>树</b>到底是啥?一张图看懂硬件适配的「翻译官」

    深入理解设备chosen节点:固件与内核的“配置桥梁”

    在嵌入式 Linux 开发中,设备(Device Tree)是连接硬件与内核的关键纽带。但有一个节点很特殊 —— 它不描述任何硬件模块,却直接决定内核能否正常启动,这就是chosen节点。
    的头像 发表于 02-09 16:36 339次阅读
    深入理解<b class='flag-5'>设备</b><b class='flag-5'>树</b>chosen节点:固件与内核的“配置桥梁”

    Linux 6.8 内核 - 错误:找不到 cmdline 扁平化设备怎么解决?

    我正在尝试一个新的 6.8 linux 内核,但我在启动时收到这个错误: 从0x44000000到0x40200000的移动图像,end=41724000 错误:未找到 cmdline 扁平化设备
    发表于 02-09 07:13

    【瑞萨FPB-RA6E2试用】GPIO-按键控制LED灯亮灭及设备理解

    GPIO-按键控制LED灯亮灭及设备理解 0、视频教程 https://www.bilibili.com/video/BV1tximBqEg2/?vd_source
    发表于 01-13 14:44

    无线倾角传感器在古监测中的应用:以科技守护活文物的结构安全

    无线倾角传感器在古监测中的应用:以科技守护活文物的结构安全
    的头像 发表于 01-09 11:38 824次阅读
    无线倾角传感器在古<b class='flag-5'>树</b>监测中的应用:以科技守护活文物的结构安全

    【OK3506-S12Mini试用评测(二)】开发板SDK配置动态设备

    在配好的虚拟机的终端输入./build.sh bconfig,选择Kernal 进去之后选择图中选项(按Y确定) Defconfig name 需要在终端输入命令,才能得到需要写的名字。 动态设备的名字是在虚拟机中找到要用的的dts文件。
    发表于 11-19 17:09

    如何在AMD Vitis Unified IDE中使用系统设备

    您将在这篇博客中了解系统设备 (SDT) 以及如何在 AMD Vitis Unified IDE 中使用 SDT 维护来自 XSA 的硬件元数据。本文还讲述了如何对 SDT 进行操作,以便在 Vitis Unified IDE 中实现更灵活的使用场景。
    的头像 发表于 11-18 11:13 3402次阅读
    如何在AMD Vitis Unified IDE中使用系统<b class='flag-5'>设备</b><b class='flag-5'>树</b>

    E203工程源码时钟解析

    的system.v文件以及引脚约束文件,和rtl文件夹内的源码,我们参考源码绘制了E203在MCU200T的时钟,方便我们团队对E203源码的时钟进行修改,分享如下:
    发表于 10-29 07:25

    科技,被起诉

    电子发烧友网综合报道 天眼查显示,近日,杭州宇科技股份有限公司(以下简称“宇科技”)新增1条开庭公告,原告为杭州露韦美日化有限公司(以下简称“露韦美日化”),案由为侵害发明专利权纠纷,该案将于8
    的头像 发表于 08-26 07:50 5283次阅读
    宇<b class='flag-5'>树</b>科技,被起诉

    成都汇阳投资关于智元与宇拿下 1.24 亿订单,人形机器人商业化加速

    尺寸人形标包 1,宇中标4605万包含小尺寸人形、算力背包、五指灵巧手的标包。 2025年智元/宇频频出手 , 中标量可观 除本订单外 ,根据企查查数据 ,2025 年以来宇与智元均拿下诸多其他大订单。宇
    的头像 发表于 08-04 13:43 1445次阅读

    想在rtsmart中使用uart2,是不是只能通过修改设备方法来实现uart2的复用呀?

    我想在rtsmart中使用uart2,是不是只能通过修改设备方法来实现uart2的复用呀? 修改设备后如何只编译设备
    发表于 06-24 07:04