1. Device Tree简介

Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a fucking pain in the ass”,引发ARM Linux社区的地震,随后ARM社区进行了一系列的重大修正。在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。 社区必须改变这种局面,于是PowerPC等其他体系架构下已经使用的Flattened Device Tree(FDT)进入ARM社区的视野。Device Tree是一种描述硬件的数据结构,它起源于OpenFirmware(OF)。在Linux2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。

Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中):

  • CPU的数量和类别

  • 内存基地址和大小

  • 总线和桥

  • 外设连接

  • 中断控制器和中断使用情况

  • GPIO控制器和GPIO使用情况

它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备。这些设备用到的内存、IRQ等资源,也被传递给了kernel,kernel会将这些资源绑定给展开的相应的设备。

2. Device Tree编译

Device Tree文件的格式为dts,包含的头文件格式为dtsi,dts文件是一种人可以看懂的编码格式。但是uboot和linux不能直接识别,他们只能识别二进制文件,所以需要把dts文件编译成dtb文件。dtb文件是一种可以被kernel和uboot识别的二进制文件。把dts编译成dtb文件的工具是dtc。Linux源码目录下scripts/dtc目录包含dtc工具的源码。在Linux的scripts/dtc目录下除了提供dtc工具外,也可以自己安装dtc工具,linux下执行:sudo apt-get install device-tree-compiler安装dtc工具。其中还提供了一个fdtdump的工具,可以反编译dtb文件。dts和dtb文件的转换如图1所示。

dtc工具的使用方法是:dtc –I dts –O dtb –o xxx.dtb xxx.dts,即可生成dts文件对应的dtb文件了。

3.  早期Linux内核启动

早期的Linux内核(Linux-3.0以前)里的设备信息(platform_device)和驱动信息(platform_driver)都是通过C代码硬写入到Linux内核里去了,这些源文件都在arch/arm/mach-xxx或plat-xxx下:

例如我们移植Linux内核代码到FL2440开发板时,就会在设备文件arch/arm/mach-s3c2440/mach-smdk2440.c中作大量修改的,该文件就描述了开发板上所有的设备信息。

我们在编译Linux内核源码之后会生成zImage文件,该文件并不能直接被u-boot启动。之后需要使用u-boot里的mkimage工具生成uImage。

在将zImage转换成uImage文件后,我们在u-boot下就可以直接使用tftp 下载并通过bootm 命令启动Linux内核了。

U-Boot> tftp 30008000 linuxrom-s3c2440.bin && bootm 30008000

在前些年我们玩ARM Linux时大多是使用的这种方法。但自从Linus大神发飙之后,ARM社区几乎“一夜”之间将 arch/arm/mach-xxx 或 arch/arm/plat-xxx的代码全部废除,并不再支持。这也就是使用像S3C2440这样的开发板,最高Linux内核版本只能到Linux-3.0的原因。而最新的内核中所有硬件信息都必须通过arch/arm/boot/dts中的DTS(Device Tree Source)文件来描述。这样如果S3C2440想要升级到更高版本的Linux话,就必须自己重写S3C2440的DTS文件,当然很少有人愿意为一个停产的CPU做这些无用功的。

4.  设备树启动

Linux-3.x之后的内核统一启用Device Tree机制之后,所有的设备硬件信息描述都会放到 arch/arm/boot/dts/ 路径下的 xxx.dts文件中描述。这些dts(Device Tree Source)文件并不是C代码,而是具有相应语法格式的源文件。在编译内核时,我们可以使用 make dtbs 命令编译生成相应开发板的dtb(Device Tree Blob)文件。因为这些源文件并不是C程序,所以不是用gcc来编译,而是由其相应的编译工具dtc(Device Tree Compiler)来编译。

如下面我对Atmel SAMA5D44开发板移植Linux内核的编译过程和结果:

很显然,这里Linux内核uImage文件中只包含了Linux内核驱动相关的信息,而所有的设备硬件信息都在编译生成的at91-sama5d4_xplained.dtb设备树文件中。这也就意味着u-boot在启动时只有uImage是不够的,而是两个文件都需要。对于这种情况,u-boot在启动时需要这两个文件,同时bootm命令里还要指定它们加载到内存中的地址。如下所示:

5  设备树和uImage合并

