泰晓科技 -- 聚焦 Linux - 追本溯源,见微知著!
网站地址:https://tinylab.org

泰晓RISC-V实验箱,转战RISC-V,开箱即用
请稍侯

Device Tree 初探

iosdevlog 创作于 2022/09/27

Author: iOSDevLog iosdevlog@iosdevlog.com Date: 2022/07/01 Project: RISC-V Linux 内核剖析 Sponsor: PLCT Lab, ISCAS

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-xxxarch/arm/mach-xxx 中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的 platform 设备、resource、i2c_board_info、spi_board_info 以及各种硬件的 platform_data。

社区必须改变这种局面,于是 PowerPC 等其他体系架构下已经使用的 Flattened Device Tree(FDT)进入 ARM 社区的视野。

Device Tree 是一种描述硬件的数据结构,它起源于 OpenFirmware(OF)。

在 Linux 2.6 中,ARM 架构的板极硬件细节过多地被硬编码在 arch/arm/plat-xxxarch/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 会将这些资源绑定给相应的设备。

术语

  • AMP
    • Asymmetric Multiprocessing.
    • 非对称多处理器。
    • Computer available CPUs are partitioned into groups, each running a distinct operating system image.
    • 计算机中的 CUPs 中被划成组,每个组运行不同的系统镜像。
    • The CPUs may or may not be identical.
    • CPUs 不一定是相同的。
  • boot CPU
    • The first CPU which a boot program directs to a client program’s entry point.
    • 运行引导程序跳转到客户端程序入口的 CPU。
  • Book III-E
    • Embedded Environment.
    • 嵌入式环境。
    • Section of the Power ISA defining supervisor instructions and related facilities used in embedded Power processor implementations.
    • Power ISA 中的一个章节,用于定义嵌入式 Power 处理器具体实现中的监控指令和相关设施。
  • boot program
    • Used to generically refer to a software component that initializes the system state and executes another software component referred to as a client program.
    • 用于泛指初始化系统状态并执行另一个称为客户端程序的软件组件。
    • Examples of a boot program include: firmware, bootloaders, and hypervisors.
    • 引导程序的示例包括:固件、引导加载程序和虚拟机管理程序。
  • client program
    • Program that typically contains application or operating system software.
    • 通常包含应用程序或操作系统软件的程序。
    • Examples of a client program include: bootloaders, hypervisors, operating systems, and special purpose programs.
    • 客户端程序的示例包括:引导加载程序、虚拟机管理程序、操作系统和特殊用途程序。
  • cell
    • A unit of information consisting of 32 bits.
    • 由 32 位组成的信息单位。
  • DMA
    • Direct memory access
    • 直接内存访问。
  • DTB
    • Devicetree blob.
    • 设备树 blob。
    • Compact binary representation of the devicetree.
    • 设备树的紧凑二进制表示形式。
  • DTC
    • Devicetree compiler.
    • 设备树编译器。
    • An open source tool used to create DTB files from DTS files.
    • 用于从 DTS 文件创建 DTB 文件的开源工具。
  • DTS
    • Devicetree syntax.
    • 设备树语法。
    • A textual representation of a devicetree consumed by the DTC.
    • 被 DTC 使用的设备树的文本表示形式。
    • See Appendix A Devicetree Source Format (version 1).
    • 请参阅附录 A 设备树源格式(版本 1)。
  • effective address
    • Memory address as computed by processor storage access or branch instruction.
    • 由处理器存储访问或分支指令计算的内存地址。
  • physical address
    • Address used by the processor to access external device, typically a memory controller.
    • 处理器用于访问外部设备(通常是存储器控制器)的地址。
  • Power ISA
    • Power Instruction Set Architecture.
    • Power 指令集架构。
  • interrupt specifier
    • A property value that describes an interrupt.
    • 描述中断的属性值。
    • Typically information that specifies an interrupt number and sensitivity and triggering mechanism is included.
    • 通常包括指定中断号、灵敏度和触发机制的信息。
  • secondary CPU
    • CPUs other than the boot CPU that belong to the client program are considered secondary CPUs.
    • 属于客户端程序的引导 CPU 以外的 CPU 被视为辅助 CPU。
  • SMP
    • Symmetric multiprocessing.
    • 对称多处理。
    • A computer architecture where two or more identical CPUs can share memory and IO and operate under a single operating system.
    • 一种计算机体系结构,其中两个或多个相同的 CPU 可以共享内存和 IO,并在单个操作系统下运行。
  • SoC
    • System on a chip.
    • 片上系统。
    • A single computer chip integrating one or more CPU core as well as number of other peripherals.
    • 集成一个或多个 CPU 内核以及许多其他外设的单个计算机芯片。
  • unit address
    • The part of a node name specifying the node’s address in the address space of the parent node.
    • 节点名称的一部分,用于指定父节点的地址空间中的节点地址。
  • quiescent CPU
    • A quiescent CPU is in a state where it cannot interfere with the normal operation of other CPUs.
    • 休眠的 CPU 处于无法干扰其他 CPU 正常运行的状态。
    • nor can its state be affected by the normal operation of other running CPUs.
    • 其状态也不会受到其他正在运行的 CPU 正常运行的影响。
    • except by an explicit method for enabling or re-enabling the quiescent CPU.
    • 除非通过显式方法启用或重新启用静态 CPU。

