This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[FAQ] [参考译文] [常见问题解答] Linux:如何从 initramfs (.cio Archive、RAM 磁盘)引导 Sitara AM3x/AM4x/AM6x 器件

Guru**** 657500 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1176944/faq-linux-how-to-boot-sitara-am3x-am4x-am6x-devices-from-initramfs-cpio-archive-ram-disk

器件型号: AM335x、AM437x、AM62x、AM62Ax、AM64x、 AM65x

概述

TI SDK Yocto 构建环境、适用于所有 Sitara MPU、例如 AM335x、AM437x、AM62x、AM62Ax、AM64x、 AM65x 可用于 生成"微型"映像(通过  bitbake tisdk-Tina-image)、这些映像可直接用于从 RAM 磁盘引导 Linux、从而为实验和自定义开发提供良好的起点、 特别是作为这些编译的一部分而生成的.cpio 存档:

  • tisdk-Tina-image-am*-evm.cpio (未压缩的 rootfs 存档)
  • tisdk-Tina-image-am*-evm.cpio.xz (压缩存档)

此外, 还可以生成第三种与上述内容类似但附带额外 U-Boot 标头的.cpio 归档文件,以便于 U-Boot 使用/使用,即  tisdk-Tiny-image-am*-evm.cpio.gz.u-boot ,方法是将以下内容添加到 Yocto 的  local.conf  配置文件中:

# Generate a cpio archive which is compressed and has a U-Boot header
IMAGE_FSTYPES_append = " cpio.gz.u-boot"

(至少)有4种不同的方法可以加载和使用.cpio 格式的 rootfs 映像从 U-Boot 引导 Linux:

  1. 将 cpio 格式的映像直接构建到内核中(每次映像需要 更改时都需要重新构建内核)
  2. 通过 U-Boot 加载 cpio 格式的映像并将其传递到内核(保持内核恒定)
    1. 在 U-Boot 中加载标准 cpio 映像、并将其传递到 U-Boot bootti/bootm 命令
    2. 在 U-Boot 中加载标准 cpio 映像,并通过 initrd 直接将其传递给内核
    3. 使用 U-Boot 标头加载 cpio 映像、并将其传递到 U-Boot bootti/bootm 命令

让我们更仔细地看看这些选项...

加载和使用.cpio 格式化的 rootfs 映像从 U-Boot 引导 Linux 的方法

选项1:将 cpio 格式的映像直接构建到内核中

使用  CONFIG_initramfs_source Kernel config 选项(在 menuconfig 中的常规设置中)可以指向主机系统上的文件夹位置、该文件夹位置包含 带有.cpio 后缀的单个 cpio 归档文件或用于构建 initramfs 映像的以空格分隔的目录和文件列表。 使用内置 initramfs 映像构建内核时、它将直接初始化并使用此 initramfs、而无需任何特殊的 U-Boot 处理(只需将'-'作为 RAM 磁盘的地址传递到 booti/bootm 命令第二个参数)或对内核命令行进行所需的更新。 虽然这种方法易于部署/使用,但每次需要对 rootfs 进行更改时,都需要重新构建完整的内核。 以下示例说明了如何通过 TFTP 加载此类组合内核映像和设备树 BLOB 并引导它:

=> dhcp ${loadaddr} Image-with-initramfs-am62xx-evm.bin
link up on port 1, speed 1000, full duplex
BOOTP broadcast 1
DHCP client bound to address 192.168.1.67 (3 ms)
Using ethernet@8000000port@1 device
TFTP from server 192.168.1.1; our IP address is 192.168.1.67
Filename 'Image-with-initramfs-am62xx-evm.bin'.
Load address: 0x82000000
Loading: #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 ######
	 5 MiB/s
done
Bytes transferred = 22028800 (1502200 hex)

=> dhcp ${fdtaddr} k3-am625-sk.dtb 
link up on port 1, speed 1000, full duplex
BOOTP broadcast 1
DHCP client bound to address 192.168.1.67 (3 ms)
Using ethernet@8000000port@1 device
TFTP from server 192.168.1.1; our IP address is 192.168.1.67
Filename 'k3-am625-sk.dtb'.
Load address: 0x88000000
Loading: ####
	 4.1 MiB/s
done
Bytes transferred = 55666 (d972 hex)