参考上面的例子我们可以看到,在这里使用dtb文件会有一个很大的好处,即通过dtb文件将设备的硬件信息和Linux内核分离开了。这样也就意味着我们只需要编译一个Linux内核,然后加载不同的dtb文件,就可以为不同的硬件开发板服务了。譬如在上面的例子中,我使用同一个内核uImage,如果我想在Atmel的SAMA5D4 Xplained开发板上运行就只需要加载dtb文件at91-sama5d4_xplained.dtb即可; 而如果我们想启动开发板SAMA5D3 Xplained的话,只需要将DTB文件更新为at91-sama5d3_xplained.dtb即可,而不需更新uImage。这为今后的产品升级换代提供了很大的便利。

但嵌入式是一个软硬件高度定制的产品,我们一般很少使用这种特性。因为在生产时Linux系统内核要提供两个文件(uImage和dtb)并下载烧录,显得有点繁琐,这时我们更多地是希望将dtb和uImage打包到一个image中烧录启动。这时候可以分别通过Linux内核和u-boot来实现:

5.1  Linux内核append DTB

之所以Linux内核会提供这种方式是因为很多厂家都有自己的bootloader,但是这些bootloader并不都一定支持设备树,为了实现支持设备树启动,就引入了这种启动方式,即将编译出的zImage和编译出的设备树镜像文件拼成一个新的镜像,在内核的自解压代码中会识别到,不会出现自解压时导致设备树被覆盖。2016年在本人深圳消安做的一个LoRa物联网网关产品使用的Atmel的处理器AT91SAM9X35+Linux-4.1内核,在该内核代码中就是通过内核里支持的功能来合并uImage和dtb文件的。具体的实现方式是:

首先在内核make menuconfig的“Boot options  --->”选项里要选择:

在编译Linux内核生成uImage和dtb文件之后,使用cat命令将他们合并,然后再使用mkimage命令生成u-boot启动相关的uImage文件:

guowenxue@ubuntu-master: ~/linux-at91-linux4sam_5.3$  cat arch/arm/boot/dts/at91sam9x35ek.dtb >> arch/arm/boot/zImage

guowenxue@ubuntu-master: ~/linux-at91-linux4sam_5.3$  mkimage -A arm -O linux -n AT91SAM9X35EK -C NONE -a 0x20008000 -e 0x20008000 -d arch/arm/boot/zImage linuxrom-sam9x35ek.bin

guowenxue@ubuntu-master: ~/linux-at91-linux4sam_5.3$  chmod a+x linuxrom-sam9x35ek.bin

这样,在u-boot里直接下载生成的uImage文件启动即可。

U-Boot> tftp 22000000 linuxrom-sam9x35ek.bin && bootm 22000000

5.2  u-boot FIT image合并

最近接的马来西亚CoherentPlus的一个NFC支付读卡器项目,选用Atmel的Cortex A5处理器SAMA5D44,所使用的是Linux-4.9和U-Boot 2014.07。同样尝试上面SAM9X35的套路打包uImage和dtb文件并启动Linux内核时失败,U-boot启动时提示如下错误。毕竟现在已经是9102年了,在这里没有太大兴趣研究这种老的打包方式,而转向u-boot的全兴工作方式FIT Image。

我们知道,Linux kernel在ARM架构中引入device tree(全称是Flattened Device Tree,后续将会以FDT代称)的时候,其实怀揣了一个Unify Kernel的梦想----同一个Image,可以支持多个不同的平台。随着新的ARM64架构将FDT列为必选项,并将和体系结构有关的代码剥离之后,这个梦想已经接近实现。Device Tree在ARM架构中普及之后,u-boot也马上跟进、大力支持,毕竟,美好的Unify kernel的理想,需要bootloader的成全。为了支持基于device tree的unify kernel,u-boot需要一种新的Image格式,这种格式需要具备如下能力:

  1. Image中需要包含多个dtb文件;

  2. 可以方便的选择使用哪个dtb文件boot kernel;

是不是这样就感觉跟Linux内核一样Niubility了?没错!要的就是这种感觉。综合上面的需求,u-boot推出了全新的image格式----FIT uImage,其中FIT是flattened image tree的简称。它利用了Device Tree Source files(DTS)的语法,生成的image文件也和dtb文件类似(称作itb),下面是我们项目中的示例代码。:

