加載支持全解析)
固件嵌入式操作系統(tǒng)驅(qū)動開發(fā)【免費下載鏈接】corebootRead-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We dont handle Pull Requests.項目地址https://gitcode.com/gh_mirrors/co/coreboot點擊查看免費下載coreboot 完成硬件初始化后需要把控制權(quán)移交給一個后續(xù)程序payload例如 Linux 內(nèi)核、SeaBIOS 或 U-Boot。本文以 coreboot 官方文檔 Documentation/lib/payloads/index.md 為骨架結(jié)合倉庫內(nèi)src/lib/fit.c、src/lib/fit_payload.c以及各架構(gòu)的fit_payload.c源碼系統(tǒng)講解 coreboot 的 payload 體系并重點深入 uImage.FITFlattened Image Tree這一原生 Linux payload 格式包括其支持架構(gòu)、FIT 分區(qū)與配置選擇機制、compat 字符串匹配原理、壓縮算法、以及從 ITS 源文件到mkimage生成 uImage 的完整構(gòu)建流程。讀完本文你將能獨立為基于 aarch32 / aarch64 / RISC-V 的 coreboot 主板上配置并構(gòu)建一個可引導(dǎo) Linux 的 FIT payload。一、什么是 Payloadcoreboot 移交控制權(quán)的最后一棒coreboot 本身只負責(zé)硬件的早期初始化romstage、ramstage引導(dǎo)流程的最后一步是把控制權(quán)交給一個 payload。官方文檔的描述是Payloads are run after coreboot has initialized the hardware. coreboot supports multiple payloads, depending on the architecture of the selected mainboard.也就是說payload 是運行在 coreboot 完成硬件初始化之后的程序coreboot 支持哪些 payload取決于所選主板的架構(gòu)。coreboot 原生的 payload 二進制格式是 SimpleELFSELF它在 CBFS 文檔 中作為CBFS_TYPE_SELF0x20詳細記載。從 CBFS 的角度看payload 是 CBFS 中的一個文件條目。CBFS 是 coreboot 用于在系統(tǒng) ROM 中管理獨立數(shù)據(jù)塊的扁平、追加式歸檔格式詳見 Documentation/lib/cbfs.md一次典型的引導(dǎo)過程如下/------------------------\ - flash 起始 | FMAP | describes the region layout |------------------------| | COREBOOT | --\ | /-------------------\ | | | | fallback/payload | | |-- 一個 CBFS 實例 | | fallback/ramstage | | | | | fallback/romstage | | | | | bootblock | | | | \-------------------/ | | \------------------------/ - flash 末尾其中fallback/payload就是最終要執(zhí)行的 payload 文件。CBFS 中與 payload 相關(guān)的文件類型見 cbfs.md 的 File types 章節(jié)名稱值內(nèi)容SELF0x20一個 SELF 格式的 payloadFIT_PAYLOAD0x21一個 FIT 格式的 payload需要特別留意的是FIT_PAYLOAD一種扁平鏡像樹與INTEL_FIT0x54由 Intel CPU 微碼消費的指針表雖然縮寫相同但完全是兩回事。SELF 格式回顧cbfstool 如何把 ELF 變成 payload在深入 FIT 之前先回顧 SELF 這一原生格式。靜態(tài)鏈接的 ELF 二進制在構(gòu)建時由cbfstool的add-payload命令轉(zhuǎn)換為 SELF二進制被拆分為多個段每個段擁有獨立的加載地址和壓縮方式LZMA、LZ4、ZSTD 或 none。SELF payload 是一串段頭后跟段數(shù)據(jù)定義見 cbfs.mdstruct cbfs_payload_segment { uint32_t type; uint32_t compression; uint32_t offset; uint64_t load_addr; uint32_t len; uint32_t mem_len; } __packed;段類型包括PAYLOAD_SEGMENT_CODE可執(zhí)行代碼、PAYLOAD_SEGMENT_DATA數(shù)據(jù)、PAYLOAD_SEGMENT_BSS清零內(nèi)存和PAYLOAD_SEGMENT_ENTRY入口點。與 FIT 不同SELF 的壓縮是逐段進行的而不是通過文件級COMPRESSION屬性。SELF 加載器實現(xiàn)在 src/lib/selfboot.c它在加載前會用 bootmem 映射檢查每個段因此段必須落在可用 RAM 內(nèi)——SELF payload從不重定位固定加載在指定的地址地址不可用則無法引導(dǎo)。二、FIT面向 Linux 的扁平鏡像樹格式uImage.FIT 是 U-Boot 社區(qū)為 uImage payload 開發(fā)的新格式目前也是 coreboot 在 aarch32、aarch64、RISC-V 架構(gòu)上引導(dǎo) Linux 的推薦方式之一。它的核心思想是把內(nèi)核、initrd、設(shè)備樹FDT和啟動配置打包進一個統(tǒng)一的容器由 coreboot 在引導(dǎo)時解析、選擇合適的配置并逐項解壓、落位。支持的架構(gòu)FIT 解析器需要架構(gòu)級支持官方文檔明確列出了三個支持架構(gòu)其余架構(gòu)如 x86不支持aarch32aarch64riscv對應(yīng)源碼架構(gòu)架構(gòu)相關(guān)源碼內(nèi)核格式要求aarch32src/arch/arm/fit_payload.cImage格式 FDTaarch64src/arch/arm64/fit_payload.cImage格式 FDTRISC-Vsrc/arch/riscv/fit_payload.cImage格式 FDT三個架構(gòu)有一個共同點內(nèi)核必須是Image格式即 ARM/RISC-V 內(nèi)核的扁平鏡像格式而非壓縮的 zImage并且都必須攜帶設(shè)備樹fdt才能引導(dǎo)。從源碼看RISC-V 側(cè)src/arch/riscv/fit_payload.c甚至?xí)谌笔?FDT 時直接報錯if (!config-fdt || !fdt) { printk(BIOS_CRIT, Providing a valid FDT is mandatory to boot a RISC-V kernel!\n); return false; }FIT 包含的分區(qū)sections一個 FIT 鏡像可以包含多個分區(qū)每個分區(qū)持有唯一的內(nèi)核、initrd 或配置。引導(dǎo)時根據(jù)匹配的配置從眾多分區(qū)中挑出一個內(nèi)核和一個 initrd。分區(qū)必須按以下名稱命名FIT 解析器才能找到它們見 fit.mdkernelfdtramdisk在源碼層面src/lib/fit.c的config_node()正是按屬性名查找這些分區(qū)配置節(jié)點中的kernel、fdt、ramdisk屬性分別通過find_image()關(guān)聯(lián)到/images下的同名節(jié)點。此外fdt屬性還支持通過空格分隔的多個名稱指定FDT overlay 鏈find_image_with_overlays()coreboot 會把 overlay 依次應(yīng)用到基礎(chǔ) FDT 上見 src/lib/fit_payload.c 的list_for_each(chain, config-overlays, ...)循環(huán)。三、配置選擇與 Compat 字符串匹配機制FIT 的核心價值在于一份鏡像、多種配置同一個 uImage 里可以存放面向多個板卡的 FDT/內(nèi)核組合引導(dǎo)時按 compat 字符串自動選擇。默認 compat 字符串FIT 配置條目中的compatible屬性用于尋找匹配的配置。coreboot 會調(diào)用主板特有的函數(shù)獲取 BOARDID 和 SKUIDuint32_t board_id(void); uint32_t sku_id(void);默認情況下src/lib/fit.c 的fit_add_default_compat_strings()會依次注冊如下 compat 字符串優(yōu)先級從低到高CONFIG_MAINBOARD_VENDOR,CONFIG_MAINBOARD_PART_NUMBERCONFIG_MAINBOARD_VENDOR,CONFIG_MAINBOARD_PART_NUMBER-revBOARDIDCONFIG_MAINBOARD_VENDOR,CONFIG_MAINBOARD_PART_NUMBER-revBOARDID-skuSKUIDCONFIG_MAINBOARD_VENDOR,CONFIG_MAINBOARD_PART_NUMBER-skuSKUID源碼中同樣會注冊例如文檔給出的示例cavium,cn8100_sff_evb如果board_id()或sku_id()返回?zé)o效值對應(yīng)那一條 compat 字符串就不會被添加源碼中通過UNDEFINED_STRAPPING_ID判斷。需要指出的是先注冊的字符串優(yōu)先級更高見 src/include/fit.h 中fit_add_compat_string()的注釋Strings that were added first have a higher priority on finding a match。默認字符串注冊順序為vendor,part-revX-skuY→vendor,part-revX→vendor,part-skuY→vendor,part因此最精確的revsku組合擁有最高優(yōu)先級匹配到后即被選中。自定義 compat 字符串主板可以在板級代碼中調(diào)用以下函數(shù)追加自定義 compat 字符串fit_add_compat_string(const char *str);該函數(shù)src/lib/fit.c會保存字符串的副本并通過clean_compat_string()將其轉(zhuǎn)為小寫、并把_和空格替換為-隨后插入 compat 列表。這解釋了為什么默認字符串中的CONFIG_MAINBOARD_VENDOR、CONFIG_MAINBOARD_PART_NUMBER配置值會被規(guī)范化成類似cavium,cn8100_sff_evb的小寫連字符形式。匹配與回退邏輯fit_load()src/lib/fit.c是整套選擇邏輯的入口用fdt_unflatten()解包整個 FIT 鏡像遍歷/images下的所有鏡像節(jié)點、/configurations下的所有配置節(jié)點跳過缺少 kernel、缺少 fdt、或 ramdisk 壓縮算法不支持的配置對每個配置計算其compatible屬性與本地 compat 列表的匹配位置和優(yōu)先級選優(yōu)順序有 compat 匹配的配置 匹配優(yōu)先級最高者 顯式指定的 default 配置若既無匹配也無 default 配置則報錯放棄No compatible or default configs. Giving up.。文檔特別說明如果沒有找到任何匹配的 compat 字符串就選擇 default 配置由configurations節(jié)點的default屬性指定。fit_load()解析完成后fit_payload()src/lib/fit_payload.c負責(zé)真正裝載解包 FDT、應(yīng)用 overlay 與 fixup、把 coreboot 表/CBMEM 信息add_cb_fdt_data()寫入設(shè)備樹firmware/coreboot節(jié)點、根據(jù)CONFIG_LINUX_COMMAND_LINE寫入chosen/bootargs、調(diào)用架構(gòu)相關(guān)的fit_payload_arch()擺放內(nèi)核/FDT/initrd最后通過extract()解壓并跳轉(zhuǎn)。四、支持的壓縮算法與 CBFS 集成約束關(guān)于壓縮官方文檔有一項重要約束The FIT image has to be included uncompressed into the CBFS. The sections inside the FIT image can use different compression schemes.即FIT 鏡像本身必須以未壓縮形式放進 CBFS這也是 cbfs.md 所述 FIT payload does not support whole-file compression 的原因但 FIT內(nèi)部的各個分區(qū)可以各自采用不同的壓縮方案。支持三種LZMALZ4none源碼驗證src/lib/fit.c的image_node()只識別這三種compression屬性值none、lzma、lz4其它值一律置為-1表示不支持src/lib/fit_payload.c的extract()也僅實現(xiàn)了CBFS_COMPRESS_NONEmemcpy 搬運、CBFS_COMPRESS_LZMAulzman與CBFS_COMPRESS_LZ4ulz4fn三分支其它壓縮直接報 Unsupported compression。這與 CBFS 文件級支持的四種算法none/LZMA/LZ4/Zstandard不同——FIT 分區(qū)不支持 Zstandard。五、各架構(gòu)的裝載細節(jié)內(nèi)核、FDT、initrd 如何落位fit_payload_arch()是架構(gòu)相關(guān)代碼的唯一入口聲明于 src/include/fit.h負責(zé)把內(nèi)核、FDT、initrd 擺放到內(nèi)存中合適的可用 RAM 區(qū)域并設(shè)置入口點。各架構(gòu)的算法均由bootmem_walk()遍歷 bootmem 映射中的可用 RAM 完成擺放結(jié)果同時用bootmem_add_range(..., BM_MEM_PAYLOAD)標(biāo)記為預(yù)留避免后續(xù)分配沖突。aarch64src/arch/arm64/fit_payload.c 的實現(xiàn)最精細先做部分解壓讀取內(nèi)核 Image 頭decompress_kernel_header()校驗?zāi)?shù)0x644d5241ARM64_IMAGE_MAGIC并獲取text_offset與image_size內(nèi)核的擺放遵循 ARM64 規(guī)范放在距 2 MiB 對齊基址偏移text_offset處若內(nèi)核頭未設(shè)置image_size則按文檔約定回退為text_offset 0x80000并在內(nèi)核后預(yù)留最多MAX_KERNEL_SIZE64 MiB自由空間get_kernel_size()內(nèi)核入口通過prog_set_entry(payload, (void *)kernel-offset, arg)設(shè)置arg是 FDT 地址——內(nèi)核期望 FDT 作為首個參數(shù)initrd 與 FDT 的位置取決于內(nèi)核頭 flags 的 bit 3place_anywhere4.6 之前的內(nèi)核無法使用 Image 物理偏移之下的內(nèi)存此時 initrd/FDT 必須放在內(nèi)核之后。aarch32src/arch/arm/fit_payload.c 相對簡單內(nèi)核放在_dram 32 MiB處避開解壓時需重定位的區(qū)域FDT 放在_dram 128 MiB以上防止被內(nèi)核解壓器覆蓋initrd 緊隨 FDT 之后所有區(qū)域按 1 MiB 對齊Linux 4.15 doesnt like 4KiB alignment. Align to 1 MiB for now.。RISC-Vsrc/arch/riscv/fit_payload.c 實現(xiàn)的是兼容 Berkeley Boot LoaderBBL的加載方式內(nèi)核放在按SECTION_ALIGN對齊的可用內(nèi)存RV64 為 2 MiBRV32 為 4 MiBFDT 與 initrd 依次排在內(nèi)核之后入口參數(shù)同樣是 FDT 地址。結(jié)合 src/arch/riscv/boot.c 可以看到RISC-V 上 payload 與 coreboot 表的交接方式也與眾不同coreboot 會把 coreboot 表指針以coreboot-table屬性嵌入 FDT 的/chosen節(jié)點且調(diào)用約定在 HARTID、FDT 之后coreboot 表作為第三個參數(shù)傳入這與 CBFS 文檔中關(guān)于 SELF 調(diào)用約定的特例說明一致。六、構(gòu)建 FIT 鏡像從 ITS 到 uImageFIT 鏡像必須通過 U-Boot 的mkimage工具構(gòu)建。官方文檔 fit.md 給出了完整的示例配置下面完整繼承并補充注釋/* * Simple U-Boot uImage source file containing a single kernel and FDT blob */ /dts-v1/; / { description Simple image with single Linux kernel and FDT blob; #address-cells 1; images { kernel { description Vanilla Linux kernel; data /incbin/(Image.lzma); /* 內(nèi)核數(shù)據(jù)LZMA 壓縮的 Image */ type kernel; arch arm64; /* 目標(biāo)架構(gòu)arm64 */ os linux; compression lzma; /* 該分區(qū)壓縮算法lzma / lz4 / none */ load 0x80000; /* 建議加載地址aarch64 慣例 */ entry 0x80000; /* 入口地址 */ hash-1 { algo crc32; }; }; fdt-1 { description Flattened Device Tree blob; data /incbin/(target.dtb); /* 設(shè)備樹數(shù)據(jù) */ type flat_dt; arch arm64; compression none; /* FDT 通常不壓縮 */ hash-1 { algo crc32; }; }; ramdisk-1 { description Compressed Initramfs; data /incbin/(initramfs.cpio.xz); /* 由 Linux 內(nèi)核自行解壓的 initrd */ type ramdisk; arch arm64; os linux; compression none; /* 此處不用 FIT 解壓交給內(nèi)核 */ load 00000000; entry 00000000; hash-1 { algo sha1; }; }; }; configurations { default conf-1; /* 無 compat 匹配時的回退配置 */ conf-1 { description Boot Linux kernel with FDT blob; kernel kernel; /* 引用 /images 下的分區(qū)名 */ fdt fdt-1; ramdisk ramdisk-1; /* 可在此添加 compatible vendor,board; 以便按 compat 精確匹配 */ }; }; };將這個文件保存為 ITS 源文件config.its并與以下文件放在同一目錄target.dtb—— 設(shè)備樹二進制initramfs.cpio.xz—— 壓縮的 initramfsImage.lzma—— LZMA 壓縮的 ARM64/ARM/RISC-V 內(nèi)核 Image然后執(zhí)行mkimage -f config.its uImage生成的uImage中initramfs.cpio.xz會在引導(dǎo)后由 Linux 內(nèi)核負責(zé)解壓Image.lzma由 coreboot 的 FIT 加載器extract()中的ulzman解壓target.dtb以未壓縮形式隨鏡像交付。最終把uImage作為 FIT payload 加入 CBFS 即可CBFS 文件類型為FIT_PAYLOAD0x21。七、接入 coreboot 構(gòu)建系統(tǒng)Kconfig 配置要點從 payloads/Kconfig 可以看到 FIT payload 的配置入口PAYLOAD_FIT布爾選項 A FIT payload選中后自動select PAYLOAD_FIT_SUPPORTPAYLOAD_FILE指定 payload 文件路徑當(dāng)PAYLOAD_FIT時默認值為uImage壓縮默認值FIT 支持時默認COMPRESSED_PAYLOAD_NONE與FIT 鏡像必須以未壓縮形式放入 CBFS的約束呼應(yīng)非 FIT 時默認COMPRESSED_PAYLOAD_LZMA。構(gòu)建時相關(guān)文件按架構(gòu)納入編譯例如 src/arch/arm64/Makefile.mk 中的ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) fit_payload.c即只有開啟 FIT 支持時才把fit_payload.c編入 ramstage。RISC-V 側(cè)src/arch/riscv/Makefile.mk則無條件編入。引導(dǎo)時各架構(gòu)通過prog_cbfs_type(prog) CBFS_TYPE_FIT_PAYLOAD判斷 payload 類型如 src/arch/arm/boot.c 在 ramstage 中調(diào)用boot_linux()直接跳轉(zhuǎn)內(nèi)核說明 FIT payload 只在 ramstage 階段執(zhí)行。八、調(diào)試與排查建議結(jié)合源碼中的日志輸出printk排查 FIT 引導(dǎo)問題時可關(guān)注以下節(jié)點無法選擇配置fit_load()會打印每個配置的 compat 及匹配情況FIT: config xxx, kernel yyy, fdt zzz (match)最終若輸出No compatible or default configs. Giving up.說明 ITS 中既無匹配的compatible也沒有default配置找不到鏡像Cannot find image node xxx!表示配置引用的分區(qū)名與/images下的節(jié)點名不一致注意區(qū)分kernel與kernel1這類命名不支持壓縮Unsupported compression或Ramdisk is compressed with an unsupported algorithm提示分區(qū)壓縮算法不在 LZMA/LZ4/none 之列ZSTD 不支持內(nèi)存擺放失敗Failed to find free memory region并伴隨bootmem_dump_ranges()輸出的內(nèi)存映射說明內(nèi)核/FDT/initrd 找不到足夠的可用 RAM例如與 ramstage 重疊FDT 缺失RISC-V 下Providing a valid FDT is mandatory to boot a RISC-V kernel!表明配置未提供 fdt 分區(qū)。總結(jié)coreboot 的 payload 機制以 SELF 為原生格式同時為 aarch32、aarch64、RISC-V 架構(gòu)提供了完善的 uImage.FIT 支持FIT 解析器src/lib/fit.c負責(zé)解包鏡像并依據(jù) compat 字符串或 default 配置選定引導(dǎo)配置架構(gòu)相關(guān)的 fit_payload.c 負責(zé)按各架構(gòu)規(guī)范把內(nèi)核、FDT、initrd 擺放到安全的可用內(nèi)存最終跳轉(zhuǎn)內(nèi)核。實踐中只需按本文第六節(jié)的 ITS 模板準(zhǔn)備Image、target.dtb、initramfs.cpio.xz用mkimage -f config.its uImage生成鏡像并通過PAYLOAD_FIT配置接入構(gòu)建即可完成一個由 coreboot 直接引導(dǎo) Linux 的 FIT payload 方案。贊分享固件嵌入式操作系統(tǒng)驅(qū)動開發(fā)【免費下載鏈接】corebootRead-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We dont handle Pull Requests.項目地址https://gitcode.com/gh_mirrors/co/coreboot點擊查看免費下載相關(guān)推薦coreboot 的 Flattened uImage TreeFITPayload 引導(dǎo)機制與 uImage 構(gòu)建實戰(zhàn)指南coreboot 的 Flattened uImage TreeFITPayload 引導(dǎo)機制與 uImage 構(gòu)建實戰(zhàn)指南 本指南以倉庫內(nèi) Documen固件嵌入式操作系統(tǒng)驅(qū)動開發(fā)coreboot 支持 vbootVerified Boot的設(shè)備清單與啟用機制深度解析coreboot 支持 vbootVerified Boot的設(shè)備清單與啟用機制深度解析 導(dǎo)讀 本文面向 coreboot 開發(fā)者與固件安全研究人員系統(tǒng)梳固件嵌入式操作系統(tǒng)驅(qū)動開發(fā)Atmosphere重啟機制全解析warmboot payload與冷啟動流程Atmosphere重啟機制全解析warmboot payload與冷啟動流程 概述 Atmosphere作為Nintendo Switch的定制固件其重啟固件操作系統(tǒng)嵌入式系統(tǒng)編程上一篇mtkclient項目Realme C3設(shè)備Bootloop問題分析與解決指南下一篇Web Audio API實戰(zhàn)PitchDetect中的音頻流處理與分析技術(shù)創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考