From patchwork Sun Sep 19 21:51:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1529899 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=RMkypavn; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4HCLxc6Nxgz9sX3 for ; Mon, 20 Sep 2021 07:51:48 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 78FFE8328E; Sun, 19 Sep 2021 23:51:42 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="RMkypavn"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 73BE583276; Sun, 19 Sep 2021 23:51:34 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-il1-x135.google.com (mail-il1-x135.google.com [IPv6:2607:f8b0:4864:20::135]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id D928A83281 for ; Sun, 19 Sep 2021 23:51:19 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-il1-x135.google.com with SMTP id x2so2018954ilm.2 for ; Sun, 19 Sep 2021 14:51:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=r+dNxnggqozBuPFxwqiqT/psVlkGrXmQqRyt002q/FI=; b=RMkypavnUMfBNCHkD0bDAFf0oNCkv34PeqmMtqYVk89k/NGoq3x5wTKnPQvhIMmXqx QzO6ZLuXgnPiLHqD2ByovyTPjP8sh7pi4SWeBIBW5cnRCnUMFJwE7cPbt7/Eq0FiLvn3 +1c51VEuOPCxoYO7V4TefhOXQWuOlgtCiGpiU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=r+dNxnggqozBuPFxwqiqT/psVlkGrXmQqRyt002q/FI=; b=BMO8Lhg3ALOnPDrJwG3lKv/xQ5AcU7e2S4rCulvOJA2XrtYBfSjIPut9CB/3oAPU1u UQ2ZQuVKxW7CDIjLZJ6YoSrXNYkwUMzqgPS0K6SzVUT4IVDZ7DURP1IC0IBK8yLTXzmN cB4Kit7sZocOXDpBhMcntjQp8pEnNAYWCyRO46cjYQxBuSpAebaUPhnF1cnsIUipYXNq BY3GS1drYI3WrFckm0G59o470HytL9wPbFuL9sHgpDCvrUBt8fuJ4ZwLb2iQLWXPR4rv kTR21JsWSTlJZdT8vG2SXqG7oSU2QlED8RVtwXFRUtzmby8NUhUgrg7gsDXQ0jkHo6Y4 xAqw== X-Gm-Message-State: AOAM533cwktzvyIXOCSkCen6aNLJCF4PqoNSgo313rxceLWyhjBpCRxw IUzE25+nHbNv2C+jcYG/gEJCDrznziHRDg== X-Google-Smtp-Source: ABdhPJxQqG/nornXnPEqlFqOzGV+/Iqi2sPiNaumevluHTfsp0URGKRfsUZ5hCx3zpX81oCJJeRxnQ== X-Received: by 2002:a05:6e02:12a1:: with SMTP id f1mr15111664ilr.293.1632088277289; Sun, 19 Sep 2021 14:51:17 -0700 (PDT) Received: from kiwi.bld.corp.google.com (c-67-190-101-114.hsd1.co.comcast.net. [67.190.101.114]) by smtp.gmail.com with ESMTPSA id o5sm8017581ilk.88.2021.09.19.14.51.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Sep 2021 14:51:16 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Cc: Heinrich Schuchardt , Sean Anderson , Ilias Apalodimas , Tom Rini , Mark Kettenis , Simon Glass , Marcel Ziswiler Subject: [PATCH v4 2/2] doc: Add documentation about devicetree usage Date: Sun, 19 Sep 2021 15:51:11 -0600 Message-Id: <20210919215111.3830278-3-sjg@chromium.org> X-Mailer: git-send-email 2.33.0.464.g1972c5931b-goog In-Reply-To: <20210919215111.3830278-1-sjg@chromium.org> References: <20210919215111.3830278-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean At present some of the ideas and techniques behind devicetree in U-Boot are assumed, implied or unsaid. Add some documentation to cover how devicetree is build, how it can be modified and the rules about using the various CONFIG_OF_... options. Signed-off-by: Simon Glass Reviewed-by: Marcel Ziswiler --- This patch attracted quite a bit of discussion here: https://patchwork.ozlabs.org/project/uboot/patch/20210909201033.755713-4-sjg@chromium.org/ I have not included the text suggested by François. While I agree that it would be useful to have an introduction in this space, I do not agree that we should have two devicetrees or that U-Boot should not have its own things in the devicetree, so it is not clear to me what we should actually write. The 'Devicetree Control in U-Boot' docs were recently merged and these provide some base info, for now. (no changes since v3) Changes in v3: - Clarify the 'bug' refered to at the top - Reword 'This means that there' paragraph to explain U-Boot-specific things - Move to doc/develop/devicetree now that OF_CONTROL is in the docs Changes in v2: - Fix typos per Sean (thank you!) and a few others - Add a 'Use of U-Boot /config node' section - Drop mention of dm-verity since that actually uses the kernel cmdline - Explain that OF_BOARD will still work after these changes (in 'Once this bug is fixed...' paragraph) - Expand a bit on the reason why the 'Current situation' is bad - Clarify in a second place that Linux and U-Boot use the same devicetree in 'To be clear, while U-Boot...' - Expand on why we should have rules for other projects in 'Devicetree in another project' - Add a comment as to why devicetree in U-Boot is not 'bad design' - Reword 'in-tree U-Boot devicetree' to 'devicetree source in U-Boot' - Rewrite 'Devicetree generated on-the-fly in another project' to cover points raised on v1 - Add 'Why does U-Boot have its nodes and properties?' - Add 'Why not have two devicetrees?' doc/develop/devicetree/dt_update.rst | 569 +++++++++++++++++++++++++++ doc/develop/devicetree/index.rst | 1 + 2 files changed, 570 insertions(+) create mode 100644 doc/develop/devicetree/dt_update.rst diff --git a/doc/develop/devicetree/dt_update.rst b/doc/develop/devicetree/dt_update.rst new file mode 100644 index 00000000000..f2ad317573a --- /dev/null +++ b/doc/develop/devicetree/dt_update.rst @@ -0,0 +1,569 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Updating the devicetree +======================= + +U-Boot uses devicetree for runtime configuration and storing required blobs or +any other information it needs to operate. It is possible to update the +devicetree separately from actually building U-Boot. This provides a good degree +of control and flexibility for firmware that uses U-Boot in conjunction with +other project. + +There are many reasons why it is useful to modify the devicetree after building +it: + +- Configuration can be changed, e.g. which UART to use +- A serial number can be added +- Public keys can be added to allow image verification +- Console output can be changed (e.g. to select serial or vidconsole) + +This section describes how to work with devicetree to accomplish your goals. + +See also :doc:`../devicetree/control` for a basic summary of the available +features. + + +Devicetree source +----------------- + +Every board in U-Boot must include a devicetree sufficient to build and boot +that board on suitable hardware (or emulation). This is specified using the +`CONFIG DEFAULT_DEVICE_TREE` option. + + +Current situation (September 2021) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As an aside, at present U-Boot allows `CONFIG_DEFAULT_DEVICE_TREE` to be empty, +e.g. if `CONFIG_OF_BOARD` or `CONFIG_OF_PRIOR_STAGE` are used. This has +unfortunately created an enormous amount of confusion and some wasted effort. +This was not intended. Since these two options do essentially the same thing, +they will be combined in a future release. Also, support for an empty +`CONFIG_DEFAULT_DEVICE_TREE` will be dropped soon. + +Some of the problems created are: + +- It is not obvious that the devicetree is coming from another project + +- There is no way to see even a sample devicetree for these platform in U-Boot, + so it is hard to know what is going on, e.g. which devices are typically + present + +- The other project may not provide a way to support U-Boot's requirements for + devicetree, such as the /config node. Note: On the U-Boot mailing linst, this + was only discovered after weeks of discussion and confusion + +- For QEMU specifically, consulting two QEMU source files is required, for which + there are no references in U-Boot documentation. The code is generating a + devicetree, but it is not clear what controls affect this generation. + +Specifically on the changes in U-Boot: + +- `CONFIG_OF_BOARD` was added in rpi_patch_ for Raspberry Pi, which does have + an in-tree devicetree, but this feature has since been used for boards that + don't +- `CONFIG_OF_PRIOR_STAGE` was added in bcm_patch_ as part of a larger Broadcom + change with a tag indicating it only affected one board, so the change in + behaviour was not noticed at the time. It has since been used by RISC-V qemu + boards. + +Once this bug is fixed, CONFIG_OF_BOARD and CONFIG_OF_PRIOR_STAGE will override +(at runtime) the devicetree suppled with U-Boot, but will otherwise use +CONFIG_OF_SEPARATE for the in-tree build. So these two will become options, +moving out of the 'choice' in `dts/Kconfig`. + +This means that there is a basic devicetree build in the U-Boot tree, for +build-testing, consistency and documentation purposes, but at runtime U-Boot can +accept its devicetree from another source. The in-tree devicetree may contain +U-Boot-specific features (in u-boot*.dtsi files) and this may prove useful for +the other project, so it can ensure that U-Boot functions correctly and supports +all its expected features. + +To be clear, while U-Boot has its own copy of the devicetree source for each +board, this must match the Linux source, perhaps with some u-boot.dtsi +additions. The intent here is not to create a separate binding, just to provide +a representative devicetree in U-Boot. + +Offending boards are: + +- bcm7260 +- bcm7445 +- qemu_arm64 +- qemu_arm +- qemu-ppce500 +- qemu-riscv32 +- qemu-riscv32_smode +- qemu-riscv64 +- qemu-riscv64_smode + +All of these need to have a devicetree added in-tree. This is targeted to be +fixed in the 2022.01 release. + + +Building the devicetree +----------------------- + +U-Boot automatically builds the devicetree for a board, from the +`arch//dts` directory. The Makefile in those directories has rules for +building devicetree files. It is preferable to avoid target-specific rules in +those files: i.e. all boards for a particular SoC should be built at once, +where practical. Apart from simplifying the Makefile, this helps to efficiently +(and immediately) ensure that changes in one board's DT do not break others that +are related. Building devicetrees is fast, so performance is seldom a concern +here. + + +Overriding the default devicetree +--------------------------------- + +When building U-Boot, the `DEVICE_TREE` environment variable allows the +default devicetree file to be overridden at build time. This can be useful if +modifications have to be made to the in-tree devicetree file, for the benefit +of a downstream build system. Note that the in-tree devicetree must be +sufficient to build and boot, so this is not a way to bypass that requirement. + + +Modifying the devicetree after building +--------------------------------------- + +While it is generally painful and hacky to modify the code or rodata of a +program after it is built, in many cases it is useful to do so, e.g. to add +configuration information like serial numbers, enabling/disabling features, etc. + +Devicetree provides a very nice solution to these problems since it is +structured data and it is relatively easy to change it, even in binary form +(see fdtput). + +U-Boot takes care that the devicetree is easily accessible after the build +process. In fact it is placed in a separate file called `u-boot.dtb`. If the +build system wants to modify or replace that file, it can do so. Then all that +is needed is to run `binman update` to update the file inside the image. If +binman is not used, then `u-boot-nodtb.bin` and the new `u-boot.dtb` can simply +be concatenated to achieve the desired result. U-Boot happily copes with the +devicetree growing or shrinking. + +The `u-boot.bin` image contains both pieces. While it is possible to locate the +devicetree within the image using the signature at the start of the file, this +is a bit messy. + +This is why `CONFIG_OF_SEPARATE` should always be used when building U-Boot. +The `CONFIG_OF_EMBED` option embeds the devicetree somewhere in the U-Boot ELF +image as rodata, meaning that it is hard to find it and it cannot increase in +size. + +When modifying the devicetree, the different cases to consider are as follows: + +- CONFIG_OF_SEPARATE + This is easy, described above. Just change, replace or rebuild the + devicetree so it suits your needs, then rerun binman or redo the `cat` + operation to join `u-boot-nodtb.bin` and the new `u-boot.dtb` + +- CONFIG_OF_EMBED + This is tricky, since the devicetree cannot easily be located. If the EFL + file is available, then the _dtb_dt_begin and __dtb_dt_end symbols can be + examined to find it. While it is possible to contract the file, it is not + possible to expand the file since that would involve re-linking + +- CONFIG_OF_PRIOR_STAGE + In this case the devicetree must be modified in the project which provides + it, as described below + +- CONFIG_OF_BOARD + This is a board-specific situation, so needs to be considered on a + case-by-case base. The devicetree must be modified so that the correct + one is provided to U-Boot. How this is done depends entirely on the + implementation of this option for the board. It might require injecting the + changes into a different project somehow using tooling available there, or + it might involve merging an overlay file at runtime to obtain the desired + result. + + +Use of U-Boot /config node +-------------------------- + +A common problem with firmware is that many builds are needed to deal with the +slight variations between different, related models. For example, one model may +have a TPM and another may not. Devicetree provides an excellent solution to +this problem, in that the devicetree to actually use on a platform can be +injected in the factory based on which model is being manufactured at the time. + +A related problem causing build proliferation is dealing with the differences +between development firmware, developer-friendly firmware (e.g. with all +security features present but with the ability to access the command line), +test firmware (which runs tests used in the factory), final production firmware +(before signing), signed firmware (where the signatures have been inserted) and +the like. Ideally all or most of these should use the same U-Boot build, with +just some options to determine the features available. For example, being able +to control whether the UART console or JTAG are available, on any image, is a +great debugging aid. + +When the firmware consists of multiple parts, it is helpful that all operate +the same way at runtime, regardless of how they were built. This can be achieved +by passing the runtime configuration (e.g. 'enable UART console) along the chain +through each firmware stage. It is frustrating to have to replicate a bug on +production firmware which does happen on developer firmware, because they are +completely different builds. + +The /config node provides useful functionality for this. It allows the different +controls to be 'factored out' of the U-Boot binary, so they can be controlled +separately from the initial source-code build. The node can be easily updated by +a build or factory tool and can control various features in U-Boot. It is +similar in concept to a Kconfig option, except that it can be changed after +U-Boot is built. + +The /config node is similar in concept to the `/chosen node`_ except that it is +for passing information *into* firmware instead of from firmware to the +Operating System. Also, while Linux has a (sometimes extremely long) command +line, U-Boot does not support this. The devicetree provides a more structured +approach in any case. + + +Devicetree in another project +----------------------------- + +In some cases U-Boot receive its devicetree at runtime from a program that calls +it. For example ARM's Trusted Firmware A (`TF-A`_) may have a devicetree that it +passes to U-Boot. This overrides any devicetree build by U-Boot. When packaging +the firmware, the U-Boot devicetree may in fact be left out if it can be +guaranteed that it will receive one from another project. + +In this case, the devicetree in the other project must track U-Boot's use of +device tree, for the following reasons: + +- U-Boot only has one devicetree. See `Why not have two devicetrees?`_. +- For a consistent firmware build, decisions made in early stages should be + communicated to later ones at runtime. For example, if the serial console is + enabled in an early stage, it should be enabled in U-Boot too. +- U-Boot is quite capable of managing its own copy of the devicetree. If + another project wants to bypass this (often for good reason), it is reasonable + that it should take on the (fairly small) requirements that U-Boot features + that rely on devicetree are still available +- The point here is not that *U-Boot needs this extra node*, or *U-Boot needs + to have this public key*. These features are present in U-Boot in service of + the entire firmware system. If the U-Boot features are used, but cannot be + supported in the normal way, then there is pressure to implement these + features in other ways. In the end, we would have a different mechanism for + every other project that uses U-Boot. This introduces duplicate ways of doing + the same thing, needlessly increases the complexity of the U-Boot source code, + forces authors to consider parallel implementations when writing new features, + makes U-Boot harder to test, complicates documentation and confuses the + runtime flow of U-Boot. If every board did things its own way rather than + contributing to the common code, U-Boot would lose a lot of its cross-platform + value. + +The above does not indicate *bad design* within U-Boot. Devicetree is a core +component of U-Boot and U-Boot makes use of it to the full. It solves a myriad +of problems that would otherwise need their own special C struct, binary format, +special property, tooling for viewing and updating, etc. + +Specifically, the other project must provide a way to add configuration and +other information to the devicetree for use by U-Boot, such as the /config node. +Note that the U-Boot in-tree devicetree source must be sufficient to build and +boot, so this is not a way to bypass that requirement. + +If binman is used, the devicetree source in U-Boot must contain the binman +definition so that a valid image can be build. This helps people discover what +other firmware components are needed and seek out appropriate documentation. + +If verified boot is used, the project must provide a way to inject a public key, +certificate or other material into the U-Boot devicetree so that it is available +to U-Boot at runtime. See `Signing with U-Boot devicetree`_. This may be +through tooling in the project itself or by making use of U-Boot's tooling. + + +Devicetree generated on-the-fly in another project +-------------------------------------------------- + +In some rare cases, another project may wish to create a devicetree for U-Boot +entirely on-the-fly, then pass it to U-Boot at runtime. The only known example +of this at the time of writing (2021) is qemu, for ARM (`QEMU ARM`_) and +RISC-V (`QEMU RISC-V`_). + +In effect, when the board boots, U-Boot is *downstream* of the other project. +It is entirely reliant on that project for its correct operation. + +This does not mean to imply that the other project is creating its own, +incompatible devicetree. In fact QEMU generates a valid devicetree which is +suitable for both U-Boot and Linux. It is quite normal for a devicetree to be +present in flash and be made available to U-Boot at runtime. What matters is +where the devicetree comes from. If the other project builds a devicetree for +U-Boot then it needs to support adding the things needed by U-Boot features. +Without them, for example: + +- U-Boot may not boot because too many devices are enabled before relocation +- U-Boot may not have access to the developer or production public keys used for + signing +- U-Boot may not support controlling whether the console is enabled +- U-Boot may not be know which MMC device to boot from +- U-Boot may not be able to find other firmware components that it needs to load + +Normally, supporting U-Boot's features is trivial, since the devicetree compiler +(dtc) can compile the source, including any U-Boot pieces. So the burden is +extremely low. + +In this case, the devicetree in the other project must track U-Boot's use of +device tree, so that it remains compatible. See `Devicetree in another project`_ +for reasons why. + +If a particular version of the project is needed for a particular version of +U-Boot, that must be documented in both projects. + +Further, it must provide a way to add configuration and other information to +the devicetree for use by U-Boot, such as the `/config` node and the tags used +by driver model. Note that the U-Boot in-tree devicetree must be sufficient to +build and boot, so this is not a way to bypass that requirement. + +More specifically, tooling or command-line arguments must provide a way to +add a `/config` node or items within that node, so that U-Boot can receive a +suitable configuration. It must provide a way of adding `u-boot,dm-...` tags for +correct operation of driver model. These options can then be used as part of the +build process, which puts the firmware image together. For binman, a way must be +provided to add the binman definition into the devicetree in the same way. + +One way to do this is to allow a .dtsi file to be merged in with the generated +devicetree. + +Note that the burden goes both ways. If a new feature is added to U-Boot which +needs support in another project, then the author of the U-Boot patch must add +any required support to the other project. + + +Passing the devicetree through to Linux +--------------------------------------- + +Ideally U-Boot and Linux use the same devicetree source, even though it is +hosted in separate projects. U-Boot adds some extra pieces, such as the +`config/` node and tags like `u-boot,dm-spl`. Linux adds some extra pieces, such +as `linux,default-trigger` and `linux,code`. This should not interfere with +each other. + +In principle it is possible for U-Boot's control devicetree to be passed to +Linux. This is, after all, one of the goals of devicetree and the original +Open Firmware project, to have the firmware provide the hardware description to +the Operating System. + +For boards where this approach is used, care must be taken. U-Boot typically +needs to 'fix up' the devicetree before passing it to Linux, e.g. to add +information about the memory map, about which serial console is used, provide +the kernel address space layout randomization (KASLR) seed or select whether the +console should be silenced for a faster boot. + +Fix-ups involve modifying the devicetree. If the control devicetree is used, +that means the control devicetree could be modified, while U-Boot is using it. +Removing a device and reinserting it can cause problems if the devicetree offset +has changed, for example, since the device will be unable to locates its +devicetree properties at the expected devicetree offset, which is a fixed +integer. + +To deal with this, it is recommended to employ one or more of the following +approaches: + +- Make a copy of the devicetree and 'fix up' the copy, leaving the control + devicetree alone +- Enable `CONFIG_OF_LIVE` so that U-Boot makes its own copy of the devicetree + during relocation; fixups then happen on the original flat tree +- Ensure that fix-ups happen after all loading has happened and U-Boot has + completed image verification + +In practice,the last point is typically observed, since boot_prep_linux() is +called just before jumping to Linux, long after signature verification, for +example. But it is important to make sure that this line is not blurred, +particularly if untrusted user data is involved. + + +Devicetree use cases that must be supported +------------------------------------------- + +Regardless of how the devicetree is provided to U-Boot at runtime, various +U-Boot features must be fully supported. This section describes some of these +features and the implications for other projects. + +If U-Boot uses its own in-tree devicetree these features are supported +automatically. + + +Signing with U-Boot devicetree +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +U-Boot supports signing a payload so that it can be verified to have been +created by a party owning a private key. This is called verified boot in U-Boot +(see doc/uImage.FIT/verified-boot.txt). + +Typically this works by creating a FIT and then running the `mkimage` tool to +add signatures for particular images. As part of this process, `mkimage` writes +a public key to the U-Boot devicetree, although this can be done separately. +See fdt_add_pubkey_ for patches for a suitable tool, for example. + +As with all configuration information, if another project is providing the +devicetree to U-Boot, it must provide a way to add this public key into the +devicetree it passes to U-Boot. This could be via a tooling option, making use +of `mkimage`, or allowing a .dtsi file to be merged in with what is generated in +the other project. + + +Providing the binman image definition +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In complex systems U-Boot must locate and make use of other firmware components, +such as images for the user interface, files containing peripheral firmware, +multiple copies of U-Boot for use with A/B boot, etc. U-Boot uses +:doc:`Binman <../package/binman>` as a standard way of putting an image +together. + +Typically this works by running binman with the devicetree as an input, to +create the file image. Binman then outputs an updated devicetree which is +packed in the firmware image, so U-Boot can access the binman definition and +locate all the components. + +As with all configuration information, if another project is providing the +devicetree to U-Boot, it must provide a way to add this binman definition into +the devicetree it passes to U-Boot. This could be via a tooling option, making +use of `binman`, or alowing a .dtsi file to be merged in with what is generated +in the other project. + + +Protecting the devicetree +------------------------- + +U-Boot relies heavily on devicetree for correct operation. A corrupt or invalid +device can cause U-Boot to fail to start, behave incorrectly, crash (e.g. if +`CONFIG_OF_LIBFDT_ASSUME_MASK` is adjusted, or fail to boot an Operating System. +Within U-Boot, the devicetree is as important as any other part of the source +code. At ruuntime, the devicetree can be considered to be structured rodata. + +With secure systems, care must be taken that the devicetree is valid: + +- If the code / rodata has a hash or signature, the devicetree should also, if + they are packaged separately. +- If the code / rodata is write-protected when running, the devicetree should be + also. Note that U-Boot relocates its code and devicetree, so this is not as + simple as it sounds. U-Boot must write-protect these items after relocating. + + +Why does U-Boot have its nodes and properties? +---------------------------------------------- + +See also :doc:`../devicetree/intro`. + +There has been pushback at the concept that U-Boot dares have its own nodes and +properties in the devicetree. + +Apart from these nodes and properties, U-Boot uses the same bindings as Linux. +A `u-boot.dtsi` file helps to keep U-Boot-specific changes in separate files, +making it easier to keep devicetree source files in U-Boot in sync with Linux. + +As a counter-example, the Zephyr OS project takes a different approach. It uses +entirely different bindings, in general, making no effort to sync devicetree +source files with Linux. U-Boot strives to be compatible with Linux in a number +of ways, such as source code style and common APIs, to aid porting of code +between the projects. Devicetree is another way where U-Boot and Linux follow a +similar approach. + +Fundamentally, the idea that U-Boot cannot have its own tags flies in the face +of the devicetree specification (see dtspec_), which says: + + Nonstandard property names should specify a **unique string prefix**, such as + a stock ticker symbol, identifying the name of the company **or organization** + that defined the property. Examples: + + - fsl,channel-fifo-len + - ibm,ppc-interrupt-server#s + - **linux**,network-index + +It is also fundamentally unbalanced. Linux has many tags of its own (some 36 in +version 5.13) and at least one Linux-specific node, even if you ignore things +like flash partitions which clearly provide configuration information to Linux. + +Practically speaking there are many reasons why U-Boot has its own nodes and +properties. Some examples: + +- Binding every device before relocation even if it won't be used, consumes time + and memory: tags on each node can specify which are needed in SPL or before + relocation. Linux has no such constraints. + +- Requiring the full clock tree to be up and running just to get the debug UART + running is inefficient. It is also and self-defeating, since if that much + code is working properly, you probably don't need the debug UART. A devicetree + property to provide the UART input-clock frequency is a simple solution. + +- U-Boot does not have a user space to provide policy and configuration. It + cannot do what Linux does and run programs and look up filesystems to figure + out how to boot. + + +Why not have two devicetrees? +----------------------------- + +Setting aside the argument for restricting U-Boot from having its own nodes and +properties, another idea proposed is to have two devicetrees, one for the +U-Boot-specific bits (here called `special`) and one for everything else (here +called `linux`). + +On the positive side, it might quieten the discussion alluded to in the section +above. But there are many negatives to consider and many open questions to +resolve. + +- **Bindings** - Presumably the special devicetree would have its own bindings. + It would not be necessary to put a `u-boot,` prefix on anything. People coming + across the devicetree source would wonder how it fits in with the Linux + devicetree. + +- **Access** - U-Boot has a nice `ofnode` API for accessing the devicetree. This + would need to be expanded to support two trees. Features which need to access + both (such as a device driver which reads the special devicetree to get some + configuration info) could become quite confusing to read and write. + +- **Merging** - Can the two devicetree be merged if a platform desires it? If + so, how is this managed in tooling? Does it happen during the build, in which + case they are not really separate at all. Or does U-Boot merge them at + runtime, in which case this adds time and memory? + +- **Efficiency** - A second device tree adds more code and more code paths. It + requires that both be made available to the code in U-Boot, e.g. via a + separate pointer or argument or API. Overall the separation would certainly + not speed up U-Boot, nor decrease its size. + +- **Source code** - At present `u-boot.dtsi` files provide the pieces needed for + U-Boot for a particular board. Would we use these same files for the special + devicetree? + +- **Complexity** - Two devicetrees complicates the build system since it must + build and package them both. Errors must be reported in such a way that it + is obvious which one is failing. + +- **Referencing each other** - The `u-boot,dm-xxx` tags used by driver model + are currently placed in the nodes they relate to. How would these tags + reference a node that is in a separate devicetree? What extra validation would + be needed? + +- **Storage** - How would the two devicetrees be stored in the image? At present + we simply concatenate the U-Boot binary and the devicetree. We could add the + special devicetree before the Linux one, so two are concatenated, but it is + not pretty. We could use binman to support more complex arrangements, but only + some boards use this at present, so it would be a big change. + +- **API** - How would another project provide two devicetree files to U-Boot at + runtime? Presumably this would just be too painful. But if it doesn't, it + would be unable to configure run-time features of U-Boot during the boot. + +- **Confusion** - No other project has two devicetrees. U-Boot would be in the + unfortunate position of having to describe this fact to new users, along with + the (arguably contrived) reason for the arrangement. + +- **Signing flow** - The current signing flow is simple as it involves running + `mkimage` with the U-Boot devicetree. This would have to be updated to use the + special devicetree. Some way of telling the user that they have done it wrong + would have to be invented. + +Overall, adding a second devicetree would create enormous confusion and +complexity. It seems a lot cheaper to solve this by a change of attitude. + + +.. _rpi_patch: https://patchwork.ozlabs.org/project/uboot/patch/20170402082520.32546-1-deymo@google.com/ +.. _bcm_patch: https://patchwork.ozlabs.org/project/uboot/patch/16fc0901f4521d3c399eac950c52a634b2f9473b.1528485916.git.fitzsim@fitzsim.org/ +.. _`TF-A`: https://www.trustedfirmware.org/projects/tf-a +.. _`QEMU ARM`: https://github.com/qemu/qemu/blob/master/hw/arm/virt.c +.. _`QEMU RISC-V`: https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c +.. _`/chosen node`: https://www.kernel.org/doc/Documentation/devicetree/bindings/chosen.txt +.. _fdt_add_pubkey: https://patchwork.ozlabs.org/project/uboot/list/?series=157843&state=* +.. _dtspec: https://www.devicetree.org/specifications/ diff --git a/doc/develop/devicetree/index.rst b/doc/develop/devicetree/index.rst index fa5db3eb76e..b5b33dfea0f 100644 --- a/doc/develop/devicetree/index.rst +++ b/doc/develop/devicetree/index.rst @@ -11,3 +11,4 @@ build-time and runtime configuration. intro control + dt_update