早期用户空间支持¶
最后更新:2004-12-20 tlh
“早期用户空间”是一组库和程序,它们提供各种功能,这些功能非常重要,可以在 Linux 内核启动时使用,但不需要在内核本身内部运行。
它由几个主要的基础设施组件组成
gen_init_cpio,一个构建包含根文件系统镜像的 cpio 格式存档的程序。 该存档被压缩,压缩后的镜像链接到内核镜像中。
initramfs,一段代码,在内核引导过程中间解压缩压缩的 cpio 镜像。
klibc,一个用户空间 C 库,目前单独打包,它针对正确性和小尺寸进行了优化。
initramfs 使用的 cpio 文件格式是 “newc”(又名 “cpio -H newc”)格式,并在 “initramfs 缓冲区格式” 文件中进行了说明。 有两种方法可以添加早期用户空间镜像:指定要用作镜像的现有 cpio 存档,或者让内核构建过程从规范构建镜像。
CPIO 归档方法¶
您可以创建一个包含早期用户空间镜像的 cpio 存档。 您的 cpio 存档应在 CONFIG_INITRAMFS_SOURCE 中指定,它将被直接使用。 CONFIG_INITRAMFS_SOURCE 中只能指定一个 cpio 文件,并且不允许目录和文件名与 cpio 存档组合使用。
镜像构建方法¶
内核构建过程也可以从源部分构建早期用户空间镜像,而不是提供 cpio 存档。 这种方法提供了一种创建具有 root 拥有的文件的镜像的方法,即使该镜像是由非特权用户构建的。
该镜像在 CONFIG_INITRAMFS_SOURCE 中指定为一个或多个源。 源可以是目录或文件 - 从源构建时不允许 cpio 存档。
源目录将打包其自身及其所有内容。 指定的目录名称将映射到“/”。 打包目录时,可以执行有限的用户和组 ID 转换。 可以将 INITRAMFS_ROOT_UID 设置为需要映射到用户 root (0) 的用户 ID。 可以将 INITRAMFS_ROOT_GID 设置为需要映射到组 root (0) 的组 ID。
源文件必须是 usr/gen_init_cpio 实用程序所需的格式的指令(运行“usr/gen_init_cpio -h”以获取文件格式)。 文件中的指令将直接传递给 usr/gen_init_cpio。
当指定目录和文件组合时,initramfs 镜像将是它们的聚合。 通过这种方式,用户可以创建一个“root-image”目录并将所有文件安装到其中。 由于设备专用文件不能由非特权用户创建,因此可以在“root-files”文件中列出特殊文件。 “root-image”和“root-files”都可以列在 CONFIG_INITRAMFS_SOURCE 中,并且完整的早期用户空间镜像可以由非特权用户构建。
作为一个技术说明,当指定目录和文件时,整个 CONFIG_INITRAMFS_SOURCE 将传递给 usr/gen_initramfs.sh。 这意味着 CONFIG_INITRAMFS_SOURCE 实际上可以解释为 gen_initramfs.sh 的任何合法参数。 如果指定一个目录作为参数,则扫描内容,执行 uid/gid 转换,并输出 usr/gen_init_cpio 文件指令。 如果将目录指定为 usr/gen_initramfs.sh 的参数,则文件的内容将简单地复制到输出。 目录扫描和文件内容复制的所有输出指令都由 usr/gen_init_cpio 处理。
另请参阅“usr/gen_initramfs.sh -h”。
这一切都指向哪里?¶
klibc 发行版包含一些必要的软件,使早期用户空间有用。 klibc 发行版目前与内核分开维护。
您可以从 https://linuxkernel.org.cn/pub/linux/libs/klibc/ 获取不太频繁的 klibc 快照
对于活跃用户,最好使用 klibc git 存储库,地址为 https://git.kernel.org/?p=libs/klibc/klibc.git
除了 klibc 库之外,独立的 klibc 发行版目前还提供三个组件
ipconfig,一个配置网络接口的程序。 它可以静态配置它们,也可以使用 DHCP 动态获取信息(又名“IP 自动配置”)。
nfsmount,一个可以挂载 NFS 文件系统的程序。
kinit,“胶水”,它使用 ipconfig 和 nfsmount 来替换对 IP 自动配置的旧支持,通过 NFS 挂载文件系统,并继续使用该文件系统作为 root 来引导系统。
kinit 构建为单个静态链接的二进制文件,以节省空间。
最终,希望有更多的内核功能转移到早期用户空间
几乎所有的 init/do_mounts*(这部分的开头已经到位)
ACPI 表解析
在此处插入不需要真正位于内核空间中的笨拙子系统
如果 kinit 不能满足您当前的需求,并且您有足够的字节要烧毁,则 klibc 发行版包含一个小的 Bourne 兼容 shell (ash) 和许多其他实用程序,因此您可以替换 kinit 并构建完全满足您需求的自定义 initramfs 镜像。
如有问题和帮助,您可以在 https://www.zytor.com/mailman/listinfo/klibc 注册早期用户空间邮件列表
它是如何工作的?¶
内核目前有 3 种挂载根文件系统的方法
所有必需的设备和文件系统驱动程序都编译到内核中,没有 initrd。 init/main.c:init() 将调用 prepare_namespace() 以挂载最终的根文件系统,基于 root= 选项和可选的 init= 以运行一些其他 init 二进制文件,而不是列在 init/main.c:init() 的末尾。
一些设备和文件系统驱动程序构建为模块并存储在 initrd 中。 initrd 必须包含一个二进制文件“/linuxrc”,该文件应该加载这些驱动程序模块。 也可以通过 linuxrc 挂载最终的根文件系统并使用 pivot_root 系统调用。 initrd 通过 prepare_namespace() 挂载和执行。
使用 initramfs。 必须跳过对 prepare_namespace() 的调用。 这意味着一个二进制文件必须完成所有工作。 该二进制文件可以通过修改 usr/gen_init_cpio.c 或通过新的 initrd 格式(一个 cpio 存档)存储到 initramfs 中。 它必须被称为“/init”。 此二进制文件负责完成 prepare_namespace() 将完成的所有事情。
为了保持向后兼容性,/init 二进制文件仅在它通过 initramfs cpio 存档时才会运行。 如果不是这种情况,init/main.c:init() 将运行 prepare_namespace() 以挂载最终的根并执行预定义的 init 二进制文件之一。
Bryan O’Sullivan <bos@serpentine.com>