十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux 内核 PowerPC 启动包装器(Boot Wrapper)完全指南:镜像类型、构建流程与固件适配原理

Linux 内核 PowerPC 启动包装器(Boot Wrapper)完全指南:镜像类型、构建流程与固件适配原理 Linux 内核 PowerPC 启动包装器Boot Wrapper完全指南镜像类型、构建流程与固件适配原理【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux导读本文以 Linux 内核源码树中的官方文档 Documentation/arch/powerpc/bootwrapper.rst 为主体结合arch/powerpc/boot/目录下的真实实现系统讲解 PowerPC 架构特有的启动镜像生成机制。你将掌握zImage、uImage、cuImage、dtbImage、simpleImage、treeImage六类镜像格式的适用场景与差异理解 boot wrapper 如何在链接期按平台定制启动代码并能通过 Makefile 与 wrapper 脚本自行构建和剖析 PowerPC 启动镜像。PowerPC 平台没有统一的固件标准——OpenFirmware、U-Boot、PlanetCore、OpenBIOS 等固件接口并存各自需要不同的镜像格式。Linux 内核的解决方案是在arch/powerpc/boot/中实现一个可裁剪的 boot wrapper将压缩后的内核镜像vmlinux与必要的启动代码打包成固件可直接使用的镜像。这套机制的核心设计原则是wrapper 源码中不使用任何条件编译#ifdef所有组成部分在任何内核配置下都可编译最终通过链接期选择不同的目标文件组合来完成平台适配。一、为什么 PowerPC 需要 Boot WrapperPowerPC 镜像目标的构建流程是先压缩内核镜像vmlinux再用 boot wrapper 进行包装使其可被系统固件使用参见 bootwrapper.rst。由于不存在标准的 PowerPC 固件接口boot wrapper 被设计成可针对每种需要构建的镜像类型进行适配。常见固件接口包括OpenFirmwareApple、IBM 等厂商的通用 PowerPC 系统上最常见的固件类型能够向内核传递设备树device treeU-Boot嵌入式 PowerPC 硬件上的主流固件早期版本不支持设备树需要cuImage兼容其他固件如 OpenBIOS部分 ppc4xx 硬件、PlanetCoreEmbedded Planet 板卡等。每一种固件接口都对应一种不同的镜像格式这就是arch/powerpc/boot/目录下存在多种镜像目标的根本原因。二、六类镜像格式全解析官方文档用一张表完整列出了当前支持的镜像格式目标见 bootwrapper.rst。下表在此基础上补充了设备树来源与典型平台目标格式设备树处理方式典型适用场景备注cuImage.%镜像内嵌设备树不支持设备树的旧版 U-Boot平台相关需cuboot-*.c平台初始化代码dtbImage.%镜像内嵌设备树无法直接传递设备树的系统PS3、PlanetCore 板卡输出可为 ELF 或 flat binary含平台专属固件数据提取代码simpleImage.%镜像内嵌设备树完全与固件无关的场合flat binary可加载到 RAM 任意位置跳转不与固件通信treeImage.%镜像内嵌设备树OpenBIOS 固件的 ppc4xx 硬件—uImage由 U-Boot 在启动时传递支持设备树的较新版本 U-Boot不添加启动代码仅将压缩 vmlinux 包装进 uImage 数据结构zImage.%不嵌入设备树由固件提供OpenFirmware 及通用 PowerPC 硬件通用硬件首选格式各格式的核心差异在于设备树由谁提供以及是否需要与板级固件通信。2.1 cuImage旧版 U-Boot 的兼容镜像cuImage.%是为不理解设备树的旧版 U-Boot 设计的向后兼容镜像。boot wrapper、内核与设备树三者都被嵌入 U-Boot 的 uImage 文件格式中wrapper 启动代码会从旧的bd_info结构中提取数据并在跳入内核之前将其加载进设备树。由于旧 U-Boot 接口中bd_info结构体内部包含大量#ifdefcuImage 是平台相关的每个具体 U-Boot 平台都有一个独立的平台初始化文件负责用该平台特有的bd_info字段填充内嵌设备树。这些代码位于 arch/powerpc/boot/cuboot.*.c如cuboot-52xx.c、cuboot-83xx.c、cuboot-85xx.c、cuboot-bamboo.c等具体板卡应选用哪个初始化代码由 wrapper 脚本中的平台分支决定。2.2 dtbImage需要板级固件数据交互的嵌入镜像dtbImage.%与 zImage 类似区别在于设备树 blob 被嵌入镜像内部而非由固件提供输出文件可以是 ELF 或 flat binary取决于平台。它用于没有直接传递设备树接口的系统。文档特别指出dtbImage 与 simpleImage 的区别在于——dtbImage 包含从板级固件提取数据的平台专属代码而 simpleImage 完全不与固件通信。PlayStation 3 和采用 PlanetCore 固件的 Embedded Planet 板卡均使用 dtbImage。板级专属初始化代码通常位于arch/powerpc/boot/platform.c但可被 wrapper 脚本覆盖。2.3 simpleImage完全固件无关的镜像simpleImage.%是不依赖任何固件接口的压缩镜像内嵌设备树 blob输出为 flat binary可加载到 RAM 任意位置并直接跳转。固件无法向内核传递任何配置数据内核完全依赖内嵌设备树获取全部信息。2.4 treeImageOpenBIOS 专用镜像treeImage.%用于运行 OpenBIOS 固件的部分 ppc4xx 硬件同样在镜像内嵌入设备树 blob。2.5 uImage原生 U-Boot 镜像uImage是 U-Boot 的原生镜像格式不添加任何启动代码只是将压缩后的 vmlinux 包装进 uImage 数据结构。它要求 U-Boot 版本能够在内核启动时传递设备树如果使用旧版 U-Boot则应改用cuImage。2.6 zImage固件提供设备树的通用镜像zImage.%不嵌入设备树由 OpenFirmware 等能够提供设备树的固件接口在启动时传递。文档建议如果你拥有通用 PowerPC 硬件通常应选用这种格式。三、设备树从何处来dts 目录与目标命名约定所有内嵌设备树 blob 的镜像类型simpleImage、dtbImage、treeImage、cuImage都会从 arch/powerpc/boot/dts/ 目录下的设备树源文件生成 blob。Makefile 根据目标名称选择对应的设备树源文件如果执行make treeImage.walnut构建系统会自动使用arch/powerpc/boot/dts/walnut.dts来构建该镜像。设备树源文件采用标准 DTS 语法例如 bamboo.dts 中定义了amcc,bamboo板卡的模型、compatible字符串、CPU、内存与串口别名等信息/dts-v1/; / { #address-cells 2; #size-cells 1; model amcc,bamboo; compatible amcc,bamboo; dcr-parent {/cpus/cpu0}; aliases { ethernet0 EMAC0; serial0 UART0; /* ... */ }; cpus { cpu0 { device_type cpu; model PowerPC,440EP; reg 0x00000000; clock-frequency 0; /* Filled in by zImage */ /* ... */ }; }; };构建时DTS 文件通过设备树编译器dtc编译为 DTB 二进制。在 wrapper 脚本中当传入-s tree.dts参数时会自动调用dtc默认路径scripts/dtc/dtc生成 dtb见 wrapper 脚本第 182-190 行。四、构建系统Makefile 如何编排镜像生成Boot wrapper 由 arch/powerpc/boot/Makefile 构建并使用 arch/powerpc/boot/wrapper 脚本生成目标镜像。4.1 多平台内核与零条件编译设计arch/powerpc支持多平台内核multiplatform kernel即单个 vmlinux 可以在多个不同的目标板卡上启动这也意味着 boot wrapper 必须在一次构建中支持多种镜像。为此设计决策是wrapper 源码中不使用任何条件编译代码#ifdef 等所有 wrapper 组成部件在任何内核配置下都可以构建。每次内核构建都编译全部 wrapper 部件还能保证即使不常用的 wrapper 代码也在大量环境中至少通过编译测试参见 bootwrapper.rst 的 How it is built 一节。4.2 链接期适配wrapper.a 与平台目标文件wrapper 针对不同镜像类型的适配发生在链接期只链接该镜像类型所需的 wrapper 部件。Makefile 中将通用部件src-wlib-y如string.S、stdio.c、decompress.c、main.c、libfdt、串口驱动、zlib 解压代码等打包为wrapper.a将平台相关部件src-plat-y如of.c、epapr.c、各cuboot-*.c、ps3.c、gamecube.c等按 Kconfig 条件分别编译成独立目标文件见 Makefile 第 137-183 行src-wlib-y : string.S crt0.S stdio.c decompress.c main.c \ $(libfdt) libfdt-wrapper.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ elf_util.c $(zlib-y) devtree.c stdlib.c \ oflib.c ofconsole.c cuboot.c src-plat-y : of.c epapr.c src-plat-$(CONFIG_44x) treeboot-ebony.c cuboot-ebony.c ... src-plat-$(CONFIG_PPC_PS3) ps3-head.S ps3-hvcall.S ps3.c src-plat-$(CONFIG_PPC_PSERIES) pseries-head.Swrapper.a与选定的平台目标文件最终由 wrapper 脚本在链接阶段合并为最终镜像。4.3 交叉编译工具链由于 wrapper 可能以 32 位 ELF32 格式构建却要打包 64 位内核Makefile 专门支持独立的 32 位交叉编译前缀CROSS32_COMPILE与顶层 Makefile 的CROSS_COMPILE类似。未设置CROSS32_COMPILE时回退使用$(CC)/$(AR)64 位 wrapper 场景CONFIG_PPC64_BOOT_WRAPPER则使用-m64 -mabielfv2否则默认-m32见 Makefile 第 23-43 行。4.4 默认镜像选择与特殊目标zImage和zImage.initrd是两个特殊目标它们会构建内核配置选定的全部默认镜像。默认镜像通过在 boot wrapper Makefile 中向$image-y变量追加目标来选定例如image-$(CONFIG_PPC_PSERIES) zImage.pseries image-$(CONFIG_PPC_PS3) dtbImage.ps3 image-$(CONFIG_PPC_PMAC) zImage.pmac image-$(CONFIG_DEFAULT_UIMAGE) uImage image-$(CONFIG_EBONY) treeImage.ebony cuImage.ebony image-$(CONFIG_BAMBOO) treeImage.bamboo cuImage.bamboo image-$(CONFIG_MPC85xx_DS) cuImage.mpc8544ds cuImage.mpc8572ds image-$(CONFIG_GAMECUBE) dtbImage.gamecube image-$(CONFIG_WII) dtbImage.wii见 Makefile 第 277-363 行。image-y还支持通过CONFIG_EXTRA_TARGETS追加额外目标。所有zImage*默认目标都会自动生成对应的zImage.initrd*变体第 365-370 行的initrd-y规则用于携带ramdisk.image.gz。如果没有选择任何平台image-y退化为vmlinux.strip仅剥离符号的内核。4.5 压缩算法选择镜像压缩算法由内核压缩配置决定见 Makefile 第 266-269 行compressor-$(CONFIG_KERNEL_GZIP) : gz compressor-$(CONFIG_KERNEL_XZ) : xz compressor-$(CONFIG_KERNEL_LZMA) : lzma compressor-$(CONFIG_KERNEL_LZO) : lzo该变量作为-Z参数传给 wrapper 脚本控制gzip、xz、lzma、lzop等压缩工具的选择。zlib 解压代码从lib/zlib_inflate/复制到构建目录并通过 fixup-headers.sed 修正头文件包含路径。五、wrapper 脚本链接期平台适配的核心arch/powerpc/boot/wrapper 脚本由 Makefile 调用负责为镜像类型选择正确的 wrapper 部件。文档特别强调脚本参数在其注释块中有完整说明而脚本以-pplatform参数作为决定编译哪些 wrapper 部件的主要方法——即脚本中部的case $platform in大分支。5.1 命令行参数速查脚本顶部注释块完整列出了支持的命令行选项见 wrapper 第 10-24 行选项含义-o zImage指定输出文件-p platform指定平台链接进$platform.o-i initrd指定 initrd 文件-d devtree指定设备树 blob-s tree.dts指定设备树源文件需要安装 dtc-e esm_blob指定安全镜像用的 ESM blob-c缓存$kernel.strip.gz存在且更新则复用-C prefix指定交叉构建工具前缀strip、objcopy、ld-D dir指定脚本数据文件目录默认./arch/powerpc/boot-W dir指定临时文件工作目录默认.-z使用 gziplegacy-Z zsuffix压缩方式gz、xz、lzma、lzo或none此外还支持--no-gzip向后兼容的无压缩选项和-V1环境变量启用详细输出。5.2 平台分支链接顺序即适配手段脚本中部的case $platform in分支是平台适配的主战场它决定链接哪些平台目标文件、使用哪个链接脚本、以及内核在镜像中的链接地址。例如case $platform in of) platformo$object/of.o $object/epapr.o make_spacen ;; pseries) platformo$object/pseries-head.o $object/of.o $object/epapr.o link_address0x4000000 if [ $format ! elf32ppc ]; then link_address pie-pie notext-z notext fi ;; cuboot*) binaryy compression case $platform in *-mpc83*|*-asp834x*) platformo$object/cuboot-83xx.o ;; *-mpc85*|*-tqm85*) platformo$object/cuboot-85xx.o ;; ... esac ;; ps3) platformo$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o lds$object/zImage.ps3.lds ... ;; simpleboot-*) platformo$object/fixed-head.o $object/simpleboot.o binaryy ;; ... esac见 wrapper 第 254-384 行。这正是文档所说的通过改变链接顺序来选择平台专属 fixup的位置——例如cuboot-85xx.o对应 mpc85xx 系列、cuboot-83xx.o对应 mpc83xx 系列、ps3-head.o ps3-hvcall.o ps3.o对应 PS3 平台。5.3 镜像内部的节区布局wrapper 脚本使用objcopy --add-section将各个组件以独立节区形式嵌入中间 ELF 文件见 wrapper 第 463-487 行.kernel:vmlinux.strip剥离符号的压缩内核.kernel:initrdinitrd 镜像可选.kernel:dtb设备树 blob可选.kernel:esm_blob安全启动 ESM blob仅 pseries 支持。随后用ld按zImage.lds链接脚本将平台目标文件与wrapper.a合并产出最终镜像。这一节区布局使得内核、initrd 和设备树可以从生成的 zImage 中独立提取详见第六节。5.4 平台后处理链接完成后不同平台还会执行各自的镜像后处理第 509-578 行pseries/chrp运行addnote添加注记coffobjcopy -O aixcoff-rs6000转为 COFF 格式并用hack-coff修补cuboot*gzip 压缩后经mkimagescripts/mkuboot.sh包装为 U-Boot uImage 格式treeboot*用mktree工具生成 OpenBIOS 可用的树镜像ps3执行特殊的系统复位向量 overlay 处理将 boot wrapper 入口复制到 0x100 地址并检查镜像是否超过 PS3 flash loader 的 16 MiB 解压上限超限会生成otheros-too-big.bld。六、cuImage 深入bd_info 兼容层的实现cuImage 是最具平台特异性的一类镜像文档提醒cuImage 的 wrapper 部件与板卡强相关构建前务必确认目标板卡受 wrapper 部件支持。从源码看cuboot兼容层的工作机制如下cuboot.c 中的cuboot_init()接收 U-Boot 通过寄存器传入的bd_info相关信息initrd 地址/大小、命令行参数初始化简单内存分配器void cuboot_init(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long end_of_ram) { unsigned long avail_ram end_of_ram - (unsigned long)_end; loader_info.initrd_addr r4; loader_info.initrd_size r4 ? r5 - r4 : 0; loader_info.cmdline (char *)r6; loader_info.cmdline_len r7 - r6; simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64); }而每个板卡的平台初始化文件如 cuboot-bamboo.c通过CUBOOT_INIT()宏把板卡特有的bd_t静态结构体暴露给 wrapper并调用板级初始化函数如bamboo_init(bd.bi_enetaddr, bd.bi_enet1addr)将 MAC 地址等来自bd_info的数据填入设备树static bd_t bd; void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { CUBOOT_INIT(); bamboo_init(bd.bi_enetaddr, bd.bi_enet1addr); }这一层正是文档所描述的每个具体 U-Boot 平台都有不同的平台初始化文件用平台特定的 bd_info 数据填充内嵌设备树的代码级印证。七、从 zImage 中提取内核组件构建出的 zImage 是一个自包含容器arch/powerpc/boot/README 给出了利用节区布局反向提取各组件的标准方法# 提取压缩的内核 vmlinux objcopy -j .kernel:vmlinux -O binary zImage vmlinux.gz # 提取 System.map objcopy -j .kernel:System.map -O binary zImage System.map.gz # 提取 .config objcopy -j .kernel:.config -O binary zImage config.gz # 提取 initrd objcopy -j .kernel:initrd -O binary zImage.initrd initrd.gz这在调试、取证或需要复用镜像中已打包组件时非常实用。八、注意事项与最佳实践构建 cuImage 前务必核对板卡支持cuImage 与具体 U-Boot 平台的bd_info结构强绑定目标板卡必须能在 arch/powerpc/boot/cuboot-*.c 中找到对应实现否则无法正确填充设备树。设备树由谁提供决定镜像类型固件能传设备树如新版 U-Boot、OpenFirmware用zImage/uImage不能传则用内嵌设备树的simpleImage/dtbImage/treeImage/cuImage是否需要与固件交互通信决定了选simpleImage零交互还是dtbImage有板级数据提取代码。默认镜像集合由内核配置决定运行make zImage构建的是$image-y变量中由 Kconfig 选定的全部默认镜像而非单一文件查看 arch/powerpc/boot/Makefile 可确认当前配置下会有哪些默认目标。交叉编译32 位 wrapper 打包 64 位内核时需要正确设置CROSS32_COMPILE前缀wrapper 脚本本身通过-C参数传递交叉工具前缀strip、objcopy、ld。链接地址自动修正wrapper 脚本会在未压缩内核体积超过 wrapper 链接地址时自动将链接地址上取整到下一个 MB 边界make_space逻辑见 wrapper 第 425-438 行避免镜像重叠。总结PowerPC boot wrapper 是 Linux 内核应对固件接口碎片化的经典工程实践通过将启动代码拆分为通用库wrapper.a与平台目标文件利用 wrapper 脚本在链接期而非编译期完成平台适配既实现了单 vmlinux 多平台启动又保证了所有 wrapper 代码在各种环境下获得编译覆盖。理解这六类镜像格式的差异、case $platform分支的适配逻辑以及内嵌节区的布局是进行 PowerPC 平台内核移植、板卡 bring-up 与启动镜像排障的基础。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表