[Android O] [RK3399] -- Uboot 解析 parameter.txt 及 Uboot 向内核传递 DTB 分析

概述

Rockchip android 系统平台使用 parameter 文件来配置一些系统参数,比如定义串口号,固件版本,nand flash 分区信息等等。Parameter 的参数是由 BootLoader 解析的。另外,Parameter 文件也是 upgrade_tool (rockchip 烧录工具) 烧录系统的依据,这点很重要,由此可知为何 BootLoader 通过解析 Parameter 文件即可获取到系统的烧录信息与相关参数。

DTB文件可以存放于 android 标准格式的 boot/recovery 分区中,也可以存放于 resource 分区。U-boot 假定 kernel 启动必须加载 dtb 文件,dtb 由 Uboot 传递给 kernel。


 

Uboot 对 Parameter.txt 的解析

解析代码位于:u-boot/board/rockchip/common/rkloader/parameter.c

调用过程如下:

load_disk_partitions(void)
                GetParam(0, param) -------- 从 0 地址中获取 param,也从侧面反应 upgrade_tool 将 parameter.txt 烧写到 0 地址中
                        StorageReadLba(param_addr+i*PARAMETER_OFFSET, buf, read_sec) -------- 读取 param
                ParsePara(&gBootInfo, param->parameter, param->length) -------- 若 GetParam成功,就解析 param
                        ParseLine(info, line) -------- 按行解析 parameter 文件

经过以上的解析之后,Uboot 就获取到了 parameter.txt 文件中的系统信息。

由其中可知: upgrade_tool 会将 parameter.txt 烧写到 0x00000000 的地址中。


Uboot 传送 DTB 到内核

设备树的概念

设备树是一种描述硬件支援的数据结构,它通过 BootLoader 将硬件资源传给内核,使得内核和硬件资源描述相对独立。

Device Tree 可以描述的信息包括 CPU 的数量和类型,内存基地址和大小,总线和桥,外设链接,中断控制器和中断使用情况,GPIO 控制器和 GPIO 使用情况,Clock 控制器和 Clock 使用情况。

另外,设备树对于可热插拔的设备不进行具体描述,它只描述用于控制该热插拔设备的控制器。

设备树的主要优势:对于同一个 SOC 的不同主板,只需要更换设备树文件 .dtb 即可实现不同主板的无差异支持,而无需更换内核文件。

注:要使得内核支持使用设备树,除了内核编译时需要打开相对应的选项外,BootLoader 也需要支持将设备树的数据结构传给内核。

BootLoader(BootLoader支持)

DTC 编译 .dts 生成二级制文件 .dtb,BootLoader 在引导内核的时,会预先读取  .dtb 到内存,进而由内核解析。

BootLoader 需要将设备树在内存中的地址传给内核,在 ARM 中通过 bootm 或 bootz 命令来进行传递。

bootm [kernel_addr] [initrd_address] [dtb_address],其中kernel_addr为内核镜像的地址,initrd为initrd的地址,dtb_address为dtb所在的地址。若initrd_address为空,则用“-”来代替。

Linux 内核对硬件的描述方式

在以前的版本中:

  1.  内核包含了对硬件的全部描述;
  2.  BootLoader 会加载一个二进制的内核镜像,并执行它,比如 uImage 或者 zImage;
  3.  BootLoader 会提供一些额外的信息,成为 ATAGS,它的地址会通过 r2 寄存器传给内核;ATAGS 包含了内存大小和地址,kernel command line 等等;
  4.  BootLoader 会告诉内核加载哪一款 board,通过 r1 寄存器存放的 machine type integer;
  5.  U-Boot 的内核启动命令:bootm
  6.  Barebox 变量:bootm.image (?)

[Android O] [RK3399] -- Uboot 解析 parameter.txt 及 Uboot 向内核传递 DTB 分析_第1张图片

现今的内核版本使用了 Device Tree:

  1.  内核不再包含对硬件的描述,它以二进制的形式单独存储在另外的位置:the device tree blob
  2.  BootLoader 需要加载两个二进制文件:内核镜像和 DTB
    内核镜像仍然是 uImage 或者 zImage;
    DTB 文件在 arch/arm64/boot/dts 中,每一个 board 对应一个 dts 文件;
  3.  BootLoader 通过 r2 寄存器来传递 DTB 地址,通过修改 DTB 可以修改内存信息,kernel command line(chosen 节点),以及潜在的其他信息;
  4.  不再有 machine type;
  5.  U-Boot 的内核启动命令:bootm -
  6.  Barebox 变量:bootm.image,bootm.oftree

[Android O] [RK3399] -- Uboot 解析 parameter.txt 及 Uboot 向内核传递 DTB 分析_第2张图片

DTS chosen 节点

DTS chosen 节点位于根节点下,该节点用来给内核传递参数,对于 Linux 内核,该节点下最有用的属性是 bootargs,该属性的类型是字符串,用来向 Linux 内核传递 cmd_line。

/{
    chosen {
        bootargs = "earlycon=uart8250,mmio32,0xff1a0000 swiotlb=1 coherent_pool=1m";
    };
};

DTB 加载及解析过程

DTS ----> DTB --(传给内核)--> 内核解析DTB ----> device_node ----> platform_device

系统应该会根据 Device Tree 来动态的增加系统中的 platform_device。当然,这个过程并非只发生在 platform_bus 上,例如 AMBA 总线,PCI 总线。一言以蔽之,如果要并入 Linux kernel 的设备驱动模型,那么就需要根据 device_node 的树状结构(root 是 of_allnodes)将一个个的 device node 挂入到相应的总线 device 链表中。只要做到这一点,总线机制就会安排 device 和 driver 的约会。当然,也不是所有的 device node 都会挂入 bus 上的设备链表,比如 cpus node,memory node,chosen node  等。

解析加载过程总结为:

  1.  kernel 入口处获取到 Uboot 传过来的 .dtb 镜像的基地址
  2.  通过 early_init_dt_scan() 函数来获取 kernel 初始化时需要的 bootargs 和 cmd_line 等系统引导参数
  3.  调用 unflatten_device_tree 函数来解析 dtb 文件,构建一个由 device_node 结构连接而成的单向链表,并使用全局变量 of_allnodes 保存这个链表的头指针
  4.  内核调用 OF 的 API 接口,获取 of_allnodes 链表信息来初始化内核其他子系统、设备等。

 

本文参考文章:https://blog.csdn.net/u014650722/article/details/79076352
         在此特别感谢!!!

 

 

 

 

 

你可能感兴趣的:(AndroidO,RK3399)