一个嵌入式Linux系统由许多不同的部分组成,这些部分共同致力于使事物高效地工作。理想情况下,这与普通的GNU/Linux系统没有太大差别,但让我们详细看看通用嵌入式系统的构建块。在以下说明中,我假设架构为ARM。下面所写的可能会因实现的不同而略有不同,但通常是商业嵌入式系统的通用轨迹。
GNU/Linux嵌入式系统的构建块如下:
硬件
SoC - 所有处理都发生在SoC中,它是整个系统的主要处理单元,也是唯一具有“智能”的地方。它负责使用其他硬件并运行软件。它由各种异构子块组成:
1.核心+Caches+MMU - “真正的”处理器,例如ARM Cortex-A9。这是您选择SoC时最关注的主要组成部分。还可以辅助例如一个像NEON这样的SIMD协处理器。
2.内部RAM - 通常非常小。在引导序列的第一阶段中使用。
3.各种“外设”-通过某些互连纺织/总线连接到核心。这些可以从简单的ADC到3D图形加速器。此类IP核的示例包括:USB、PCI-E、SGX等。
4.低功率/实时协处理器-某些系统提供一个或多个协处理器,用于帮助主核心处理实时任务(例如工业通信总线)或处理低功耗状态。它们的体系结构可能(也可能不)与核心的一致。
外部RAM - SoC用于在系统引导及其自身期间存储临时数据。这通常是您的嵌入式系统在常规操作期间使用的内存。
非易失性存储器- 可选项。在您的情况下,这是您提到的SD卡。在其他情况下,可能是NAND、NOR或SPI Dataflash存储器(或它们的任何组合)。当存在时,它通常是SoC将读取的数据的常规来源,并且通常存储系统运行所需的所有SW组件。在某些应用程序中可能不是必要/有用。
外部外设- 与上述内容无直接关系的任何内容。可以是MAC ID EEPROM、一些继电器、网络摄像头或您可能想象的任何东西。
软件
首先,我们介绍所谓的引导链(bootchain),它是在您启动SoC并-某种方式地-告诉它开始运行时发生的情况。在下面的列表中,引导链是从点1到点4的后续调用。
除了特定/奇异的实现,它基本上总是相同的:
- 引导ROM代码 - 一个小型(通常是掩模 - 即工厂印制)存储在SoC中的内存。当SoC上电时,它将执行其中的代码。
这个代码会根据外部配置引脚 - 一般上是"引导策略"或"引导顺序" - 决定在哪里(以及什么顺序)查找要执行的其他代码。
适合的媒介是不同的:USB存储设备、USB主机、SD卡、NAND、NOR、SPI数据闪存、以太网、UART等。如果上述任何一个都不包含有效内容,引导ROM通常会对SoC进行软复位,如此往复。
当然,介质中的代码不是直接执行:而是被复制到内部RAM中,然后再执行。
[以下两个内容包含在我们将称之为引导加载程序介质中]
第一阶段引导程序 - 它刚被Boot ROM复制到SoC的内部RAM中。必须足够小以适应该内存(通常远低于100kB)。它是必需的,因为Boot ROM不够大,也不知道SoC连接的外部RAM的种类。
其主要重要功能是初始化外部RAM和SoC的外部内存接口,以及可能感兴趣的其他外围设备(例如,禁用看门狗计时器)。完成后,将下一阶段复制到外部RAM并执行它。根据上下文,可以称之为MLO、SPL或其他名称。
第二阶段引导程序 - “主”引导程序。比第一阶段大(可能是其十倍),完成相关外围设备的初始化(例如以太网、附加存储介质、液晶显示器)。
允许更复杂的下一步操作逻辑,并根据复杂程度提供高级功能(文件系统/卷处理、数据复制-移动-解释、液晶输出、交互式控制台、故障安全策略等)。
大多数情况下,从某些介质将Linux内核(及相关模块)加载到内存中,并向其传递相关信息(例如,如果不是嵌入式,对于较新的内核,DTB物理地址被放入r2寄存器中 - 然后内核读取该寄存器并检索DTB)
Linux内核 - 操作系统的核心。根据硬件平台可能是或可能不是一个主线(“官方”)版本。
通常由内置或可加载的(来自外部源-免费或非免费)模块完成。根据硬编码的配置和DT启用所有完整系统所需的硬件 - 启用MMU,协调整个系统并独占地访问硬件。根据引导参数(cmdline-通常由前一阶段传递)和/或编译选项,内核会尝试挂载根文件系统。从rootfs中,它将尝试加载一个初始化程序(即,/sbin/init-其中/是刚刚挂载的rootfs)。
初始化和rootfs - 初始化是要运行的第一个非内核任务,并具有PID 1。它初始化您使用系统所需的所有内容。在生产嵌入式系统中,它还启动主应用程序。在这些系统中,它可以是BusyBox或定制的应用程序。
更多关于rootfs和发行版
Rootfs包含所有不是内核的GNU/Linux系统(除/lib/modules和其他部分之外)。
它包含管理外围设备(如以太网、WiFi或外部UMTS调制解调器)的所有应用程序。
包含系统的交互部分,包括用户界面和GNU/Linux系统启动时看到的所有其他内容 - 无论是嵌入式还是非嵌入式。"distro"只是一组特定的用户空间(非内核)程序和库(通常),经过验证可以很好地彼此协作,由特定的人员组合在一起。桌面发行版通常还配有自定义内核和引导加载程序。例如 Fedora、Ubuntu、Debian 等。
就术语的一般意义而言,你没有任何限制来创建自己的distro,这正是每次生产自定义嵌入式系统时会发生的事情:通过像Yocto或Buildroot这样的工具(或手动),实际上可以决定适用于系统目的的软件的特定集合(因此是发行版)。
总之,回答你的问题,你正在寻找的缺失部分是init和挂载rootfs的过程:内核通过其驱动程序和传递/内置参数将给定的卷/分区(你提到的ext4数据分区)挂载到“ /”挂载点。在这个卷/分区中,有一个/sbin/init可执行文件,内核执行它。这是我们GNU/Linux用户空间系统的"Big Bang":一切可见的东西都从这里开始。根据配置脚本(通常位于/etc/init.d下),你提到的"应用程序"要么由init自动运行,要么由用户通过终端/ssh/其他手段启动,而这些方式都是init让你可以使用的。