162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci.. include:: ../disclaimer-zh_CN.rst 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci:Original: Documentation/admin-guide/bootconfig.rst 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci======== 1062306a36Sopenharmony_ci引导配置 1162306a36Sopenharmony_ci======== 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci:作者: Masami Hiramatsu <mhiramat@kernel.org> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci概述 1662306a36Sopenharmony_ci==== 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci引导配置扩展了现有的内核命令行,以一种更有效率的方式在引导内核时进一步支持 1962306a36Sopenharmony_ci键值数据。这允许管理员传递一份结构化关键字的配置文件。 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci配置文件语法 2262306a36Sopenharmony_ci============ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci引导配置文件的语法采用非常简单的键值结构。每个关键字由点连接的单词组成,键 2562306a36Sopenharmony_ci和值由 ``=`` 连接。值以分号( ``;`` )或换行符( ``\n`` )结尾。数组值中每 2662306a36Sopenharmony_ci个元素由逗号( ``,`` )分隔。:: 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci KEY[.WORD[...]] = VALUE[, VALUE2[...]][;] 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci与内核命令行语法不同,逗号和 ``=`` 周围允许有空格。 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci关键字只允许包含字母、数字、连字符( ``-`` )和下划线( ``_`` )。值可包含 3362306a36Sopenharmony_ci可打印字符和空格,但分号( ``;`` )、换行符( ``\n`` )、逗号( ``,`` )、 3462306a36Sopenharmony_ci井号( ``#`` )和右大括号( ``}`` )等分隔符除外。 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci如果你需要在值中使用这些分隔符,可以用双引号( ``"VALUE"`` )或单引号 3762306a36Sopenharmony_ci( ``'VALUE'`` )括起来。注意,引号无法转义。 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci键的值可以为空或不存在。这些键用于检查该键是否存在(类似布尔值)。 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci键值语法 4262306a36Sopenharmony_ci-------- 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci引导配置文件语法允许用户通过大括号合并键名部分相同的关键字。例如:: 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci foo.bar.baz = value1 4762306a36Sopenharmony_ci foo.bar.qux.quux = value2 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci也可以写成:: 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci foo.bar { 5262306a36Sopenharmony_ci baz = value1 5362306a36Sopenharmony_ci qux.quux = value2 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci或者更紧凑一些,写成:: 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci foo.bar { baz = value1; qux.quux = value2 } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci在这两种样式中,引导解析时相同的关键字都会自动合并。因此可以追加类似的树或 6162306a36Sopenharmony_ci键值。 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci相同关键字的值 6462306a36Sopenharmony_ci-------------- 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci禁止两个或多个值或数组共享同一个关键字。例如:: 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci foo = bar, baz 6962306a36Sopenharmony_ci foo = qux # !错误! 我们不可以重定义相同的关键字 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci如果你想要更新值,必须显式使用覆盖操作符 ``:=`` 。例如:: 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci foo = bar, baz 7462306a36Sopenharmony_ci foo := qux 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci这样 ``foo`` 关键字的值就变成了 ``qux`` 。这对于通过添加(部分)自定义引导 7762306a36Sopenharmony_ci配置来覆盖默认值非常有用,免于解析默认引导配置。 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci如果你想对现有关键字追加值作为数组成员,可以使用 ``+=`` 操作符。例如:: 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci foo = bar, baz 8262306a36Sopenharmony_ci foo += qux 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci这样, ``foo`` 关键字就同时拥有了 ``bar`` , ``baz`` 和 ``qux`` 。 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci此外,父关键字下可同时存在值和子关键字。 8762306a36Sopenharmony_ci例如,下列配置是可行的。:: 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci foo = value1 9062306a36Sopenharmony_ci foo.bar = value2 9162306a36Sopenharmony_ci foo := value3 # 这会更新foo的值。 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci注意,裸值不能直接放进结构化关键字中,必须在大括号外定义它。例如:: 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci foo { 9662306a36Sopenharmony_ci bar = value1 9762306a36Sopenharmony_ci bar { 9862306a36Sopenharmony_ci baz = value2 9962306a36Sopenharmony_ci qux = value3 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci同时,关键字下值节点的顺序是固定的。如果值和子关键字同时存在,值永远是该关 10462306a36Sopenharmony_ci键字的第一个子节点。因此如果用户先指定子关键字,如:: 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci foo.bar = value1 10762306a36Sopenharmony_ci foo = value2 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci则在程序(和/proc/bootconfig)中,它会按如下显示:: 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci foo = value2 11262306a36Sopenharmony_ci foo.bar = value1 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci注释 11562306a36Sopenharmony_ci---- 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci配置语法接受shell脚本风格的注释。注释以井号( ``#`` )开始,到换行符 11862306a36Sopenharmony_ci( ``\n`` )结束。 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci:: 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci # comment line 12362306a36Sopenharmony_ci foo = value # value is set to foo. 12462306a36Sopenharmony_ci bar = 1, # 1st element 12562306a36Sopenharmony_ci 2, # 2nd element 12662306a36Sopenharmony_ci 3 # 3rd element 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci会被解析为:: 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci foo = value 13162306a36Sopenharmony_ci bar = 1, 2, 3 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci注意你不能把注释放在值和分隔符( ``,`` 或 ``;`` )之间。如下配置语法是错误的:: 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci key = 1 # comment 13662306a36Sopenharmony_ci ,2 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/proc/bootconfig 14062306a36Sopenharmony_ci================ 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/proc/bootconfig是引导配置的用户空间接口。与/proc/cmdline不同,此文件内容以 14362306a36Sopenharmony_ci键值列表样式显示。 14462306a36Sopenharmony_ci每个键值对一行,样式如下:: 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci KEY[.WORDS...] = "[VALUE]"[,"VALUE2"...] 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci用引导配置引导内核 15062306a36Sopenharmony_ci================== 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci用引导配置引导内核有两种方法:将引导配置附加到initrd镜像或直接嵌入内核中。 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci*initrd: initial RAM disk,初始内存磁盘* 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci将引导配置附加到initrd 15762306a36Sopenharmony_ci---------------------- 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci由于默认情况下引导配置文件是用initrd加载的,因此它将被添加到initrd(initramfs) 16062306a36Sopenharmony_ci镜像文件的末尾,其中包含填充、大小、校验值和12字节幻数,如下所示:: 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci [initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n] 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci大小和校验值为小端序存放的32位无符号值。 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci当引导配置被加到initrd镜像时,整个文件大小会对齐到4字节。空字符( ``\0`` ) 16762306a36Sopenharmony_ci会填补对齐空隙。因此 ``size`` 就是引导配置文件的长度+填充的字节。 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ciLinux内核在内存中解码initrd镜像的最后部分以获取引导配置数据。由于这种“背负式” 17062306a36Sopenharmony_ci的方法,只要引导加载器传递了正确的initrd文件大小,就无需更改或更新引导加载器 17162306a36Sopenharmony_ci和内核镜像本身。如果引导加载器意外传递了更长的大小,内核将无法找到引导配置数 17262306a36Sopenharmony_ci据。 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciLinux内核在tools/bootconfig下提供了 ``bootconfig`` 命令来完成此操作,管理员 17562306a36Sopenharmony_ci可以用它从initrd镜像中删除或追加配置文件。你可以用以下命令来构建它:: 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci # make -C tools/bootconfig 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci要向initrd镜像添加你的引导配置文件,请按如下命令操作(旧数据会自动移除):: 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci # tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci要从镜像中移除配置,可以使用-d选项:: 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci # tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci然后在内核命令行上添加 ``bootconfig`` 告诉内核去initrd文件末尾寻找内核配置。 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci将引导配置嵌入内核 19062306a36Sopenharmony_ci------------------ 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci如果你不能使用initrd,也可以通过Kconfig选项将引导配置文件嵌入内核中。在此情 19362306a36Sopenharmony_ci况下,你需要用以下选项重新编译内核:: 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci CONFIG_BOOT_CONFIG_EMBED=y 19662306a36Sopenharmony_ci CONFIG_BOOT_CONFIG_EMBED_FILE="/引导配置/文件/的/路径" 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci``CONFIG_BOOT_CONFIG_EMBED_FILE`` 需要从源码树或对象树开始的引导配置文件的 19962306a36Sopenharmony_ci绝对/相对路径。内核会将其嵌入作为默认引导配置。 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci与将引导配置附加到initrd一样,你也需要在内核命令行上添加 ``bootconfig`` 告诉 20262306a36Sopenharmony_ci内核去启用内嵌的引导配置。 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci注意,即使你已经设置了此选项,仍可用附加到initrd的其他引导配置覆盖内嵌的引导 20562306a36Sopenharmony_ci配置。 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci通过引导配置传递内核参数 20862306a36Sopenharmony_ci======================== 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci除了内核命令行,引导配置也可以用于传递内核参数。所有 ``kernel`` 关键字下的键 21162306a36Sopenharmony_ci值对都将直接传递给内核命令行。此外, ``init`` 下的键值对将通过命令行传递给 21262306a36Sopenharmony_ciinit进程。参数按以下顺序与用户给定的内核命令行字符串相连,因此命令行参数可以 21362306a36Sopenharmony_ci覆盖引导配置参数(这取决于子系统如何处理参数,但通常前面的参数将被后面的参数 21462306a36Sopenharmony_ci覆盖):: 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci [bootconfig params][cmdline params] -- [bootconfig init params][cmdline init params] 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci如果引导配置文件给出的kernel/init参数是:: 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci kernel { 22162306a36Sopenharmony_ci root = 01234567-89ab-cdef-0123-456789abcd 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci init { 22462306a36Sopenharmony_ci splash 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci这将被复制到内核命令行字符串中,如下所示:: 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci root="01234567-89ab-cdef-0123-456789abcd" -- splash 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci如果用户给出的其他命令行是:: 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci ro bootconfig -- quiet 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci则最后的内核命令行如下:: 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci root="01234567-89ab-cdef-0123-456789abcd" ro bootconfig -- splash quiet 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci配置文件的限制 24162306a36Sopenharmony_ci============== 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci当前最大的配置大小是32KB,关键字总数(不是键值条目)必须少于1024个节点。 24462306a36Sopenharmony_ci注意:这不是条目数而是节点数,条目必须消耗超过2个节点(一个关键字和一个值)。 24562306a36Sopenharmony_ci所以从理论上讲最多512个键值对。如果关键字平均包含3个单词,则可有256个键值对。 24662306a36Sopenharmony_ci在大多数情况下,配置项的数量将少于100个条目,小于8KB,因此这应该足够了。如果 24762306a36Sopenharmony_ci节点数超过1024,解析器将返回错误,即使文件大小小于32KB。(请注意,此最大尺寸 24862306a36Sopenharmony_ci不包括填充的空字符。) 24962306a36Sopenharmony_ci无论如何,因为 ``bootconfig`` 命令在附加启动配置到initrd映像时会验证它,用户 25062306a36Sopenharmony_ci可以在引导之前注意到它。 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci引导配置API 25462306a36Sopenharmony_ci=========== 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci用户可以查询或遍历键值对,也可以查找(前缀)根关键字节点,并在查找该节点下的 25762306a36Sopenharmony_ci键值。 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci如果您有一个关键字字符串,则可以直接使用 xbc_find_value() 查询该键的值。如果 26062306a36Sopenharmony_ci你想知道引导配置里有哪些关键字,可以使用 xbc_for_each_key_value() 迭代键值对。 26162306a36Sopenharmony_ci请注意,您需要使用 xbc_array_for_each_value() 访问数组的值,例如:: 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci vnode = NULL; 26462306a36Sopenharmony_ci xbc_find_value("key.word", &vnode); 26562306a36Sopenharmony_ci if (vnode && xbc_node_is_array(vnode)) 26662306a36Sopenharmony_ci xbc_array_for_each_value(vnode, value) { 26762306a36Sopenharmony_ci printk("%s ", value); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci如果您想查找具有前缀字符串的键,可以使用 xbc_find_node() 通过前缀字符串查找 27162306a36Sopenharmony_ci节点,然后用 xbc_node_for_each_key_value() 迭代前缀节点下的键。 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci但最典型的用法是获取前缀下的命名值或前缀下的命名数组,例如:: 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci root = xbc_find_node("key.prefix"); 27662306a36Sopenharmony_ci value = xbc_node_find_value(root, "option", &vnode); 27762306a36Sopenharmony_ci ... 27862306a36Sopenharmony_ci xbc_node_for_each_array_value(root, "array-option", value, anode) { 27962306a36Sopenharmony_ci ... 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci这将访问值“key.prefix.option”的值和“key.prefix.array-option”的数组。 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci锁是不需要的,因为在初始化之后配置只读。如果需要修改,必须复制所有数据和关键字。 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci函数与结构体 28862306a36Sopenharmony_ci============ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci相关定义的kernel-doc参见: 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci - include/linux/bootconfig.h 29362306a36Sopenharmony_ci - lib/bootconfig.c 294