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

    浏览量

    11164

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

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

收藏 人收藏

    评论

    相关推荐

    adc128s052设备配置,基准电压不能被内核识别是怎么回事?

    这是目前我配置的设备信息,不能通过编译,原因是无法识别vdd_supply,请问该处该怎么配置才行,我用的是该芯片的VA引脚接 3.3V的基准电压 compatible = \"ti
    发表于 11-29 16:00

    请问PCM1864的驱动在设备该如何描述?

    请问PCM1864的驱动在设备该如何描述呢: 1. 我使用的不是TI的LINUX内核,是另外一款SOC的LINUX内核 2. 我在设备做了以下描述: ps7-i2c@e00040
    发表于 10-23 07:30

    什么是默克尔(Merkle Tree)?如何计算默克尔根?

    01 默克尔的概念 默克尔(Merkle Tree)是一种特殊的二叉,它的每个节点都存储了一个数据块的哈希值。哈希值是一种可以将任意长度的数据转换为固定长度的字符串的算法,它具有唯一性和不可
    的头像 发表于 09-30 18:22 861次阅读
    什么是默克尔<b class='flag-5'>树</b>(Merkle Tree)?如何计算默克尔根?

    【北京迅为】iTOP-i.MX6开发板使用手册第四部分固件编译第十四章非设备Android4.4系统编译

    【北京迅为】iTOP-i.MX6开发板使用手册第四部分固件编译第十四章非设备Android4.4系统编译
    的头像 发表于 09-12 15:43 508次阅读
    【北京迅为】iTOP-i.MX6开发板使用手册第四部分固件编译第十四章非<b class='flag-5'>设备</b><b class='flag-5'>树</b>Android4.4系统编译

    如何配置Linux操作系统设备让我的开发板可以将板子上的GPIO接口用作 I2S输出??

    ALSA),我打算使用最新的Debian 11操作系统。 想问一下如何在 Linux 设备中进行调整来配置和使用所需的GPIO引脚作为 I2S。
    发表于 08-13 17:10

    使用CYUSB3014将电路连接到PC时,它没有出现在设备管理器中,为什么?

    当我将一块使用 CYUSB3014 的电路板连接到 PC 时,设备管理器中的设备会随着连接的更新而更新,但设备中显示的内容却没有任何变化
    发表于 07-05 08:28

    如何使用CubeMX生成的设备编译镜像?

    我的硬件平台是MP135,我现在想给它增加一个串口UART8,于是我打算修改设备。但是在使用SDK的时候我遇到了些问题。按照官方的`how to do.txt`,我编译了u-boot,在
    发表于 05-31 14:41

    原理图设计里两颗重要的(国产EDA)

    原理图里面两颗重要的,那就是元件和网络,作为EDA工具中的重要视图和概念,虽然看似枯燥,但它们扮演着非常重要的角色,它们为电路图的层次化结构提供了有力支撑。想象一个大型的电路设计项目,就像一个
    的头像 发表于 05-29 17:47 743次阅读
    原理图设计里两颗重要的<b class='flag-5'>树</b>(国产EDA)

    把JH7110.fd文件通过tftp烧进flash后,出现了找不到设备的问题怎么解决?

    JH7110.fd文件通过tftp烧进flash后,出现了找不到设备的问题,这个dtb文件应该怎么打包进fd文件中呢
    发表于 05-24 06:35

    圣诞灯电路图分享

    圣诞装饰的电路分为两个主要部分,即灯光和声音部分。照明部分由五组 LED 组成,它们以二进制顺序运行,每隔几分钟就会重复一次。在这里,根据我们的兴趣,LED 可以是任何颜色。这件装饰品可以装饰您的圣诞以及您的家。
    的头像 发表于 05-05 10:12 1029次阅读
    圣诞<b class='flag-5'>树</b>灯电路图分享

    如何使用Yocto更新已更改的TF-A设备来产生新的镜像文件?

    求助大佬, 我用Yocto构建了STM32MP157的镜像文件,但我需要更改和移植TF-A和U-BOOT来适配我的板子, 我按照它正点原子教程里更改了.bl2和创建了新的.dtsi设备文件,但
    发表于 03-29 08:01

    全面认识PCIe基础与设备

    CXL(Compute Express Link)是一种业界支持的高速缓存一致性互连协议,用于处理器、内存扩展和加速器之间的通信。
    发表于 03-20 13:56 2684次阅读
    全面认识PCIe基础与<b class='flag-5'>设备</b><b class='flag-5'>树</b>

    在CubeMX上面配合STM32MP135D的DDR设备后,烧录程序时产生了报错怎么解决?

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

    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