Skip to the content.

1. 通用发行版配置概念

Linux 发行版面临着支持各种引导机制、环境或引导加载程序(PC BIOS、EFI、U-Boot、Barebox 等)。 这让生活变得复杂。 更糟糕的是,U-Boot 等引导加载程序具有一组可配置的功能,并且每个板都选择启用一组不同的功能。 因此,发行版通常需要具备特定于主板的知识才能建立可启动系统。

本文档定义了发行版以通用方式支持主板所需的一组通用 U-Boot 功能。 任何希望允许发行版以开箱即用的方式安装和启动的主板都应该启用所有这些功能。 然后,Linux 发行版可以创建一组针对这些功能的引导支持/安装逻辑。 这将允许发行版安装在许多板上,而不需要特定于板的逻辑。

事实上,其中一些功能可以由任何引导加载程序实现,从而将发行版安装/引导逻辑与引导加载程序的任何知识分离。

该模型假设主板将从具有标准分区方案(MBR、GPT)的常规存储机制(eMMC、SD 卡、USB 磁盘、SATA 磁盘等)加载启动配置文件。 不支持此存储模型的主板不在本文档的讨论范围内,并且可能仍然需要发行版中特定于主板的安装程序/启动配置支持。

在某种程度上,该模型假设主板具有包含 U-Boot 的单独启动闪存,并且用户在运行发行版安装程序之前已以某种方式将 U-Boot 安装到该闪存中。 即使在不符合模型这一方面的主板上,发行版安装程序逻辑中特定于主板的支持范围也将是在安装过程中将特定于主板的 U-Boot 软件包安装到引导分区。 这个发行版提供的 U-Boot 仍然可以实现与任何其他主板相同的功能,因此发行版的引导配置文件生成逻辑仍然可以与主板无关。

1.1 找到可启动磁盘

典型的台式机/服务器 PC 会在所有(或用户定义的子集)连接的存储设备中搜索可引导分区,然后从那里加载引导加载程序或引导配置文件。 启用本文档中提到的功能的 U-Boot 板端口将以相同的方式搜索启动配置文件。

因此,发行版不需要操作任何类型的引导加载程序特定的配置数据来指示系统应从哪个存储设备引导。

发行版只需在 ext2/3/4 或 FAT 分区中安装启动配置文件(请参阅下一节),将分区标记为可启动(通过 MBR 可启动标志或 GPT Legacy_bios_bootable 属性),以及 U-Boot(或任何其他 bootloader)将找到这些启动文件并执行它们。 这在概念上与在台式 PC 上创建 grub2 配置文件相同。

请注意,如果没有任何明确标记为可引导的分区,U-Boot 将回退到在磁盘的第一个有效分区中搜索引导配置文件。 建议其他引导加载程序也这样做,因为我相信分区表可引导标志在 x86 PC 领域之外并不常用。

U-Boot 还可以从 TFTP 服务器搜索启动配置文件。

1.2 启动配置文件

启动配置文件的标准格式是 extlinux.conf,由 U-Boot 的“syslinux”(磁盘)或“pxe boot”(网络)处理。 这大致如引导加载程序规范中所指定:

…除了引导加载程序规范文档之外:

另请参阅“pxe 文件格式”下的 doc/README.pxe。

Fedora 安装程序生成的 extlinux.conf 示例如下:

# extlinux.conf generated by anaconda

ui menu.c32

menu autoboot Welcome to Fedora. Automatic boot in # second{,s}. Press a key for options.
menu title Fedora Boot Options.
menu hidden

timeout 50
#totaltimeout 9000

default Fedora (3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae) 22 (Rawhide)

label Fedora (3.17.0-0.rc4.git2.1.fc22.armv7hl) 22 (Rawhide)
    kernel /boot/vmlinuz-3.17.0-0.rc4.git2.1.fc22.armv7hl
    append ro root=UUID=8eac677f-8ea8-4270-8479-d5ddbb797450 console=ttyS0,115200n8 LANG=en_US.UTF-8 drm.debug=0xf
    fdtdir /boot/dtb-3.17.0-0.rc4.git2.1.fc22.armv7hl
    initrd /boot/initramfs-3.17.0-0.rc4.git2.1.fc22.armv7hl.img

