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

    文章

    48

    浏览量

    11036

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

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

收藏 人收藏

    评论

    相关推荐

    MCP251X can驱动移植nuc980采样用设备配置时,中断如何配置设备?

    MCP251X can驱动移植nuc980 采样用设备配置时,中断如何配置设备? spi0: spi@b0061000 { status = \"okay\"
    发表于 01-17 06:43

    NUC980设备DTB文件如何通过NUWrite烧录到SPI-Flash中,烧录的地址是多少?

    NUC980设备DTB文件如何通过NUWrite烧录到SPI-Flash中,烧录的地址是多少;内核编译设备后卡死在“Calibrating delay loop... ”是什么问题
    发表于 01-17 06:29

    如何修改内核设备

    本文档介绍了内核设备的位置和包含关系 1.内核设备位置 文件 备注 dts longan/device/config/chips/t507/configs/evb/board.dt
    发表于 12-14 13:42

    【米尔-TIAM62开发板-接替335x-试用评测】+(三)手把手创建Uboot设备与内核设备实战

    子节点,以进一步描述硬件的详细信息。例如,网络接口节点可能包含一个子节点,描述MAC地址、IP地址等信息。 当U-Boot或Linux内核引导时,它们会读取和解析这个设备文件,以了解系统硬件的配置
    发表于 11-28 09:54

    在Linux启动过程中, 想将PC13 pin配置为输出/拉起,如何修改设备

    在 Linux 启动过程中, 我想将 PC13 pin 配置为输出/ 拉起 。 我该如何修改设备
    发表于 11-13 06:21

    迅为RK3588开发板Android12单摄方案设备修改

    打开 3588-android12/kernel-5.10/arch/arm64/boot/dts/rockchip/topeet_camera_config.dtsi 设备,此设备
    发表于 10-19 15:14

    【昉·星光 2 高性能RISC-V单板计算机体验】设备如何加载

    我们有时候需要自己编译一个设备,然后更新到设备中,我本次测试时候改变了I2C接口的IO,结果编译完成后更新过去没有反应。想问下到底应该更新到哪个目录下才能生效。** 首先就是修改linux源码下
    发表于 08-13 14:33

    在CubeMX上面配合STM32MP135D的DDR设备后,烧录程序的问题求解

    在烧录程序之前,我已经将生成的所有设备参数替换到原程序中,请问有人能指导一下我是哪里处理出了问题吗
    发表于 08-07 09:16

    根据NUC980LinuxBsp内核配置中开启设备后Linux内核无法启动怎么解决?

    根据NUC980LinuxBsp内核配置中开启设备后Linux内核无法启动
    发表于 06-27 07:26

    请问驱动能不能设备和传统方式同时用?

    有的驱动用设备有的驱动不用能这样吗?
    发表于 06-25 09:39

    如何使用设备插件dtbo?

    我想使用设备插件,但我不知道如何部署它
    发表于 06-07 09:00

    如何在yocto中创建新相机(IMX219)设备文件和.ko文件?

    我正在研究 I.MX 8 QM SBC。我需要如何在 yocto 中创建新相机(IMX219)设备文件和 .ko 文件的步骤。
    发表于 05-24 07:29

    如何在iMX7D上的uboot设备中设置EIM?

    我在 iMX7D 上的 uboot 设备中设置了 EIM。如果标签名称是 &eim 或 &weim,将出现“未找到”错误。 我想知道正确的标签名称。 如果恩智浦有像 STmicro 那样的支持文档就好了。
    发表于 05-19 06:16

    求分享iMX8QM ESAI的设备实例

    我正在使用 Linux 5.15 开发基于 iMX8QM 的 SoM Apalis iMX8。两个音频解码器(只需要 TX)将连接到 iMX8QM ESAI0 接口,如附图所示。从内核源代码中,我没有找到可供参考的设备实例。您是否有此类实施的公开文件?
    发表于 05-18 08:33

    QCVS设备编辑器不工作怎么解决?

    我将 Code Warrior 用于 PA 10.5.1 和 QCVS 4.5。 我正在尝试使用硬件设备功能,但它给我带来了麻烦。 联机帮助说 GUI 编辑器提供了用于添加、编辑和删除节点的插入
    发表于 05-06 08:45