# Do the minimum bootargs setup for consistency sake with other flows shown here
# (otherwise the dtb 'bootargs' property will take effect)
=> setenv args_initramfs 'setenv bootargs console=${console} ${optargs}'
=> run args_all args_initramfs

# Now boot the Kernel without explicitly specifying the initramfs address
# as it is fully baked into the Kernel
=> booti ${loadaddr} - ${fdtaddr}
## Flattened Device Tree blob at 88000000
   Booting using the fdt blob at 0x88000000
   Loading Device Tree to 000000008ffef000, end 000000008ffff971 ... OK

Starting kernel ...

选项2a: 在 U-Boot 中加载标准 cpio 映像并将其传递 到 U-Boot bootti/bootm 命令  

这是使用当前 TI SDK 时推荐的方法、因为 Yocto 构建工件可直接用于从 initramfs 成功引导、而无需进行任何进一步更改。 在这里、我们将 cpio 映像(压缩或未压缩-两者均有效)存储在引导介质上、并使用 U-Boot 从该介质加载、或通过其他方式(例如 TFTP)将其加载到 RAM 中。 然后、我们传递其位置_和_大小 (重要!) 直接转至 U-Boot bootti/bootm 命令 的第二个参数。 然后 U-Boot 将使用此信息来相应地设置内核引导。 通常、此方法的工作原理如下(例如使用 AM62器件型号):

=> load mmc 1:1 ${loadaddr} Image-am62axx-evm.bin
18526720 bytes read in 1547 ms (11.4 MiB/s)
=> load mmc 1:1 ${fdtaddr} k3-am62a7-sk-am62axx-evm.dtb
50483 bytes read in 19 ms (2.5 MiB/s)

# Load uncompressed cpio archive
=> load mmc 1:1 ${rdaddr} tisdk-tiny-image-am62axx-evm.cpio
6619136 bytes read in 562 ms (11.2 MiB/s)

...or....

# Load compressed cpio archive (Kernel will automatically extract)
=> load mmc 1:1 ${rdaddr} tisdk-tiny-image-am62axx-evm.cpio.xz
1802312 bytes read in 164 ms (10.5 MiB/s)

# Do the minimum bootargs setup for consistency sake with other flows shown here
# (otherwise the dtb 'bootargs' property will take effect)
=> setenv args_initramfs 'setenv bootargs console=${console} ${optargs}'
=> run args_all args_initramfs

# Now boot the Kernel with explicitly specifying the initramfs address
# and size as the second parameter. Do this step right after loading the
# initramfs image as we need ${filesize} to be initialized from that
# loading process.
=> booti ${loadaddr} ${rdaddr}:0x${filesize} ${fdtaddr}

选项2b: 在 U-Boot 中加载标准 cpio 映像,并通过 initrd 直接将其传递到内核

这是使用当前 TI SDK 时的另一种方法、因为 Yocto 编译工件可直接用于从 initramfs 成功引导、而无需进行任何进一步更改。 在这里、我们将 cpio 映像(压缩或未压缩-两者均有效)存储在引导介质上、并使用 U-Boot 从该介质加载、或通过其他方式(例如 TFTP)将其加载到 RAM 中。 我们通过更新内核命令行  initrd= 参数将其传递到内核、以指向加载地址_and_大小(重要!) 在 U-Boot 中 、booti/bootm 命令仍然传递'-'作为 RAM 磁盘(第二个参数)映像的地址。 通常、此方法的工作原理如下(例如使用 AM62器件型号):

=> load mmc 1:1 ${loadaddr} Image-am62axx-evm.bin
18526720 bytes read in 1547 ms (11.4 MiB/s)
=> load mmc 1:1 ${fdtaddr} k3-am62a7-sk-am62axx-evm.dtb
50483 bytes read in 19 ms (2.5 MiB/s)

# Load uncompressed cpio archive
=> load mmc 1:1 ${rdaddr} tisdk-tiny-image-am62axx-evm.cpio
6619136 bytes read in 562 ms (11.2 MiB/s)

...or....

# Load compressed cpio archive (Kernel will automatically extract)
=> load mmc 1:1 ${rdaddr} tisdk-tiny-image-am62axx-evm.cpio.xz
1802312 bytes read in 164 ms (10.5 MiB/s)

