| .. SPDX-License-Identifier: GPL-2.0 | |
| .. _bootconfig: | |
| ================== | |
| Boot Configuration | |
| ================== | |
| :Author: Masami Hiramatsu <mhiramat@kernel.org> | |
| Overview | |
| ======== | |
| The boot configuration expands the current kernel command line to support | |
| additional key-value data when booting the kernel in an efficient way. | |
| This allows administrators to pass a structured-Key config file. | |
| Config File Syntax | |
| ================== | |
| The boot config syntax is a simple structured key-value. Each key consists | |
| of dot-connected-words, and key and value are connected by ``=``. The value | |
| string has to be terminated by the following delimiters described below. | |
| Each key word must contain only alphabets, numbers, dash (``-``) or underscore | |
| (``_``). And each value only contains printable characters or spaces except | |
| for delimiters such as semi-colon (``;``), new-line (``\n``), comma (``,``), | |
| hash (``#``) and closing brace (``}``). | |
| If the ``=`` is followed by whitespace up to one of these delimiters, the | |
| key is assigned an empty value. | |
| For arrays, the array values are comma (``,``) separated, and comments and | |
| line breaks with newline (``\n``) are allowed between array values for | |
| readability. Thus the first entry of the array must be on the same line as | |
| the key.:: | |
| KEY[.WORD[...]] = VALUE[, VALUE2[...]][;] | |
| Unlike the kernel command line syntax, white spaces (including tabs) are | |
| ignored around the comma and ``=``. | |
| If you want to use those delimiters in a value, you can use either double- | |
| quotes (``"VALUE"``) or single-quotes (``'VALUE'``) to quote it. Note that | |
| you can not escape these quotes. | |
| There can be a key which doesn't have value or has an empty value. Those keys | |
| are used for checking if the key exists or not (like a boolean). | |
| Key-Value Syntax | |
| ---------------- | |
| The boot config file syntax allows user to merge partially same word keys | |
| by brace. For example:: | |
| foo.bar.baz = value1 | |
| foo.bar.qux.quux = value2 | |
| These can be written also in:: | |
| foo.bar { | |
| baz = value1 | |
| qux.quux = value2 | |
| } | |
| Or more shorter, written as following:: | |
| foo.bar { baz = value1; qux.quux = value2 } | |
| In both styles, same key words are automatically merged when parsing it | |
| at boot time. So you can append similar trees or key-values. | |
| Same-key Values | |
| --------------- | |
| It is prohibited that two or more values or arrays share a same-key. | |
| For example,:: | |
| foo = bar, baz | |
| foo = qux # !ERROR! we can not re-define same key | |
| If you want to update the value, you must use the override operator | |
| ``:=`` explicitly. For example:: | |
| foo = bar, baz | |
| foo := qux | |
| then, the ``qux`` is assigned to ``foo`` key. This is useful for | |
| overriding the default value by adding (partial) custom bootconfigs | |
| without parsing the default bootconfig. | |
| If you want to append the value to existing key as an array member, | |
| you can use ``+=`` operator. For example:: | |
| foo = bar, baz | |
| foo += qux | |
| In this case, the key ``foo`` has ``bar``, ``baz`` and ``qux``. | |
| Moreover, sub-keys and a value can coexist under a parent key. | |
| For example, following config is allowed.:: | |
| foo = value1 | |
| foo.bar = value2 | |
| foo := value3 # This will update foo's value. | |
| Note, since there is no syntax to put a raw value directly under a | |
| structured key, you have to define it outside of the brace. For example:: | |
| foo { | |
| bar = value1 | |
| bar { | |
| baz = value2 | |
| qux = value3 | |
| } | |
| } | |
| Also, the order of the value node under a key is fixed. If there | |
| are a value and subkeys, the value is always the first child node | |
| of the key. Thus if user specifies subkeys first, e.g.:: | |
| foo.bar = value1 | |
| foo = value2 | |
| In the program (and /proc/bootconfig), it will be shown as below:: | |
| foo = value2 | |
| foo.bar = value1 | |
| Comments | |
| -------- | |
| The config syntax accepts shell-script style comments. The comments starting | |
| with hash ("#") until newline ("\n") will be ignored. | |
| :: | |
| # comment line | |
| foo = value # value is set to foo. | |
| bar = 1, # 1st element | |
| 2, # 2nd element | |
| 3 # 3rd element | |
| This is parsed as below:: | |
| foo = value | |
| bar = 1, 2, 3 | |
| Note that you can NOT put a comment or a newline between value and delimiter | |
| (``,`` or ``;``). This means following config has a syntax error :: | |
| key = 1 # comment | |
| ,2 | |
| /proc/bootconfig | |
| ================ | |
| /proc/bootconfig is a user-space interface of the boot config. | |
| Unlike /proc/cmdline, this file shows the key-value style list. | |
| Each key-value pair is shown in each line with following style:: | |
| KEY[.WORDS...] = "[VALUE]"[,"VALUE2"...] | |
| Boot Kernel With a Boot Config | |
| ============================== | |
| There are two options to boot the kernel with bootconfig: attaching the | |
| bootconfig to the initrd image or embedding it in the kernel itself. | |
| Attaching a Boot Config to Initrd | |
| --------------------------------- | |
| Since the boot configuration file is loaded with initrd by default, | |
| it will be added to the end of the initrd (initramfs) image file with | |
| padding, size, checksum and 12-byte magic word as below. | |
| [initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n] | |
| The size and checksum fields are unsigned 32bit little endian value. | |
| When the boot configuration is added to the initrd image, the total | |
| file size is aligned to 4 bytes. To fill the gap, null characters | |
| (``\0``) will be added. Thus the ``size`` is the length of the bootconfig | |
| file + padding bytes. | |
| The Linux kernel decodes the last part of the initrd image in memory to | |
| get the boot configuration data. | |
| Because of this "piggyback" method, there is no need to change or | |
| update the boot loader and the kernel image itself as long as the boot | |
| loader passes the correct initrd file size. If by any chance, the boot | |
| loader passes a longer size, the kernel fails to find the bootconfig data. | |
| To do this operation, Linux kernel provides ``bootconfig`` command under | |
| tools/bootconfig, which allows admin to apply or delete the config file | |
| to/from initrd image. You can build it by the following command:: | |
| # make -C tools/bootconfig | |
| To add your boot config file to initrd image, run bootconfig as below | |
| (Old data is removed automatically if exists):: | |
| # tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z | |
| To remove the config from the image, you can use -d option as below:: | |
| # tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z | |
| Then add "bootconfig" on the normal kernel command line to tell the | |
| kernel to look for the bootconfig at the end of the initrd file. | |
| Alternatively, build your kernel with the ``CONFIG_BOOT_CONFIG_FORCE`` | |
| Kconfig option selected. | |
| Embedding a Boot Config into Kernel | |
| ----------------------------------- | |
| If you can not use initrd, you can also embed the bootconfig file in the | |
| kernel by Kconfig options. In this case, you need to recompile the kernel | |
| with the following configs:: | |
| CONFIG_BOOT_CONFIG_EMBED=y | |
| CONFIG_BOOT_CONFIG_EMBED_FILE="/PATH/TO/BOOTCONFIG/FILE" | |
| ``CONFIG_BOOT_CONFIG_EMBED_FILE`` requires an absolute path or a relative | |
| path to the bootconfig file from source tree or object tree. | |
| The kernel will embed it as the default bootconfig. | |
| Just as when attaching the bootconfig to the initrd, you need ``bootconfig`` | |
| option on the kernel command line to enable the embedded bootconfig, or, | |
| alternatively, build your kernel with the ``CONFIG_BOOT_CONFIG_FORCE`` | |
| Kconfig option selected. | |
| Note that even if you set this option, you can override the embedded | |
| bootconfig by another bootconfig which attached to the initrd. | |
| Kernel parameters via Boot Config | |
| ================================= | |
| In addition to the kernel command line, the boot config can be used for | |
| passing the kernel parameters. All the key-value pairs under ``kernel`` | |
| key will be passed to kernel cmdline directly. Moreover, the key-value | |
| pairs under ``init`` will be passed to init process via the cmdline. | |
| The parameters are concatenated with user-given kernel cmdline string | |
| as the following order, so that the command line parameter can override | |
| bootconfig parameters (this depends on how the subsystem handles parameters | |
| but in general, earlier parameter will be overwritten by later one.):: | |
| [bootconfig params][cmdline params] -- [bootconfig init params][cmdline init params] | |
| Here is an example of the bootconfig file for kernel/init parameters.:: | |
| kernel { | |
| root = 01234567-89ab-cdef-0123-456789abcd | |
| } | |
| init { | |
| splash | |
| } | |
| This will be copied into the kernel cmdline string as the following:: | |
| root="01234567-89ab-cdef-0123-456789abcd" -- splash | |
| If user gives some other command line like,:: | |
| ro bootconfig -- quiet | |
| The final kernel cmdline will be the following:: | |
| root="01234567-89ab-cdef-0123-456789abcd" ro bootconfig -- splash quiet | |
| Config File Limitation | |
| ====================== | |
| Currently the maximum config size is 32KB and the total key-words (not | |
| key-value entries) must be under 1024 nodes. | |
| Note: this is not the number of entries but nodes, an entry must consume | |
| more than 2 nodes (a key-word and a value). So theoretically, it will be | |
| up to 512 key-value pairs. If keys contains 3 words in average, it can | |
| contain 256 key-value pairs. In most cases, the number of config items | |
| will be under 100 entries and smaller than 8KB, so it would be enough. | |
| If the node number exceeds 1024, parser returns an error even if the file | |
| size is smaller than 32KB. (Note that this maximum size is not including | |
| the padding null characters.) | |
| Anyway, since bootconfig command verifies it when appending a boot config | |
| to initrd image, user can notice it before boot. | |
| Bootconfig APIs | |
| =============== | |
| User can query or loop on key-value pairs, also it is possible to find | |
| a root (prefix) key node and find key-values under that node. | |
| If you have a key string, you can query the value directly with the key | |
| using xbc_find_value(). If you want to know what keys exist in the boot | |
| config, you can use xbc_for_each_key_value() to iterate key-value pairs. | |
| Note that you need to use xbc_array_for_each_value() for accessing | |
| each array's value, e.g.:: | |
| vnode = NULL; | |
| xbc_find_value("key.word", &vnode); | |
| if (vnode && xbc_node_is_array(vnode)) | |
| xbc_array_for_each_value(vnode, value) { | |
| printk("%s ", value); | |
| } | |
| If you want to focus on keys which have a prefix string, you can use | |
| xbc_find_node() to find a node by the prefix string, and iterate | |
| keys under the prefix node with xbc_node_for_each_key_value(). | |
| But the most typical usage is to get the named value under prefix | |
| or get the named array under prefix as below:: | |
| root = xbc_find_node("key.prefix"); | |
| value = xbc_node_find_value(root, "option", &vnode); | |
| ... | |
| xbc_node_for_each_array_value(root, "array-option", value, anode) { | |
| ... | |
| } | |
| This accesses a value of "key.prefix.option" and an array of | |
| "key.prefix.array-option". | |
| Locking is not needed, since after initialization, the config becomes | |
| read-only. All data and keys must be copied if you need to modify it. | |
| Functions and structures | |
| ======================== | |
| .. kernel-doc:: include/linux/bootconfig.h | |
| .. kernel-doc:: lib/bootconfig.c | |