The DeviceTree Specification 设备树规范

A devicetree is a data structure for describing hardware.

设备树是用于描述硬件的数据结构。

在设备树的官方网站这样写着:

Welcome to devicetree.org 欢迎来到 devicetree.org

If you are looking for the devicetree specification you’ve come to the right place! 如果您正在寻找设备树规范,那么您来对地方了!

Devicetree.org 是许多公司和个人为促进 Devicetree 标准的未来发展而做出的社区努力。

无需将设备的每个细节硬编码到操作系统中,硬件的许多方面都可以在引导时传递给操作系统的数据结构中进行描述。

该设备树由 OpenFirmware,OpenPOWER 抽象层(OPAL),Power Architecture Platform Requirements(PAPR)和独立的扁平设备树(FDT)形式使用。

设备树规范提供了设备树数据格式和最佳做法的完整技术说明。

在这里可以下载到最新的设备树规范 v0.4-rc1.

打开最新的规范,发现版本是:

Devicetree Specification Release v0.3-40-g7e1cc17

查看一下目录,规范分了以下六章。

  • 第一章:介绍设备树规范的结构
  • 第二章:介绍设备树概念和描述它的逻辑结构和标准属性
  • 第三章:阐述 DTSpec-compliant 设备树要求的设备节点基本集合的定义
  • 第四章:具体的设备 (类型) 的设备 bindings
  • 第五章:设备树的 DTB 编码
  • 第六章:DTS 语法

In computing, a devicetree (also written device tree) is a data structure describing the hardware components of a particular computer so that the operating system’s kernel can use and manage those components, including the CPU or CPUs, the memory, the buses and the integrated peripherals.

在计算中,设备树 devicetree(也写作 device tree)是描述特定计算机的硬件组件的数据结构,以便操作系统的内核可以使用和管理这些外设。

The device tree was derived from SPARC-based computers via the Open Firmware project. The current Devicetree specification is targeted at smaller systems, but is still used with some server-class systems (for instance, those described by the Power Architecture Platform Reference).

设备树是通过开放固件项目从基于 SPARC 的计算机派生的。当前的 Devicetree 规范针对的是较小的系统,但仍与某些服务器级系统(例如,Power Architecture 平台参考中描述的系统)一起使用。

Personal computers with the x86 architecture generally do not use device trees, relying instead on various auto configuration protocols (e.g. ACPI) to discover hardware. Systems which use device trees usually pass a static device tree (perhaps stored in ROM) to the operating system, but can also generate a device tree in the early stages of booting.

具有 x86 体系结构的个人计算机通常不使用设备树,而是依靠各种自动配置协议(例如 ACPI)来发现硬件。使用设备树的系统通常会将静态设备树(可能存储在 ROM 中)传递给操作系统,但也可以在启动的早期阶段生成设备树。

As an example, Das U-Boot and kexec can pass a device tree when launching a new operating system.

例如,Das U-Boot 和 kexec 可以在启动新操作系统时传递设备树。

On systems with a boot loader that does not support device trees, a static device tree may be installed along with the operating system; the Linux kernel supports this approach.

在不支持设备树的引导加载程序的系统上,静态设备树可以与操作系统一起安装。Linux 内核支持这种方法。

The Devicetree specification is currently managed by a community named devicetree.org, which is associated with, among others, Linaro and Arm.

