加載支持全解析)
固件嵌入式操作系統(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 完成硬件初始化后需要把控制權移交給一個后續(xù)程序payload例如 Linux 內(nèi)核、SeaBIOS 或 U-Boot。本文以 coreboot 官方文檔 Documentation/lib/payloads/index.md 為骨架結合倉庫內(nèi)src/lib/fit.c、src/lib/fit_payload.c以及各架構的fit_payload.c源碼系統(tǒng)講解 coreboot 的 payload 體系并重點深入 uImage.FITFlattened Image Tree這一原生 Linux payload 格式包括其支持架構、FIT 分區(qū)與配置選擇機制、compat 字符串匹配原理、壓縮算法、以及從 ITS 源文件到mkimage生成 uImage 的完整構建流程。讀完本文你將能獨立為基于 aarch32 / aarch64 / RISC-V 的 coreboot 主板上配置并構建一個可引導 Linux 的 FIT payload。一、什么是 Payloadcoreboot 移交控制權的最后一棒coreboot 本身只負責硬件的早期初始化romstage、ramstage引導流程的最后一步是把控制權交給一個 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取決于所選主板的架構。coreboot 原生的 payload 二進制格式是 SimpleELFSELF它在 CBFS 文檔 中作為CBFS_TYPE_SELF0x20詳細記載。從 CBFS 的角度看payload 是 CBFS 中的一個文件條目。CBFS 是 coreboot 用于在系統(tǒng) ROM 中管理獨立數(shù)據(jù)塊的扁平、追加式歸檔格式詳見 Documentation/lib/cbfs.md一次典型的引導過程如下/------------------------\ - flash 起始 | FMAP | describes the region layout |------------------------| | COREBOOT | --\ | /-------------------\ | | | | fallback/payload | | |-- 一個 CBFS 實例 | | fallback/ramstage | | | | | fallback/romstage | | | | | bootblock | | | | \-------------------/ | | \------------------------/ - flash 末尾其中fallback/payload就是最終要執(zhí)行的 payload 文件。CBFS 中與 payload 相關的文件類型見 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 二進制在構建時由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從不重定位固定加載在指定的地址地址不可用則無法引導。二、FIT面向 Linux 的扁平鏡像樹格式uImage.FIT 是 U-Boot 社區(qū)為 uImage payload 開發(fā)的新格式目前也是 coreboot 在 aarch32、aarch64、RISC-V 架構上引導 Linux 的推薦方式之一。它的核心思想是把內(nèi)核、initrd、設備樹FDT和啟動配置打包進一個統(tǒng)一的容器由 coreboot 在引導時解析、選擇合適的配置并逐項解壓、落位。支持的架構FIT 解析器需要架構級支持官方文檔明確列出了三個支持架構其余架構如 x86不支持aarch32aarch64riscv對應源碼架構架構相關源碼內(nèi)核格式要求aarch32src/arch/arm/fit_payload.cImage格式 FDTaarch64src/arch/arm64/fit_payload.cImage格式 FDTRISC-Vsrc/arch/riscv/fit_payload.cImage格式 FDT三個架構有一個共同點內(nèi)核必須是Image格式即 ARM/RISC-V 內(nèi)核的扁平鏡像格式而非壓縮的 zImage并且都必須攜帶設備樹fdt才能引導。從源碼看RISC-V 側src/arch/riscv/fit_payload.c甚至會在缺失 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 或配置。引導時根據(jù)匹配的配置從眾多分區(qū)中挑出一個內(nèi)核和一個 initrd。分區(qū)必須按以下名稱命名FIT 解析器才能找到它們見 fit.mdkernelfdtramdisk在源碼層面src/lib/fit.c的config_node()正是按屬性名查找這些分區(qū)配置節(jié)點中的kernel、fdt、ramdisk屬性分別通過find_image()關聯(lián)到/images下的同名節(jié)點。此外fdt屬性還支持通過空格分隔的多個名稱指定FDT overlay 鏈find_image_with_overlays()coreboot 會把 overlay 依次應用到基礎 FDT 上見 src/lib/fit_payload.c 的list_for_each(chain, config-overlays, ...)循環(huán)。三、配置選擇與 Compat 字符串匹配機制FIT 的核心價值在于一份鏡像、多種配置同一個 uImage 里可以存放面向多個板卡的 FDT/內(nèi)核組合引導時按 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()返回無效值對應那一條 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負責真正裝載解包 FDT、應用 overlay 與 fixup、把 coreboot 表/CBMEM 信息add_cb_fdt_data()寫入設備樹firmware/coreboot節(jié)點、根據(jù)CONFIG_LINUX_COMMAND_LINE寫入chosen/bootargs、調(diào)用架構相關的fit_payload_arch()擺放內(nèi)核/FDT/initrd最后通過extract()解壓并跳轉(zhuǎn)。四、支持的壓縮算法與 CBFS 集成約束關于壓縮官方文檔有一項重要約束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。五、各架構的裝載細節(jié)內(nèi)核、FDT、initrd 如何落位fit_payload_arch()是架構相關代碼的唯一入口聲明于 src/include/fit.h負責把內(nèi)核、FDT、initrd 擺放到內(nèi)存中合適的可用 RAM 區(qū)域并設置入口點。各架構的算法均由bootmem_walk()遍歷 bootmem 映射中的可用 RAM 完成擺放結果同時用bootmem_add_range(..., BM_MEM_PAYLOAD)標記為預留避免后續(xù)分配沖突。aarch64src/arch/arm64/fit_payload.c 的實現(xiàn)最精細先做部分解壓讀取內(nèi)核 Image 頭decompress_kernel_header()校驗魔數(shù)0x644d5241ARM64_IMAGE_MAGIC并獲取text_offset與image_size內(nèi)核的擺放遵循 ARM64 規(guī)范放在距 2 MiB 對齊基址偏移text_offset處若內(nèi)核頭未設置image_size則按文檔約定回退為text_offset 0x80000并在內(nèi)核后預留最多MAX_KERNEL_SIZE64 MiB自由空間get_kernel_size()內(nèi)核入口通過prog_set_entry(payload, (void *)kernel-offset, arg)設置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 地址。結合 src/arch/riscv/boot.c 可以看到RISC-V 上 payload 與 coreboot 表的交接方式也與眾不同coreboot 會把 coreboot 表指針以coreboot-table屬性嵌入 FDT 的/chosen節(jié)點且調(diào)用約定在 HARTID、FDT 之后coreboot 表作為第三個參數(shù)傳入這與 CBFS 文檔中關于 SELF 調(diào)用約定的特例說明一致。六、構建 FIT 鏡像從 ITS 到 uImageFIT 鏡像必須通過 U-Boot 的mkimage工具構建。官方文檔 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; /* 目標架構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ù)據(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—— 設備樹二進制initramfs.cpio.xz—— 壓縮的 initramfsImage.lzma—— LZMA 壓縮的 ARM64/ARM/RISC-V 內(nèi)核 Image然后執(zhí)行mkimage -f config.its uImage生成的uImage中initramfs.cpio.xz會在引導后由 Linux 內(nèi)核負責解壓Image.lzma由 coreboot 的 FIT 加載器extract()中的ulzman解壓target.dtb以未壓縮形式隨鏡像交付。最終把uImage作為 FIT payload 加入 CBFS 即可CBFS 文件類型為FIT_PAYLOAD0x21。七、接入 coreboot 構建系統(tǒng)Kconfig 配置要點從 payloads/Kconfig 可以看到 FIT payload 的配置入口PAYLOAD_FIT布爾選項 A FIT payload選中后自動select PAYLOAD_FIT_SUPPORTPAYLOAD_FILE指定 payload 文件路徑當PAYLOAD_FIT時默認值為uImage壓縮默認值FIT 支持時默認COMPRESSED_PAYLOAD_NONE與FIT 鏡像必須以未壓縮形式放入 CBFS的約束呼應非 FIT 時默認COMPRESSED_PAYLOAD_LZMA。構建時相關文件按架構納入編譯例如 src/arch/arm64/Makefile.mk 中的ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) fit_payload.c即只有開啟 FIT 支持時才把fit_payload.c編入 ramstage。RISC-V 側src/arch/riscv/Makefile.mk則無條件編入。引導時各架構通過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)試與排查建議結合源碼中的日志輸出printk排查 FIT 引導問題時可關注以下節(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ū)。總結coreboot 的 payload 機制以 SELF 為原生格式同時為 aarch32、aarch64、RISC-V 架構提供了完善的 uImage.FIT 支持FIT 解析器src/lib/fit.c負責解包鏡像并依據(jù) compat 字符串或 default 配置選定引導配置架構相關的 fit_payload.c 負責按各架構規(guī)范把內(nèi)核、FDT、initrd 擺放到安全的可用內(nèi)存最終跳轉(zhuǎn)內(nèi)核。實踐中只需按本文第六節(jié)的 ITS 模板準備Image、target.dtb、initramfs.cpio.xz用mkimage -f config.its uImage生成鏡像并通過PAYLOAD_FIT配置接入構建即可完成一個由 coreboot 直接引導 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點擊查看免費下載相關推薦coreboot 的 Flattened uImage TreeFITPayload 引導機制與 uImage 構建實戰(zhàn)指南coreboot 的 Flattened uImage TreeFITPayload 引導機制與 uImage 構建實戰(zhàn)指南 本指南以倉庫內(nèi) Documen固件嵌入式操作系統(tǒng)驅(qū)動開發(fā)coreboot 支持 vbootVerified Boot的設備清單與啟用機制深度解析coreboot 支持 vbootVerified Boot的設備清單與啟用機制深度解析 導讀 本文面向 coreboot 開發(fā)者與固件安全研究人員系統(tǒng)梳固件嵌入式操作系統(tǒng)驅(qū)動開發(fā)Atmosphere重啟機制全解析warmboot payload與冷啟動流程Atmosphere重啟機制全解析warmboot payload與冷啟動流程 概述 Atmosphere作為Nintendo Switch的定制固件其重啟固件操作系統(tǒng)嵌入式系統(tǒng)編程上一篇mtkclient項目Realme C3設備Bootloop問題分析與解決指南下一篇Web Audio API實戰(zhàn)PitchDetect中的音頻流處理與分析技術創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考