label Fedora (3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae) 22 (Rawhide)
    kernel /boot/vmlinuz-3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae
    append ro root=UUID=8eac677f-8ea8-4270-8479-d5ddbb797450 console=ttyS0,115200n8 LANG=en_US.UTF-8 drm.debug=0xf
    fdtdir /boot/dtb-3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae
    initrd /boot/initramfs-3.17.0-0.rc4.git2.1.fc22.armv7hl+lpae.img

label Fedora-0-rescue-8f6ba7b039524e0eb957d2c9203f04bc (0-rescue-8f6ba7b039524e0eb957d2c9203f04bc)
    kernel /boot/vmlinuz-0-rescue-8f6ba7b039524e0eb957d2c9203f04bc
    initrd /boot/initramfs-0-rescue-8f6ba7b039524e0eb957d2c9203f04bc.img
    append ro root=UUID=8eac677f-8ea8-4270-8479-d5ddbb797450 console=ttyS0,115200n8
    fdtdir /boot/dtb-3.16.0-0.rc6.git1.1.fc22.armv7hl+lpae

手工制作的 extlinux.conf 的一个示例:

menu title Select kernel
timeout 100

label Arch with uart devicetree overlay
    kernel /arch/Image.gz
    initrd /arch/initramfs-linux.img
    fdt /dtbs/arch/board.dtb
    fdtoverlays /dtbs/arch/overlay/uart0-gpio0-1.dtbo
    append console=ttyS0,115200 console=tty1 rw root=UUID=fc0d0284-ca84-4194-bf8a-4b9da8d66908

label Arch with uart devicetree overlay but with Boot Loader Specification keys
    kernel /arch/Image.gz
    initrd /arch/initramfs-linux.img
    devicetree /dtbs/arch/board.dtb
    devicetree-overlay /dtbs/arch/overlay/uart0-gpio0-1.dtbo
    append console=ttyS0,115200 console=tty1 rw root=UUID=fc0d0284-ca84-4194-bf8a-4b9da8d66908

另一个手工制作的网络启动配置文件是:

TIMEOUT 100

MENU TITLE TFTP boot options

LABEL jetson-tk1-emmc
        MENU LABEL ../zImage root on Jetson TK1 eMMC
        LINUX ../zImage
        FDTDIR ../
        APPEND console=ttyS0,115200n8 console=tty1 loglevel=8 rootwait rw earlyprintk root=PARTUUID=80a5a8e9-c744-491a-93c1-4f4194fd690b

LABEL venice2-emmc
        MENU LABEL ../zImage root on Venice2 eMMC
        LINUX ../zImage
        FDTDIR ../
        APPEND console=ttyS0,115200n8 console=tty1 loglevel=8 rootwait rw earlyprintk root=PARTUUID=5f71e06f-be08-48ed-b1ef-ee4800cc860f

LABEL sdcard
        MENU LABEL ../zImage, root on 2GB sdcard
        LINUX ../zImage
        FDTDIR ../
        APPEND console=ttyS0,115200n8 console=tty1 loglevel=8 rootwait rw earlyprintk root=PARTUUID=b2f82cda-2535-4779-b467-094a210fbae7

LABEL fedora-installer-fk
        MENU LABEL Fedora installer w/ Fedora kernel
        LINUX fedora-installer/vmlinuz
        INITRD fedora-installer/initrd.img.orig
        FDTDIR fedora-installer/dtb
        APPEND loglevel=8 ip=dhcp inst.repo=http://10.0.0.2/mirrors/fedora/linux/development/rawhide/armhfp/os/ rd.shell cma=64M

2. U-Boot 实现

2.1 启用发行版选项

在主板的 defconfig 中,通过添加一行“CONFIG_DISTRO_DEFAULTS=y”来启用 DISTRO_DEFAULTS 选项。 如果您想从 Kconfig 本身启用此功能,例如 然后,所有使用特定 SoC 的主板都将“imply DISTRO_DEFAULTS”添加到您的 SoC CONFIG 选项中。

要被更新:

在您的板配置文件中,包含以下内容:

#ifndef CONFIG_SPL_BUILD
#include <config_distro_bootcmd.h>
#endif

第一个标头主要启用一组核心 U-Boot 功能,例如支持 MBR 和 GPT 分区、ext* 和 FAT 文件系统、引导原始 zImage 和 initrd(而不是 FIT 或 uImage 包装的文件)等。 此处还启用了网络启动支持,鉴于发行版目前通常不为非 PC 目标分发可启动安装介质,这对于启动发行版安装程序非常有用。