# Do this step right after loading the initramfs image as we need its ${filesize}
=> setenv args_initramfs 'setenv bootargs console=${console} ${optargs} initrd=${rdaddr},0x${filesize}'
=> run args_all args_initramfs

# Now boot the Kernel without explicitly specifying the initramfs address
# as this is done via the bootargs Kernel command line parameter
=> booti ${loadaddr} - ${fdtaddr}

选项2c: 使用 U-Boot 标头加载 cpio 映像、并将其传递到 U-Boot bootti/bootm 引导命令

这种方法有些是传统方法、但从 U-Boot 使用的角度来看可能是最方便用户的方法、因为它不需要更新内核命令行、或者必须跟踪 initramfs 文件大小、 但是、让 U-Boot 的 booti/bootm 命令执行提取 initramfs 映像大小并将其传递到内核的工作、方法是使用 booti/bootm 的第二个参数仅指定加载地址。 但是、它确实需要更新 Yocto Build 配置以生成 包含 所需 U-Boot 标头的*。gz.u-boot 类型的映像。  通常、此方法的工作原理如下(例如使用 AM62器件型号):

=> load mmc 1:1 ${loadaddr} Image-am62axx-evm.bin
18526720 bytes read in 1546 ms (11.4 MiB/s)
=> load mmc 1:1 ${fdtaddr} k3-am62a7-sk-am62axx-evm.dtb
50483 bytes read in 19 ms (2.5 MiB/s)
=> load mmc 1:1 ${rdaddr} tisdk-tiny-image-am62axx-evm.cpio.gz.u-boot
2958209 bytes read in 259 ms (10.9 MiB/s)

# Do the minimum bootargs setup for consistency sake with other flows shown here
# (otherwise the dtb 'bootargs' property will take effect)
=> setenv args_initramfs 'setenv bootargs console=${console} ${optargs}'
=> run args_all args_initramfs

# Now boot the Kernel with explicitly specifying the initramfs address
=> booti ${loadaddr} ${rdaddr} ${fdtaddr} 
## Loading init Ramdisk from Legacy Image at 88080000 ...
   Image Name:   tisdk-tiny-image-am62axx-evm-202
   Image Type:   AArch64 Linux RAMDisk Image (uncompressed)
   Data Size:    2958145 Bytes = 2.8 MiB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 88000000
   Booting using the fdt blob at 0x88000000
   Loading Ramdisk to 8fd2d000, end 8ffff341 ... OK
   Loading Device Tree to 000000008fd1d000, end 000000008fd2c532 ... OK

Starting kernel ...

常见问题的备注和解决方案

  • 通过 cpio 格式的归档文件使用 initramfs 是一种更现代/更高效的方法、可以通过实际 RAM 磁盘映像(initrd)执行传统上的引导操作、以下是有关此操作的一些良好背景: https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt
  • 确保内核配置为  CONFIG_BLK_DEV_initrd=y。 尽管名称可能表明这一点、但基于 initramfs/cpio 的引导也需要这一点。
  • 为了使内核能够从 initramfs 引导,它需要   在其根目录中有一个 init 文件。    基于 tisdk-Tina-image 的 cpio 存档将此文件作为指向 /sbin/init 的符号链接 (例如  ln -s /sbin/init init)。 也可以通过  rdinit= Kernel 命令行参数(例如  rdinit=/sbin/init.)显式指定 init 文件位置 否则、内核将引发如下错误: "kernel panic - not Syncing:no working init found (内核紧急-未同步:未找到正在工作的初始化)"。
  • 使用选项2a 时、请确保将 initramfs 位置_and_ size 传递给  U-Boot bootti/bootm 命令第二个参数。 位置和大小都需要用冒号分隔。 如果未指定大小、U-Boot 将不会引导内核、并出现如下错误: "Wrong Ramdisk Image Format (错误的 Ramdisk 映像格式)"。 RAMDISK 映像损坏或无效"
  • 使用选项2b 时、请确保将 initramfs 位置_and_ size 传递到 内核命令行  initrd= 参数、否则内核将根本无法识别 initramfs、并将以如下错误提示缺少引导介质: "kernel panic - not Syncing:vfs: 无法在未知块(0、0)上安装根 FS "