- 固件
- 嵌入式
- 操作系统
- 驱动开发
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
coreboot 镜像中通常包含来自众多第三方项目的代码——编译进镜像的开源组件、借用的源码片段,以及 FSP、ME、microcode、payload 等二进制文件。util/attribution是 coreboot 官方提供的构建期工具,负责根据本次构建实际启用的配置,自动生成一份人类可读的第三方归属/声明(notices)文件,并以名为attribution的 raw 文件存进 CBFS。读完本文,你将掌握:如何启用该功能、它如何从CONFIG_*选项推导出声明清单、三个分类 section 的语义、attribution.list清单格式与gen_attribution.sh渲染器的实现原理,以及如何用cbfstool从最终镜像中取回并核验这份文件。
功能定位:人类可读的声明文件,与 SBOM 互补
coreboot 还提供另一项与之独立的软件物料清单功能——SBOM(Software Bill of Materials,见 Documentation/sbom/sbom.md)。SBOM 由goswid工具生成,输出的是机器可读的 uSWID(uSWID 是 CoSWID 的容器格式,CoSWID 以 CBOR 二进制编码,见 src/sbom/Kconfig)文档,适合自动化合规审计、依赖关系分析等场景。而util/attribution生成的是纯文本 notices 文件,专门给人阅读。两者相互独立,可以只启用其一、同时启用,也可以都不启用。
attribution文件的内容直接来源于当前构建启用的 Kconfig 配置,因此它反映的是"这一个"镜像里实际包含的东西,而不是一个笼统的全项目声明。从源码结构看,这正是它最核心的设计:声明清单与编译清单同源同门,配置变了,声明文件也会随之重新生成,避免出现"列了没编进去"或"编了没列上"的失真。
工作原理:配置选项 → 清单 → 渲染 → CBFS
整个生成链路由三个文件协作完成,它们都位于 util/attribution:
| 文件 | 职责 |
|---|---|
Makefile.mk | 依据启用的CONFIG_*选项挑选本次构建涉及的"键"(key),决定渲染哪些条目 |
attribution.list | 数据清单:一行一个项目,管分隔的元数据(名称、许可证、上游 URL、版权行、分类) |
gen_attribution.sh | POSIX sh 渲染器,把清单中被选中的行渲染成可读文本块 |
Makefile.mk顶部的注释把分工概括得很清楚:"make 用与门控源码相同的CONFIG_*变量决定哪些项目属于本次构建,gen_attribution.sh再从attribution.list渲染被选中键的摘要块。" 也就是说,绝大多数条目的门控符号,就是门控该项目源码编译的那个 Kconfig 符号——一处配置,两处生效,天然保持同步。
构建流程最终被挂在主构建系统中:根目录 Makefile.mk 第 149 行通过subdirs-$(CONFIG_INCLUDE_ATTRIBUTION_FILE) += util/attribution把该目录纳入构建,因此只有启用对应配置时,这个子目录才会被解析和构建。
启用功能:一个 Kconfig 选项
在 src/Kconfig 中定义了开关:
config INCLUDE_ATTRIBUTION_FILE bool "Include a third-party attribution/notices file into the ROM image" help Generate a human-readable text file crediting the third-party projects whose code is compiled into this coreboot image, and store it in the (CBFS) ROM image as 'attribution'. ... Saying Y here increases the image size by a couple of KB.启用方式:
- 在
.config/ defconfig 中写入CONFIG_INCLUDE_ATTRIBUTION_FILE=y; - 或执行
make menuconfig,在General setup → Include a third-party attribution/notices file into the ROM image菜单项中勾选。
代价是镜像体积增加数 KB(Kconfig 帮助文本与 README 均为此表述)。文件在构建期生成,并被加入COREBOOTCBFS 区域。
条目的三种分类(kind 字段)
清单中的每条记录都有一个可选的第六列kind,决定它渲染在文件哪个 section 下:
- 编译进镜像的软件(
kind为空)——从 coreboot 源码树构建出的库/组件,例如 coreboot 自身、LZMA、LZ4、zstd、xxHash、vboot、EDK II、openSIL、AGESA 等。 - 加入镜像的独立二进制(
kind = binary)——构建过程"缝合"进镜像、但并不由 coreboot 源码编译的二进制:payload(SeaBIOS、GRUB2、depthcharge 等)、厂商固件 blob(Intel FSP/ME、AMD FSP/PSP、microcode)以及单独构建的程序(ARM Trusted Firmware、OpenSBI)。 - 借用的外部项目代码(
kind = used)——coreboot 从一个"更大"的项目中借用的单个文件,而 coreboot 并不整体捆绑该项目:Linux 内核、U-Boot、depthcharge、Etherboot、ChromiumOS EC、Sortix UBSan runtime 等。
渲染器会为每个被选中条目输出一个摘要块,包含:项目名、许可证(有 SPDX 标识符的用 SPDX id,专有二进制 blob 则用自由文本,例如Intel FSP EULA (binary))、上游 URL、版权/备注行。完整许可证文本不嵌入文件,统一放在源码树的 LICENSES/ 目录下。
数据清单 attribution.list:字段格式与覆盖范围
attribution.list 是唯一需要人工维护项目元数据的地方。每行一个项目,格式为:
key | Project name | license | upstream URL | copyright/notes | kind规则要点(文件头注释明确说明):
key必须与Makefile.mk中使用的键一致;#开头行与空行被忽略;- 字段内不得使用
|字符; license字段:开源组件用 SPDX 标识符,专有 blob 用自由文本;- 第六列
kind可选,为空表示编译进镜像,binary表示独立二进制,used表示借用代码。
实际清单覆盖的项目包括(节选,均为仓库内已确认的行):
- 编译进镜像:coreboot(GPL-2.0-only)、LZMA(LGPL-2.1-or-later OR CPL-1.0)、LZ4(BSD-2-Clause)、zstd(BSD-3-Clause OR GPL-2.0-only)、xxHash(BSD-2-Clause)、Wuffs(Apache-2.0 OR MIT)、x86emu/YABEL(BSD-3-Clause)、Google Sans Flex 字体(OFL-1.1)、vboot(BSD-3-Clause)、GNAT Ada runtime(GPL-3.0-or-later WITH GCC-exception-3.1)、libhwbase/libgfxinit(GPL-2.0-only)、EDK II(BSD-2-Clause-Patent)、openSIL(MIT)、AGESA(BSD-3-Clause)、MediaTek DRAM 校准、Cavium BDK、TCG Storage/Opal core 等;
- 二进制:Intel FSP/ME/GBE/ACM、Intel/AMD microcode、AMD FSP/PSP、ARM Trusted Firmware、OpenSBI、VGA option ROM,以及 SeaBIOS、GRUB2、depthcharge、edk2(含 MrChromebox、Star Labs 分支)、U-Boot、LinuxBoot、FILO、iPXE、coreinfo、nvramcui、Memtest86+、coreDOOM、tint、CrabEFI、BOOTBOOT、skiboot、leanefi 等 payload;
- 借用代码:Linux kernel(console printk/vtxprintf、x86 MTRR、memmove、KASAN、ASPEED 显示驱动等)、U-Boot(src/lib/rtc.c 的 RTC 时间日期辅助、ARM SoC init)、depthcharge(src/commonlib/device_tree.c、src/commonlib/list.c、src/lib/fit.c)、Etherboot(src/drivers/net/ne2k.c)、ChromiumOS EC、Sortix UBSan runtime(ISC)。
键的挑选逻辑:Makefile.mk 的几种典型做法
Makefile.mk 中挑选键的方式体现了"与实际构建内容对齐"的几个层次:
1. 恒在项。coreboot与xxhash无条件加入。xxHash 之所以总是列出,是因为它总是被编译进镜像(源码位于 src/commonlib/bsd/xxhash.c,构建中为固定成员)。
2. 压缩解码器:扫描源列表而非镜像 Kconfig。LZMA/LZ4/zstd 三个解码器是特例:选择它们的 Kconfig 选项不止一个,Makefile.mk不去镜像这些选项,而是扫描聚合后的各阶段源列表(decompressor、bootblock、verstage、romstage、postcar、ramstage、smm、smmstub),检测对应源文件是否真的被链接进镜像:
attribution-decomp-srcs = $(foreach c,decompressor bootblock verstage romstage \ postcar ramstage smm smmstub,$($(c)-srcs)) attribution-comp-keys = \ $(if $(filter %/lzmadecode.c,$(attribution-decomp-srcs)),lzma) \ $(if $(filter %/lz4_wrapper.c,$(attribution-decomp-srcs)),lz4) \ $(if $(filter %/zstd_decompress.c,$(attribution-decomp-srcs)),zstd)注释解释了为什么必须惰性求值(=):各阶段源列表要等完整解析后才齐全,所以这个检测放到 recipe 运行时再展开。zstd 特别以zstd_decompress.c(库本体)为判定依据,而不是恒存在的zstd_wrapper.c桩——后者未被使用时会被--gc-sections丢弃,不能作为判据。源码位置对应为 src/lib/lzmadecode.c、src/commonlib/bsd/lz4_wrapper.c、src/commonlib/bsd/zstd/decompress/zstd_decompress.c。
3. 直接以门控符号为门控。多数条目形如attribution-keys-$(CONFIG_XXX) += key,例如CONFIG_UBSAN → ubsan、CONFIG_BOOTSPLASH → wuffs、CONFIG_PCI_OPTION_ROM_RUN_YABEL → x86emu、CONFIG_VBOOT → vboot。
4. 多符号 OR 用ifneq块。例如 GNAT runtime 与 libhwbase 只要CONFIG_RAMSTAGE_LIBHWBASE或CONFIG_ROMSTAGE_LIBHWBASE任一启用即列入;EDK II 头文件只要 UEFI/UDK binding 系列选项任一启用即列入;AGESA 在SOC_AMD_STONEYRIDGE或CPU_AMD_PI_00730F01启用时列入。
5. 组合条件防止误报。注释与实现都体现了对"实际有没有这个二进制"的精细判断:
- AMD microcode 必须
CONFIG_USE_AMD_BLOBS=y且CONFIG_SOC_AMD_COMMON_BLOCK_UCODE=y(后者才真正拉入 microcode,避免非 AMD 板子误报); - FSP 必须确实缝合进镜像才声明:FSP 2.0 看
CONFIG_ADD_FSP_BINARIES,FSP 1.1 看CONFIG_HAVE_FSP_BIN;再依据CONFIG_SOC_AMD_COMMON区分amd_fsp与intel_fsp; - SeaBIOS 与 GRUB2 以
CONFIG_PAYLOAD_BUILD_SEABIOS/CONFIG_PAYLOAD_BUILD_GRUB2为 canonical 门控,注释明确说明:它们可能是主 payload、次 payload 或 SeaGRUB 的一部分,PAYLOAD_BUILD_*只要实际构建就置位,而单纯检查PAYLOAD_SEABIOS会漏掉 SeaGRUB 情形。
6. 构建期才可知的信息用--extra注入。若CONFIG_EDK2_REPO_CUSTOM启用,edk2 payload 来自一个静态清单无法预先命名的自定义仓库,Makefile.mk会在构建期取出实际的CONFIG_EDK2_REPOSITORY与CONFIG_EDK2_TAG_OR_REV,拼成一行追加到临时 extra 文件:
printf '%s\n' '+|edk2 UEFI payload - custom repository|BSD-2-Clause-Patent|$(attribution-edk2-custom-url)|Built from $(attribution-edk2-custom-rev); based on TianoCore EDK II|binary' >> $@.extra渲染器 gen_attribution.sh:实现细节
gen_attribution.sh 是纯 POSIX sh 脚本,调用方式为:
$ gen_attribution.sh [--extra <file>] <manifest> <key> [<key> ...]关键行为:
--extra可选,指向一个与清单同格式的文件,其中的行无条件输出(不按 key 门控),用于注入构建期才知道的信息;脚本对--extra作为最后一个参数的情形做了防御(set -u下避免消费未绑定变量);- 脚本把所有启用的 key 拼成一个
" key1 key2 ... "查找集合,用 shell case 模式匹配逐行比对; - 解析清单时按
|分割六个字段,跳过空行与#注释行;|| [ -n "${key}" ]的处理确保最后一行没有结尾换行符时也不会被read静默丢弃; - 条目按清单中的顺序输出(而非按参数顺序),保证输出稳定,不受 make 对 key 排序的影响;
- 三个 section 的标题依次为:
This coreboot components includes software from the following projects:(编译进镜像)Code from the following projects has been used in coreboot:(借用代码,仅当存在此类条目时才输出标题)The following payloads and binaries are added to the image, but are not compiled directly against coreboot source:(独立二进制,同样按需输出标题)
- 文件末尾固定输出
Full license texts are provided with the coreboot source under LICENSES/.。
渲染器对清单中没有对应行的 key静默忽略——这是刻意设计(README 与 Makefile 注释均有说明),意味着attribution.list与Makefile.mk可以独立更新,不必担心临时的不一致导致构建失败。
构建与 CBFS 注册
Makefile.mk 末段的生成规则值得注意:
$(attribution-build-dir)/attribution.txt: $(attribution-tool-dir)/attribution.list \ $(attribution-tool-dir)/gen_attribution.sh \ $(DOTCONFIG)规则显式依赖$(DOTCONFIG),注释给出了原因:选中的 key 完全来自CONFIG_*选项,而不是其它先决条件;没有这个依赖,重新配置后文件就会过期。recipe 先清空 extra 文件、按需写入自定义 edk2 行,再调用渲染器把结果写到临时文件后mv覆盖,避免生成中途损坏。
CBFS 注册部分:
cbfs-files-y += attribution attribution-file := $(attribution-build-dir)/attribution.txt attribution-type := raw attribution-compression := $(CBFS_COMPRESS_FLAG)注意两点:
- 由于该 Makefile 只在
CONFIG_INCLUDE_ATTRIBUTION_FILE置位时被解析(subdirs-门控),所以这里直接-y即可,无需再次判断; - 压缩方式复用构建自身的
CBFS_COMPRESS_FLAG(在根 Makefile.mk 中根据配置取none/LZMA/ZSTD/LZ4),而不是强制某种压缩;注释说明该文件只通过cbfstool离线读取,压缩纯粹是主机侧体积取舍,但保持与镜像一致。
从镜像中读取与核验
构建完成后,可用cbfstool把文件提取出来(extract是 cbfstool 的标准命令,见 util/cbfstool/cbfstool.c 的用法说明):
$ cbfstool build/coreboot.rom extract -n attribution -f attribution.txt $ cat attribution.txt coreboot third-party attribution / notices This firmware image includes software from the following projects: * coreboot License: GPL-2.0-only Upstream: https://coreboot.org ...也可以在 CBFS 清单中直接看到该条目:
$ cbfstool build/coreboot.rom print | grep attribution attribution 0x40d80 raw 558 LZMA (1044 decompressed)上面的示例还顺带印证了两个机制:类型为raw、压缩为 LZMA(与CBFS_COMPRESS_FLAG复用逻辑一致),以及压缩解码器检测——镜像中attribution采用 LZMA 压缩,恰恰意味着 LZMA 解码器确实被链接了,因而lzma条目会出现在文件里。
添加一个新项目:两步操作
README 给出了明确的扩展步骤,结合实现可以归纳为:
- 在 attribution.list 新增一行,使用新的
key,并按实际情况设置第六列kind:缝合进镜像的 payload/blob 用binary,借用的单个文件用used,编译进 coreboot 的源码留空。 - 在 Makefile.mk 增加门控行:
attribution-keys-$(CONFIG_<symbol>) += <key>;若由多个符号的 OR 决定,则改用ifneq (...)块。门控符号应尽量与门控该项目源码编译的符号一致。
两个文件允许不同步——渲染器会静默忽略没有清单行的 key,也自然跳过未被选中的行,因此可以分别合入、独立演进。
小结与使用建议
util/attribution用一套轻量而精确的机制解决了固件合规声明中的一个实际问题:声明必须与构建内容一一对应。它的经验值得借鉴——用"门控源码的同一个符号"来门控声明、用"扫描实际链接的源文件"来处理难以镜像的间接选择、用"惰性求值 + 构建期注入"来覆盖运行时才可知的信息。对使用 coreboot 的开发者而言:合规审计时启用CONFIG_INCLUDE_ATTRIBUTION_FILE并提取attribution文件即可得到与镜像完全对应的人类可读声明;需要机器可读的物料清单时,可另行启用 SBOM(CONFIG_SBOM)与之互补。
- 固件
- 嵌入式
- 操作系统
- 驱动开发
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
相关推荐
GitLens第三方声明文件详解:ThirdPartyNotices.txt完整指南
GitLens第三方声明文件详解:ThirdPartyNotices.txt完整指南 GitLens作为Visual Studio Code中最强大的Git增强
开发工具版本控制coreboot 构建系统详解:从 Makefile.mk 的 class 机制到 CBFS/FMAP 镜像组装
coreboot 构建系统详解:从 Makefile.mk 的 class 机制到 CBFS/FMAP 镜像组装 coreboot 的构建系统以 GNU mak
固件嵌入式操作系统驱动开发.NET Runtime 安装包第三方声明(THIRD-PARTY-NOTICES)的生成与分发机制详解
.NET Runtime 安装包第三方声明(THIRD PARTY NOTICES)的生成与分发机制详解 本文围绕 dotnet/runtime 仓库中 src
语言运行时标准库JIT编译编译器
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考