328 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			328 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| .. 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
 | |
| has to be terminated by semi-colon (``;``) or newline (``\n``).
 | |
| For array value, array entries are separated by comma (``,``). ::
 | |
| 
 | |
|   KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
 | |
| 
 | |
| Unlike the kernel command line syntax, spaces are OK around the comma and ``=``.
 | |
| 
 | |
| 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 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 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 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
 | |
| 
 |