最后,仅在使用 U-Boot 特定的 boot.scr 脚本时才启用一些主要相关的选项。 这使得发行版能够生成 U-Boot 特定的 boot.scr 脚本而不是 extlinux.conf 作为引导配置文件。 虽然这样做是完全支持的,并且 CONFIG_DISTRO_DEFAULTS 向 boot.scr 公开了足够的参数化以允许与主板无关的 boot.scr 内容,但本文档建议发行版生成 extlinux.conf 而不是 boot.scr。 extlinux.conf 旨在跨多个引导加载程序工作,而 boot.scr 仅适用于 U-Boot。 TODO:记录 U-Boot 和 boot.scr 之间的合同,回复:通用 boot.scr 可能依赖哪些环境变量。

第二个标头设置默认环境,以便 $bootcmd 的定义方式是在附加磁盘中搜索引导配置文件,如果找到则执行它们。

2.2 所需的环境变量

U-Boot“syslinux”和“pxe boot”命令需要设置许多环境变量。 这些变量的默认值通常被硬编码到主板 U-Boot 配置文件中的 CFG_EXTRA_ENV_SETTINGS 中,以便用户无需配置它们。

fdt_addr:

对于在硬件(例如 ROM)中提供 DTB 并希望将该 DTB 传递到 Linux,而不是从引导文件系统加载 DTB 的任何系统都是强制的。 禁止用于任何其他系统。

如果指定了用于引导系统的 DTB,则必须在给定地址可用。

fdt_addr_r:

强制的。 在处理 extlinux.conf 中的 fdtdir/devicetreedir 或 fdt/devicetree 选项时,DTB 将在 RAM 中加载或复制到的位置。

即使提供了 fdt_addr,这也是强制性的,因为 extlinux.conf 必须始终能够提供覆盖硬件提供的任何副本的 DTB。

FDT/DTB 的大小为 1MB 似乎比较合理。

fdtoverlay_addr_r:

强制的。 RAM 中的位置将临时存储 DTB 覆盖,然后按加载顺序应用到存储在 fdt_addr_r 环境变量中指示的地址处的 fdt blob。

fdtfile:

强制的。 特定板的 DTB 文件名称,例如 espressobin v5 板,值为“marvell/armada-3720-espressobin.dtb”,而在clearfog pro 上,值为“armada-388-clearfog-pro.dtb” 如果板提供基于固件的 DTB,则该值可用于用不同的 DTB 覆盖 DTB。 如果 fdtfile 与覆盖大多数 32 位用例的格式 ${soc}-${board}.dtb 匹配,则会自动为您设置。 AArch64 通常不匹配,因为 Linux 内核将 dtb 文件放在 SoC 供应商目录下。

ramdisk_addr_r:

强制的。 在处理 extlinux.conf 中的 initrd 选项时,初始 ramdisk 将被加载到 RAM 中的位置。

建议将此位置设置为 fdt_addr_r、kernel_addr_r 和 ramdisk_addr_r 中 RAM 的最高位置,以便 RAM 磁盘可以改变大小并使用任何可用的 RAM。

kernel_addr_r:

强制的。 当处理 extlinux.conf 中的内核选项时,内核将被加载到 RAM 中的位置。

内核应位于 RAM 的前 128M 内,以便内核 CONFIG_AUTO_ZRELADDR 选项起作用,该选项可能在任何发行版内核上启用。 由于内核在 RAM 启动后会将自身解压到 0x8000,因此 kernel_addr_r 不应与该区域重叠,否则内核在解压之前必须先将自身复制到其他位置。

内核大小为 16MB 可能就足够了。

kernel_comp_addr_r:

选修的。 仅当用户想要使用 booti 命令从压缩映像(.gz、.bz2、.lzma、.lzo)引导 Linux 时才需要这样做。 它表示 RAM 中压缩后的图像将被临时解压的位置。 解压完成后,解压后的数据将被移至kernel_addr_r用于启动。

kernel_comp_size:

选修的。 仅当用户想要使用 booti 命令从压缩映像引导 Linux 时才需要这样做。 它代表压缩文件的大小。 大小必须至少为加载图像的大小才能成功解压。

pxefile_addr_r:

强制的。 RAM 中的位置,在处理之前将加载 extlinux.conf。

extlinux.conf 的大小为 1MB 就足够了。

scriptaddr:

强制,如果引导脚本是 boot.scr 而不是 extlinux.conf。 RAM 中 boot.scr 在执行之前将被加载到的位置。

extlinux.conf 的大小为 1MB 就足够了。

有关 ARM 系统内存位置的建议,您必须遵循 Linux 内核树中的 Documentation/arm/Booting 中指定的准则。

有关设置这些值的注释示例,请参阅 include/configs/tegra124-common.h 中 MEM_LAYOUT_ENV_SETTINGS 的定义。

2.3 引导目标配置

config_distro_bootcmd.h 文件定义 $bootcmd 和许多帮助程序命令变量,这些变量自动搜索附加磁盘以查找引导配置文件并执行它们。 主板必须提供配置,以便它支持正确的可能引导设备类型集。 要提供此配置,只需在包含 之前定义宏 BOOT_TARGET_DEVICES。 例如:

#ifndef CONFIG_SPL_BUILD
#define BOOT_TARGET_DEVICES(func) \
        func(MMC, mmc, 1) \
        func(MMC, mmc, 0) \
        func(USB, usb, 0) \
        func(PXE, pxe, na) \
        func(DHCP, dhcp, na)
#include <config_distro_bootcmd.h>
#endif

宏中的每个条目定义一个启动设备(例如特定的 eMMC 设备或 SD 卡)或启动设备类型(例如 USB 磁盘)。 func 宏的参数(由标头的内部实现传入)为:

3. 用户配置

用户安装 U-Boot 后,预计环境将重置为默认值,以启用 $bootcmd 和类似的功能,如 设置的。 此后,可以更改各种环境变量以影响引导过程:

boot_targets:

搜索到的启动位置列表。

例如: mmc0, mmc1, usb, pxe

可以删除或重新排序此列表中的条目以影响启动顺序。

boot_prefixes:

对于基于磁盘的引导,是在分区内搜索引导配置文件(extlinux.conf、boot.scr)的目录列表。

例如: / /boot/

可以删除或重新排序此列表中的条目以影响搜索的目录集。

boot_scripts:

$bootcmd 搜索的 U-Boot 样式 boot.scr 文件的名称。

例如: boot.scr.uimg boot.scr

(通常我们期望使用 extlinux.conf,但为了向后兼容而维护 boot.scr 的执行。)

可以删除或重新排序此列表中的条目以影响支持的文件名集。

scan_dev_for_extlinux:

如果您想在所有磁盘上禁用 extlinux.conf,请将值设置为无害的值,例如 setenv scan_dev_for_extlinux true。

scan_dev_for_scripts:

如果要在所有磁盘上禁用 boot.scr,请将值设置为无害的值,例如 setenv scan_dev_for_scripts true。

boot_net_usb_start:

如果您想阻止执行网络操作的发行版引导命令进行 USB 枚举,请将该值设置为无害的值,例如 setenv boot_net_usb_start true。 如果您知道您的以太网设备未连接到 USB,并且您希望通过避免不必要的操作来提高启动速度,这将非常有用。

boot_net_pci_enum:

如果您想阻止执行网络操作的发行版引导命令进行 PCI 枚举,请将该值设置为无害的值,例如 setenv boot_net_pci_enum true。 如果您知道您的以太网设备未连接到 PCI,并且您希望通过避免不必要的操作来提高启动速度,这将非常有用。

4. 在 u-boot 提示符下从特定设备交互式启动

为了在 u-boot 命令提示符处从用户选择的设备进行交互式引导,环境为 boot_targets 中定义的每个目标提供了预定义的 bootcmd_ 变量,这些变量可以由用户运行。

如果目标是存储设备,则目标的格式始终为<设备类型><设备编号>,例如 毫米c0。 对于存储设备来说,指定设备编号是强制性的,即使实际上只实现了对存储设备的单个实例的支持。

对于网络目标(dhcp、pxe),仅指定设备类型; 他们没有设备编号。

例如:

可能的目标清单包括:

除上述定义之外的其他引导变量仅供引导环境内部使用,不保证在未来的 u-boot 版本中存在或以相同的方式工作。 特别是 _boot 变量(例如 mmc_boot、usb_boot)是严格的内部实现细节,不得用作公共接口。