guowenxue@ubuntu-master:~/sama5d4-sdk/linux-bsp/linux-at91$ cat linuxrom-sama5d4.its

/* U-Boot uImage source file for "sama5d4_xplained" */
/dts-v1/;
/ {description = "U-Boot uImage source file for SAMA5D4 Xplained";#address-cells = <1>;images {kernel@sama5d4 {description = "Linux kernel for SAMA5D4 Xplained";data = /incbin/("arch/arm/boot/zImage");type = "kernel";arch = "arm";os = "linux";compression = "none";load = <0x20008000>;entry = <0x20008000>;};fdt@sama5d4 {description = "Flattened Device Tree blob for SAMA5D4 Xplained";data = /incbin/("arch/arm/boot/dts/at91-sama5d4_xplained.dtb");type = "flat_dt";arch = "arm";compression = "none";};};configurations {default = "conf@sama5d4";conf@sama5d4 {description = "Boot Linux kernel with FDT blob";kernel = "kernel@sama5d4";fdt = "fdt@sama5d4";};};
};

上面的代码是不是很眼熟?没错,就是跟Linux内核树里的DTS文件语法一样,里面的一些参数就是mkimage制作uImage时的一些参数。在编译生成Linux内核zImage和dtb文件之后,我们只需要使用mkimage命令就可以生成相应的itb文件了。当然,上面的文件遵循dts语法,那他的编译就需要dtc编译器,默认ubuntu并没有安装该命令,所以在使用之前还得安装相应的命令,好在ubuntu下都提供了,如果没有可以在u-boot或linux内核下去找:

guowenxue@ubuntu-master:~/sama5d4-sdk/linux-bsp/linux-at91$ sudo apt-get install u-boot-tools device-tree-compiler

guowenxue@ubuntu-master:~/sama5d4-sdk/linux-bsp/linux-at91$ mkimage -f linuxrom-sama5d4.its linuxrom-sama5d4.itb

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

FIT description: U-Boot uImage source file for SAMA5D4 Xplained

Created:         Fri Aug 23 21:43:12 2019

Image 0 (kernel@sama5d4)

  Description:  Linux kernel for SAMA5D4 Xplained

  Created:      Fri Aug 23 21:43:12 2019

  Type:         Kernel Image

  Compression:  uncompressed

  Data Size:    4879744 Bytes = 4765.38 kB = 4.65 MB

  Architecture: ARM

  OS:           Linux

  Load Address: 0x20008000

  Entry Point:  0x20008000

Image 1 (fdt@sama5d4)

  Description:  Flattened Device Tree blob for SAMA5D4 Xplained

  Created:      Fri Aug 23 21:43:12 2019

  Type:         Flat Device Tree

  Compression:  uncompressed

  Data Size:    32670 Bytes = 31.90 kB = 0.03 MB

  Architecture: ARM

Default Configuration: 'conf@sama5d4'

Configuration 0 (conf@sama5d4)

  Description:  Boot Linux kernel with FDT blob

  Kernel:       kernel@sama5d4

  FDT:          fdt@sama5d4

既然是全新的东西,u-boot默认并不一定支持。如果要U-boot支持FIT Image启动的话,我们还得在u-boot的配置文件中添加它的支持,即加上 CONFIG_FIT 宏定义即可:

guowenxue@ubuntu-master:~/sama5d4-sdk/linux-bsp/u-boot-at91$ vim include/configs/sama5d4_xplained.h

/* add by guowenxue, 2019.08.22 */
#define CONFIG_FIT              1
#define CONFIG_ENV_OVERWRITE    1
#define CONFIG_ETHADDR          42:96:ab:be:a7:5e
#define CONFIG_IPADDR           192.168.2.199
#define CONFIG_SERVERIP         192.168.2.2

编译升级u-boot之后,我们则可以直接启动该itb文件了。启动过程如下所示:

6  PS:

本文档主要是讲解Linux内核设备树的使用,并不涉及到Device Tree Source的语法和原理,如果有需要的请自行百度、参考Linux内核里的设备树文件学习。

Linux内核DTB文件启动的几种方式相关推荐

  1. 两台Linux主机之间文件传输的几种方式

    Linux文件传输的五种方式 FTP : FTP是文件服务器,可实现文件的上传下载,存储等功能,但本文不打算介绍ftp的使用. scp: scp能够将不同主机的文件进行相互传输,使用简单方便. rz ...

  2. Linux内核Makefile文件

    Linux内核Makefile文件(翻译自内 核手册) 转载自:http://blog.chinaunix.net/uid-21651676-id-60377.html Linux 内核Makefil ...

  3. Linux 内核/sys 文件系统介绍

    http://blog.csdn.net/sfrysh/article/details/5788446 sysfs 是 Linux 内核中设计较新的一种虚拟的基于内存的文件系统,它的作用与 proc ...

  4. Linux内核编译、启动和相关驱动构建

    Linux内核编译.启动和相关驱动构建 01 修改与编译内核 前面小哥主要是跟大家讲解了uboot的烧录.使用等等,而对于嵌入式Linux环境而言其实主要是分为三大块 : uboot,Linux Ke ...

  5. linux 内核 目录文件说明

    本文使用的源代码是Linux kernel 3.9.4. 下载地址:https://mirrors.edge.kernel.org/pub/linux/kernel/v3.x/linux-3.9.4. ...

  6. LINUX内核目录文件说明

    内核空间和用户空间 在下载内核前,我们应该讨论一些重要的术语和事实.首先了解一下内核空间和用户空间 内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据.不管是内核空间还是 ...

  7. Linux 内核的文件 Cache 管理机制介绍

    1 前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使用得非常广泛,它与 Windows.UNIX 一起占据了操作系统领域几乎所有的市场份额.特别是在高性能计算 ...

  8. linux的头文件下载,Linux内核头文件(linux headers)

    更新 Linux 内核头文件(linux headers) 三 8th, 2013 2,474 views | 发表评论 | Trackback 一般来说,如果不是自己编译 kernel,那么更新头文 ...

  9. Linux 内核dts文件是怎么一回事?

    一个CPU可能对应多个平台,为了方便开发,只能这么做,dts文件和dtsi文件相当于C语言的.c和.h文件.一样可以包含,下面以BBB的DTS文件分析学习格式规范. 涉及的文件包含: am33xx.d ...

  10. linux内核的文件组织形式

    文章目录 前言 1. Linux内核体系结构 2. 内核引导与启动 BIOS/OF BIOS功能 引导装入程序(Boot Loaders) BIOS 与boot loader及内核加载流程 GNU G ...

最新文章

  1. 180万奖金!数据挖掘,NLP,CV等23个赛道,2020 科大讯飞AI大赛正式发布!
  2. partial in latex
  3. 希尔排序(C++版)
  4. java教程pdf下载百度云,面试题+笔记+项目实战
  5. C/C++的readdir和readdir_r函数(遍历目录)
  6. 上学的时候的一个作业
  7. java jodd_Jodd :一款优雅的 Java 工具集
  8. 程序MD5校验的作用
  9. jeval 公式_几款公式解析工具的比较
  10. java泛型特点_Java泛型
  11. 一加nfc门禁卡录入_Card Emulator(NFC卡模拟):一加5NFC模拟门禁卡|饭卡|电梯卡 工卡 借书卡...
  12. 数据库设计的阶段任务
  13. 人人都需要知道的理财知识
  14. Android一点 play商店地区与语言设置
  15. 数据库优化整理之:冷热分离
  16. [Asp.Net Core]鉴权授权
  17. 黑苹果0x0501_黑苹果原版安装从零开始---3-clover配置篇
  18. RMQ与SparseTable(ST表)
  19. Twincat 3 初识
  20. 1. 【Part3】 Contour Detection and Hierarchical Image Segmentation【轮廓检测图像分割】

热门文章

  1. [leetcode] Nim Game
  2. 在windows生产环境搭建sphinx的注意事项
  3. 「实战篇」开源项目docker化运维部署-搭建mysql集群(四)
  4. Ubuntu Apache 不同端口监听不同站点
  5. OkHttp3用法全解析
  6. MySQL更新死锁问题
  7. 重载类型转换操作符(overload conversion operator)
  8. 认识linux,走进开源世界。
  9. u-boot环境的擦除,默认设置,批写入
  10. FriendStyle CSS