Devicetree 规范目前由一个名为 devicetree.org 的社区管理,该社区与 Linaro 和 Arm 等相关联。

Device Tree 编译

Device Tree 文件的格式为 dts,包含的头文件格式为 dtsidts 文件是一种人可以看懂的编码格式。

但是 U-Boot 和 Linux 不能直接识别,他们只能识别二进制文件,所以需要把 dts 文件编译成 dtb 文件。

dtb 文件是一种可以被 Kernel 和 U-Boot 识别的二进制文件。

把 dts 编译成 dtb 文件的工具是 dtc。

Linux 源码下 scripts/dtc 目录包含 dtc 工具的源码。

除了使用在 Linux 的 scripts/dtc 目录下提供 dtc 工具外,也可以自己安装 dtc 工具。

比如,在 Ubuntu 下可执行如下命令安装 dtc:

$ sudo apt install device-tree-compiler

dtc 包中还提供了一个 fdtdump 的工具,可以反编译 dtb 文件。

dtc 工具的使用方法是:

$ make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
$ make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- dtbs
  DTC     arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dtb
  DTC     arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dtb
  DTC     arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dtb
$ dtc –I dts –O dtb –o xxx.dtb xxx.dts
$ dtc –I dtb –O dts –o xxx.dts xxx.dtb
$ fdtdump xxx.dtb > xxx.dts

Device Tree 实例展示

我们首先 dump 出 QEMU 使用的 dts:

$ qemu-system-riscv64 -bios \
    /labs/linux-lab/boards/riscv64/virt/bsp/bios/opensbi/generic/fw_jump.elf \
    -M virt,dumpdtb=dump.dtb -nographic
$ dtc -o dump.dts -O dts -I dtb dump.dtb

接下来,再写一个 dts.ko 内核模块来生成 Graphviz 支持的 dot 文件:

  1. 加载自己写的 dts.ko,使用 pr_err() 输出到 /dev/kmsg
  2. dmesg > dts.dot 生成 dot 文件
  3. dot -Tsvg dts.dot -o dts.svg 生成最终的图片

经过以上步骤,将 Linux Lab 下的 riscv64/virt 生成如下图的设备树示例:

riscv64_virt_dts

这种实现方式还不完善,不过生成的图可以大概看出设备树的整体结构。

将生成的示例和通过 /proc/device-tree/ 观察到的结果进行对比。

# tree -d /proc/device-tree/
/proc/device-tree/
|-- chosen
|-- cpus
|   |-- cpu-map
|   |   `-- cluster0
|   |       |-- core0
|   |       |-- core1
|   |       |-- core2
|   |       `-- core3
|   |-- cpu@0
|   |   `-- interrupt-controller
|   |-- cpu@1
|   |   `-- interrupt-controller
|   |-- cpu@2
|   |   `-- interrupt-controller
|   `-- cpu@3
|       `-- interrupt-controller
|-- fw-cfg@10100000
|-- memory@80000000
|-- reserved-memory
|   `-- mmode_resv0@80000000
`-- soc
    |-- clint@2000000
    |-- flash@20000000
    |-- pci@30000000
    |-- plic@c000000
    |-- poweroff
    |-- reboot
    |-- rtc@101000
    |-- test@100000
    |-- uart@10000000
    |-- virtio_mmio@10001000
    |-- virtio_mmio@10002000
    |-- virtio_mmio@10003000
    |-- virtio_mmio@10004000
    |-- virtio_mmio@10005000
    |-- virtio_mmio@10006000
    |-- virtio_mmio@10007000
    `-- virtio_mmio@10008000

38 directories

可以看到:

  1. 设备树有一个根节点
  2. 每个节点有父节点,子节点(只有一个)和兄弟节点(也是一个)
  3. 图例生成的结构和通过 /proc/device-tree/ 观察到结构一致
  4. 图例生成的结构与 QEMU dump 出的 dump.dts 不一致,这个我们后面再分析一下原因

总结

本文介绍了 Linux 使用设备树的原因,设备树规范及一些术语,还介绍了如何编译设备树。

接下来几篇文章,会参考 devicetree-specification-v0.4-rc1.pdf 依次介绍第二章到第六章的内容。

了解了设备树的语法之后,我们再详细剖析设备树的源码。

参考

  1. Devicetree Specification
  2. Devicetree-Wikipedia
  3. Linux 和 Devicetree


Read Album:

Read Related:

Read Latest: