Linux 内核在系统引导期间所做的最后一件事是挂载根文件系统。Linux 内核没有规定文件系统结构,但用户空间应用程序希望在目录结构中找到具有特定名称的文件。因此,遵循 Linux 系统中出现的事实标准很有用。
构建根文件系统的“官方”规则包含在文件系统层次标准 (FHS) 中。FHS 定义了 Unix 操作系统中的目录结构和内容(图 1)。所有文件和目录都出现在根目录“/”下,即使它们存储在不同的物理或虚拟设备上。但是,根据某些子系统(例如 X Windows),这些目录中的一些可能存在于 Unix 系统上。为文件系统开发层次结构的过程早在 1993 年就开始于重组 Linux 系统的想法。当前的 FHS 标准(以前称为 FSSTND)由非营利组织 Free Standards Group 管理,该组织由惠普、红帽、IBM 和戴尔等主要软件和硬件供应商组成。
这些目录中的大多数都存在于所有 Unix 操作系统上,并且通常以几乎相同的方式使用。
根文件系统的每个顶级目录都有特定的用途。但是,其中许多仅与多用户系统相关,其中管理员负责不同用户使用的许多服务器或工作站。在嵌入式 Linux 系统中,通常没有用户和管理员,构建根文件系统的规则可以自由解释。这并不意味着可以违反所有规则,但确实意味着违反其中一些规则对系统的正常运行几乎没有影响。有趣的是,商业发行版,甚至是传统的工作站和服务器发行版,有时会偏离根文件系统的实际规则。
引导加载程序负责在内存中加载和初始化操作系统内核及其支持基础设施。引导加载程序执行的典型任务包括选择内核(Linux 桌面系统可能会提供一个内核列表以供您在引导期间按下一个键)并将初始文件系统加载到 RAM(initrd、initramfs 或类似的东西)。RAM 上的文件系统包含一个最小的环境来挂载根文件系统并启动正常的引导过程。大多数台式机和服务器系统都有扩展的系统固件(BIOS、UEFI、OpenFirmware 等),它提供了硬件设备配置和中断路由详细信息等信息。然而,嵌入式 Linux 通常没有这些扩展。它通过引导加载程序完成工作,
因此,嵌入式 Linux 有一些独特的引导加载程序要求。固件不仅必须将内核映像加载到系统内存中;它还必须对系统内存控制器进行编程、初始化处理器缓存、激活各种硬件设备、直接实现对网络引导基础设施的支持,以及执行许多其他活动。
根文件系统
Linux 内核与所谓的根文件系统协同工作。这是可以挂载根目录的文件系统,包含使系统进入可以挂载其他文件系统的状态所需的文件,并且可以启动用户空间守护程序和应用程序。大多数桌面和服务器发行版使用两种类型的根文件系统:初始根文件系统和实际根文件系统。前者用于挂载和运行后者。根文件系统的目录结构可以非常小,也可以包含通常的目录集,包括 /dev、/bin、/etc 和 /sbin。内核启动过程以初始化代码 (init /main.c) 结束,其主要目的是创建和填充具有多个目录和文件的初始根文件系统。然后尝试在用户模式下启动 ID 为 1 的第一个进程,以执行在此初始文件系统上找到的文件。内核可以通过三种方式找到 init 进程将执行的文件。第一种方法是使用在引导时通过 init = kernel 参数指定的文件。如果未设置此参数,内核会尝试一系列位置来查找名为“init”的文件。其中包括 /sbin /init、/etc /init 和 /bin /init。如果所有这些都失败了,内核会尝试执行它在 /bin /sh 中找到的任何 shell。如果后者没有找到,内核会打印一个错误,说 init 找不到。第一种方法是使用在引导时通过 init = kernel 参数指定的文件。如果未设置此参数,内核会尝试一系列位置来查找名为“init”的文件。其中包括 /sbin /init、/etc /init 和 /bin /init。如果所有这些都失败了,内核会尝试执行它在 /bin /sh 中找到的任何 shell。如果后者没有找到,内核会打印一个错误,说 init 找不到。第一种方法是使用在引导时通过 init = kernel 参数指定的文件。如果未设置此参数,内核会尝试一系列位置来查找名为“init”的文件。其中包括 /sbin /init、/etc /init 和 /bin /init。如果所有这些都失败了,内核会尝试执行它在 /bin /sh 中找到的任何 shell。如果后者没有找到,内核会打印一个错误,说 init 找不到。
一旦 init 进程启动,通常会运行其他用户空间程序。在桌面或服务器系统上,这被称为 sysvinit 进程,它包括一系列通常位于 /etc/rc.d 下的脚本。名称“sysvinit”来自 Unix System V 中使用的机制,它定义了用于目录和文件的命名方案。在嵌入式系统上,init 进程可以是一组定制设计的脚本,甚至是单个应用程序。一些桌面发行版将 sysvinit 替换为专为更快启动而设计的替代品。
目录:关键概念
首先,可以省略所有提供可扩展多用户环境的目录,例如 /home、/mnt、/opt 和 /root。您可以进一步删除 /tmp 和 /var,但这些遗漏会影响某些程序的功能。
根据引导加载程序及其配置,可能不需要 /boot 目录。这是因为引导加载程序可以在内核启动之前从根文件系统检索内核映像。
其余目录 — /bin、/dev、/etc、/lib、/proc、/sbin、/sys 和 /usr — 对于系统的正常运行至关重要。
至少,您可能决定省略 /proc 和 /sys 并在没有相应虚拟文件系统帮助的情况下配置内核。但是,ps、mount、ifconfig 和 sysfs 等基本命令需要访问 proc 文件系统,这些命令也被越来越多的程序使用。所以如果想不用proc和sysfs,就需要准备好用自定义程序替换脚本,直接访问内核调用接口。
/usr 和 /var 两个主目录具有默认层次结构,与根目录的层次结构非常相似。
因此,系统所需的基本根文件系统目录如下:$ Mkdir bin dev etc lib proc sbin sys tmp usr var boot
/tmp ( $ chmod 1777 tmp)的适当权限确保创建的文件只能由创建它们的用户删除。尽管大多数嵌入式 Linux 系统都是单用户的,但在某些情况下嵌入式应用程序不需要以 root 权限运行,例如 OpenSSH 包。
对于嵌入式 Linux 系统,创建以下目录 - $ mkdir usr /bin usr /lib usr /sbin - 足以正常系统操作。
当然,如果您需要额外的功能,例如 Web 服务器或打印驱动程序,则需要添加应用程序所需的额外目录。
使用不同的根文件系统结构运行 Linux
如前所述,构建根文件系统的规则可以在 FHS 中找到。尽管大多数 Linux 应用程序和发行版都依赖于这些规则,但它们并不是由 Linux 内核强制执行的。事实上,内核源代码很少对根文件系统的结构做出假设。可以构建具有不同根文件系统结构的嵌入式 Linux 系统。因此,有必要更改大多数软件包的默认设置以使其符合新结构。
构建 FHS 根文件系统的规则得到所有在 Linux 系统上工作的开源和自由软件开发人员的认可和共享。
初始根文件系统
初始根文件系统称为初始 RAM 磁盘,驻留在内核在 RAM 中创建的磁盘映像中。在台式机或服务器系统上,初始 RAM 磁盘用于加载驱动程序和初始化环境,以便可以安装外部存储系统(磁盘或网络附加存储)。
在嵌入式系统上,初始 RAM 磁盘可能是唯一安装的文件系统,因为它包含用户模式下所有必要的应用程序。或者,可以将初始 RAM 磁盘安装到闪存驱动器或其他本地存储介质。
在内核 2.4 中,初始 RAM 磁盘被称为 initrd 映像。initrd 文件只能在引导时从外部源加载(MIPS 内核除外,它允许将映像集成到内核中)。在引导过程结束时,会卸载 initrd 映像以清理内存使用情况,然后再切换到更完整的根文件系统。
在 Kernel 2.6 中,创建和使用初始 RAM 磁盘的过程有所简化。首先,这些文件被简单地收集在一个名为 initramfs 而不是 initrd 的 CPIO 压缩文件中。initramfs 文件始终内置在内核中(适用于所有硬件平台);否则,内核构建过程会自动创建一个默认的 CPIO 存档。
其次,initramfs 在启动时不需要外部文件系统。Ramfs 支持内置于内核中,无法关闭。
Initramfs 是初始文件系统的 CPIO 存储库,在 Linux 引导过程中加载到内存中。它必须包含挂载实际根文件系统所需的所有设备驱动程序和工具。
为什么要使用 initramfs?
理想的配置是让内核启动处于足以使系统进入对用户有用的状态的最小状态。这种最小状态将允许内核尽可能小,并带有一些编译选项。
在任何系统上,尤其是在资源有限的系统上,您都希望内核本身保持较小,并且只动态加载引导最终系统所需的驱动程序模块。大多数桌面系统使用 initramfs 来确定具有完整根文件系统的硬盘驱动器或其他存储介质的类型。在这种情况下,initramfs 包含启动脚本和主要驱动模块。由于桌面硬件种类繁多,initramfs 可以足够大且足够复杂,可以选择要安装的硬件类型。
在小型系统上,情况可能会大不相同。可能没有可用于保存另一个根文件系统的存储空间。在这种情况下,initramfs 成为真正的根文件系统。
或者,小型系统可以使用具有只读访问权限的专用闪存驱动器,以避免意外破坏系统。在这种情况下,initramfs 将包含启动脚本,这些启动脚本会挂载闪存设备以模拟可写分区,从而使系统能够正常运行。
BusyBox 嵌入式系统
BusyBox(图 2)是嵌入式系统的主力。它是单个二进制文件中常用的 Unix 实用程序的集合。命令行实用程序的选项通常少于其独立对应项,但它们往往具有相似的功能。BusyBox 的主要目标是为资源有限的系统提供全套功能。
这是一个精心设计的包,非常易于使用。这个图形配置实用程序在风格上与内核配置程序相似,它允许您通过指示要在二进制文件中包含哪些小程序来选择必要的实用程序。选择完全取决于您尝试创建的系统。
BusyBox 的源代码树组织良好,实用程序根据其用途分类并存储在单独的子目录中。例如,网络实用程序和守护程序(如 httpd、ifconfig 等)位于 ./networking 目录中;标准模块(包括 insmod、rmmod 和 lsmod)的实用程序位于 ./modutils 目录中;并且编辑器(例如 vi、awk 和 sed)位于 ./editors 目录中。用于配置、构建和安装的 makefile 和各种文档位于树的根目录中。
Linux 引导加载程序
引导加载程序(图 3)是一个由处理器执行的小型应用程序,其任务是将图像加载到内存中并随后引导系统。在 Linux 系统上,引导加载程序通常会加载内核。因为它们需要了解与底层硬件的交互,所以它们通常特定于正确选择的操作系统上的计算机体系结构。
引导加载程序在嵌入式系统的开发中起着关键作用,因为它取决于它所基于的处理器的功能。例如,在大多数 Intel x86 或 x86_64 系统上,引导加载程序可以依赖基本输入/输出 (BIOS) 来执行设备初始化,因此可以专注于更高级别的功能,例如选择要加载的特定内核。在大多数非 x86 硬件上,引导加载程序会自行初始化硬件;加载 ROM、闪存或存储设备的内核或相关独立应用程序映像;然后在开始在内存中执行之前切换到必要的内核选项。
在嵌入式 Linux 系统上,引导加载程序一步加载 Linux 内核。它可以是多级的,即由两个或多个引导加载程序组成,其中第一个加载第二个。
x86 系统的引导加载程序
Linux 桌面和服务器平台通常使用 x86 或 x86_64 处理器,因此多个引导加载程序可用于这些架构也就不足为奇了。Linux 系统最初使用 LOADLIN 引导加载程序和 LILO(Linux 加载程序)。今天,x86 和 x86_64 平台的 Linux 发行版通常支持各种引导加载程序,具体取决于引导过程:
- Gran Unified Bootloader (GRUB) — Linux 桌面系统和服务器上最常用的引导加载程序;多级级联引导加载程序,最常用于促进与引导过程的交互。最初的 GRUB 引导加载程序已被 GNU GRUB(也称为 GRUB 2)取代。
- Syslinux — 一个多级引导加载程序系列,支持从 DOS/Windows 或 Linux 文件系统 (SYSLINUX)、网络 (PXELINUX) 以及 DVD 和 CD-ROM 外围设备 (isolinux) 引导。Syslinux 通常用于允许从网络或从 USB、CD-ROM 和 DVD 设备启动。
GRUB 传统上被视为出色的引导加载程序,因为它提供了极其灵活的引导环境,在开发过程中非常有用,并且可以从 Syslinux 不支持的 Linux 文件系统类型引导。Syslinux 要小得多,但最好在不需要与引导过程交互的引导环境中使用。
英特尔提供了英特尔处理器引导加载程序开发套件 BLDK,它可以轻松开发用于基本嵌入式系统初始化的自定义引导加载程序。Timesys Desktop 不支持基于引导加载程序的 BLDK,以确保符合标准 Linux 引导过程并简化使用 Desktop 跨多个硬件平台进行开发的 Linux 平台。
Das U-Boot,独立于平台的引导加载程序
许多引导加载程序(图 4)特定于特定架构。引导加载程序支持各种架构和处理器的能力对于大型开发组织来说可能是一项重要功能。单个组织开发涵盖多种架构的多个处理器的情况并不少见。在多个平台上投资单个引导加载程序最终会降低开发成本。
Das U-Boot(图 5)是高度可配置的多级,设计用于嵌入式 Linux。事实上,它是非 x86 系统上首选的引导加载程序。U-Boot 支持 Arm、Coldfire、MIPS、PPC、XScale 和类似的嵌入式系统的引导,也可以在 x86 系统上使用。灵活的 U-Boot 配置可轻松针对卡和处理器的特定需求进行定制,同时保持引导加载程序尽可能小。
U-Boot 的主要目标是提供有关 Linux 文件系统位置的信息,并从 NAND、SD/MMC 卡、UART 或以太网(通过 TFTP)恢复 Linux 内核;此外,它可以在 NAND (jffs2)、SRAM(RAM 磁盘)、SD/MMC(ext3 分区)或通过 IP 挂载 (NFS) 上指定根文件系统。
特定于平台的引导加载程序
不同的嵌入式系统硬件为存储和运行引导加载程序提供了不同数量的系统资源。Timesys Desktop Factory 包括对以下非 x86/x86_64 平台引导加载程序的支持:
- APEX — 一些基于 Arm 的嵌入式系统中使用的引导加载程序。它最初是为夏普 LH 系列处理器编写的,但后来被开发用于一系列 Arm 镜头,例如三星 S3C24xx 系列。
- at91bootstrap——Arm AT91 系统上常用的引导加载程序,通常作为 U-Boot 的第一阶段引导加载程序,可以在加载 Linux 内核之前执行更复杂系统的初始化任务。它是 Atmel AT91 SoC 的二级引导加载程序,提供一组算法来处理硬件初始化,例如时钟速度配置、PIO 设置和 DDR2 DRAM 初始化。
- at91bootstrap-3 — at91bootstrap 引导加载程序的扩展版本。
- blob — 与一些 StrongARM 处理器一起使用的开源引导加载程序。
- x-loader — 从 U-Boot 基本代码派生的小型单阶段引导加载程序,通常用于具有少量静态内存的平台,例如 OMAP 平台,并且通常用作第一阶段引导加载程序。
- yaboot — 适用于较旧的开放固件机器的 PowerPC 引导加载程序,在新的嵌入式 Linux 项目中很少遇到。通过编辑 /etc/ 文件夹中包含的 yaboot.conf 文件来配置 Yaboot,或者通过挂载包含程序的分区并修改相应的配置文件来配置 Yaboot。
红靴
RedBoot(Debug Red Hat Embedded and Firmware Bootstrap 的缩写)是一个开源应用程序,它使用实时硬件抽象层 eCos 操作系统为嵌入式系统提供引导固件。例如,RedBoot 用于空中客车 A380 和达美波音 767 的娱乐系统。
RedBoot 允许通过串行或以太网下载和执行嵌入式应用程序,包括与 GDB 协作提供调试支持的嵌入式 Linux 和 Ecos 应用程序。它还提供交互式命令行界面,允许管理闪存映像和配置可通过串行或以太网访问的参数。
引导加载程序和嵌入式微控制器
引导加载程序是系统还原后运行的第一个代码。其目的是使系统进入可以执行其主要功能的状态。这需要通过选择正确的映像来初始化硬件。由于其作用,引导加载程序通常放置在闪存的一部分中,以防止意外删除或数据损坏。
引导加载程序是一个程序,它可以正确加载到微控制器中,允许您直接通过串行或 USB 端口对其进行编程,而不必使用编程器。这使您可以显着加快固件开发过程和上市时间。
引导加载程序的操作可以根据来自用户或来自外围设备(例如,主机系统)的启动信号进行同步。根据嵌入式系统,bootloader 信号可以首先验证系统,确定当前设备应用程序是否有效,与主机通信以加载新应用程序,并重写闪存应用程序。
大多数现代微控制器能够在微秒内重新编程其闪存。引导加载程序的任务是验证可引导加载映像并使用正确设置的中断检查代码以中断进程。通常,引导加载程序执行软复位以允许应用程序恢复活动,并且应该能够检测、报告和处理引导加载操作期间发生的错误,例如电源故障、通信丢失和写入错误(图 6) .
审核编辑:汤梓红
评论
查看更多