# 前言
完整的 linux 系統需要以下部分:
- Bootloader
- boot.img
- Linux Kernel(Linux 内核)
- Device tree blob
- Root Filesystem(根目录文件系統)
# bootloader
bootloader(引导装载程序)就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境设置成一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。
常见的 bootloader 有 PC 平台的 Grub;嵌入式平台的 vivi, RedBoot, u-boot 等,其中 u-boot 在使用上最广泛,因此在嵌入式中又常称 linux 系统构成为 u-boot、kernel、rootfs。
bootloader 是严重地依赖于硬件而实现的,特别是在嵌入式系统。因此,在嵌入式系统里建立一个通用的 bootloader 几乎是不可能的。尽管如此,我们仍然可以对 bootloader 归纳出一些通用的概念来,以指导用户进行特定的 bootloader 设计与实现。
在嵌入式系统中,bootloader 的意义与作用相当于 PC 平台中的 BIOS + Grub,它对开发板上的主要部件如 CPU、SDRAM、FLASH、串口等进行了初始化,可以使用 bootloader 下载文件到开发板,可以浏览目录,可以烧录 flash,可以启动系统等,实际上,一个功能比较强大的 bootloader 已经相当于一个微型的操作系统了。
总体上 bootloader 需要完成以下工作:
初始化 CPU 速度;
初始化内存,包括初始化内存配置寄存器等;
初始化中断控制器,在系统启动时,关闭中断,关闭看门狗;
初始化串行端口(如果在目标上有的话);
启用指令 / 数据高速缓存;
设置堆栈指针;
设置参数区域并构造参数结构和标记(这是重要的一步,因为内核在标识根设备、页面大小、内存大小以及更多内容时可能需要使用引导参数);
执行 POST(加电自检)来标识存在的设备并报告有何问题;
为电源管理提供挂起 / 恢复支持;
传输操作系统内核镜像文件到目标机。也可以将操作系统内核镜像文件事先存放在 Flash 中,这样就不需要 bootLoader 和主机传输操作系统内核镜像文件,这通常是在做成产品的情况下使用。而一般在开发过程中,为了调试内核的方便,不将操作系统内核镜像文件固化在 Flash 中,这就需要主机和目标机进行文件传输;
跳转到内核的开始,在此又分为 ROM 启动和 RAM 启动。所谓 ROM 启动就是用 XIP 技术直接在 Flash 中执行操作系统镜像文件;所谓 RAM 启动就是指把内核镜像从 Flash 复制到 RAM 中,然后再将 PC 指针跳转到 RAM 中的操作系统启动地址。
目前使用的主流嵌入式平台,几乎都是用 u-boot 作为启动引导,u-boot 有哪些突出的优点呢?
① 开放源码:https://github.com/u-boot/u-boot;
② 支持多种嵌入式操作系统内核,如 Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS, android;
③ 支持多个处理器系列,如 PowerPC、ARM、x86、MIPS;
④ 较高的可靠性和稳定性;
⑤ 高度灵活的功能设置,适合 u-boot 调试、操作系统不同引导要求、产品发布等;
⑥ 丰富的设备驱动源码,如串口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等;
⑦ 较为丰富的开发调试文档与强大的网络技术支持。
# kernel
kernel 即 linux 内核。内核源代码可以免费从官网获取,这是一个通用的内核,里面包含着内核支持的所有的硬件平台及驱动的所有代码,是一个大而全的内核源代码。
在使用层面上,当嵌入式平台使用 linux 系统,那么最重要的就是 kernel 中驱动的移植;一般都不会从一个纯净的 kernel 中去进行移植操作,而是根据芯片厂商提供的 kernel 对特定的硬件平台及设备进行各种外设驱动相关的适配工作。
# Device Tree
设备树(Device Tree)是描述计算机的特定硬件设备信息的数据结构,以便于操作系统的内核可以管理和使用这些硬件,包括 CPU 或 CPU,内存,总线和其他一些外设。
老版本的 linux kernel 是没有设备树概念的,后来因为 SOC 的发展,kernel 中需要对这些新增的 SOC 进行支持,而这些代码都会编译到 kernel 中,会导致 kernel 日渐臃肿,于是后面就引入了在 PowerPC 等架构就已经采用的设备树。
1、dts (device tree source 设备树源文件)
dts 文件是一种 ASCII 文本格式的设备树描述文件,此文件适合人类阅读主要是给用户看的。一个 .dts
文件对应一个 ARM 的设备,一般放置在 arch/arm/boot/dts/
中。
2、dtsi (device tree source include 设备树头文件)
由于 .dts
中包含了很多公共部分,linux 内核为了简化,将 Soc 公共部分提炼为 .dtsi
文件,类似 c 语言中的 .h
文件。当然,和 C 语言的头文件类似,.dtsi 也可以 include 其他的 .dtsi
,譬如几乎所有的 ARM SoC 的 .dtsi
都引用了 skeleton.dtsi
。对于同一个节点的设置情况, .dts
中的配置会覆盖 .dtsi
中的配置;因此, .dtsi
一般写 Soc 共性部分,而 .dts
一般写目标单板特性部分,所以一般 .dts
包含并重写部分 .dtsi
。
3、dtb (device tree blob 设备树二进制文件).dts
通过 dtc 编译工具编译成 .dtb
文件,被编译后的设备树文件与内核一同放入到存储介质中,当内核启动时读取设备树文件,就可以动态的将板级信息写入到内核中。
# rootfs
rootfs(Root Filesystem)即根目录文件系统,是 kernel 启动后挂载的第一个文件系统。rootfs 和 kernel 是分开的,但单独的 kernel 没有 rootfs 是没法正常工作的。在系统终端执行 cd /
即可看到当前的文件系统内容了。
现在有许多制作 rootfs 的工具,如 busybox,buildroot,Yocto 等。其中 buildroot 中包含了 busybox 的功能,只需要简单的操作就可以生成一个 rootfs 了。
# 参考
完整的 linux 系統:bootloader、linux kernel(linux 內核)、rootfile(根文件系統)
嵌入式 linux 应用开发
Linux 筆記 2
What is the difference between .dts file and .dtsi file?