All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: U-Boot Mailing List <u-boot@lists.denx.de>
Cc: "Ilias Apalodimas" <ilias.apalodimas@linaro.org>,
	"Tom Rini" <trini@konsulko.com>,
	"François Ozog" <francois.ozog@linaro.org>,
	"Heinrich Schuchardt" <xypron.glpk@gmx.de>,
	"Bill Mills" <bill.mills@linaro.org>,
	"Simon Glass" <sjg@chromium.org>,
	"Mario Six" <mario.six@gdsys.cc>
Subject: [PATCH v2 12/16] passage: Add documentation
Date: Mon, 17 Jan 2022 08:04:24 -0700	[thread overview]
Message-ID: <20220117080353.v2.12.I91d5b9ae45e8d1081b1e165620ad1946bd69af00@changeid> (raw)
In-Reply-To: <20220117150428.1580273-1-sjg@chromium.org>

Add documentation about standard passage and update the maintainers.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Add comments about how to pass standard passage to EFI
- Add comments about passing a bloblist to Linux
- Add detailed arch-specific information

 MAINTAINERS                   |  10 +
 board/sandbox/stdpass_check.c |  10 +-
 doc/develop/bloblist.rst      |   4 +-
 doc/develop/index.rst         |   1 +
 doc/develop/std_passage.rst   | 396 ++++++++++++++++++++++++++++++++++
 5 files changed, 411 insertions(+), 10 deletions(-)
 create mode 100644 doc/develop/std_passage.rst

diff --git a/MAINTAINERS b/MAINTAINERS
index 38c68ee87d4..63723d43b63 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1177,6 +1177,16 @@ F:	common/stackprot.c
 F:	cmd/stackprot_test.c
 F:	test/py/tests/test_stackprotector.py
 
+STANDARD PASSAGE
+M:	Simon Glass <sjg@chromium.org>
+F:	board/sandbox/stdpass_check.c
+F:	cmd/bloblist.c
+F:	common/bloblist.c
+F:	doc/develop/std_passage.rst
+F:	include/bloblist.h
+F:	include/stdpass/
+F:	test/bloblist.c
+
 TARGET_BCMNS3
 M:	Bharat Gooty <bharat.gooty@broadcom.com>
 M:	Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com>
diff --git a/board/sandbox/stdpass_check.c b/board/sandbox/stdpass_check.c
index 565124e1564..8391c7a4aed 100644
--- a/board/sandbox/stdpass_check.c
+++ b/board/sandbox/stdpass_check.c
@@ -8,13 +8,6 @@
 
 #include <common.h>
 
-/* BLOBLISTT_U_BOOT_SPL_HANDOFF */
-#include <handoff.h>
-void check_spl_handoff(void)
-{
-	__maybe_unused struct spl_handoff check;
-};
-
 /*
  * See also doc/develop/std_passage.rst
  *
@@ -23,7 +16,8 @@ void check_spl_handoff(void)
  * 1. Add your header file to U-Boot, or to include/stdpass if it is not used in
  * U-Boot
  *
- * 2. Add a function below to include the header and use the struct
+ * 2. Add a function below to include the header and use the struct. Please put
+ * your function in order of tag ID (see bloblist.h)
  *
  * Template follows, see above for example
  */
diff --git a/doc/develop/bloblist.rst b/doc/develop/bloblist.rst
index 572aa65d764..e819c6dc76b 100644
--- a/doc/develop/bloblist.rst
+++ b/doc/develop/bloblist.rst
@@ -1,7 +1,7 @@
 .. SPDX-License-Identifier: GPL-2.0+
 
-Blob Lists - bloblist
-=====================
+Bloblist
+========
 
 Introduction
 ------------
diff --git a/doc/develop/index.rst b/doc/develop/index.rst
index 9592d193fca..d0aecc30059 100644
--- a/doc/develop/index.rst
+++ b/doc/develop/index.rst
@@ -21,6 +21,7 @@ Implementation
    logging
    makefiles
    menus
+   std_passage
    uefi/index
    version
 
diff --git a/doc/develop/std_passage.rst b/doc/develop/std_passage.rst
new file mode 100644
index 00000000000..461098e01e7
--- /dev/null
+++ b/doc/develop/std_passage.rst
@@ -0,0 +1,396 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Standard Passage
+================
+
+Introduction
+------------
+
+It is sometimes necessary for SPL to communicate information to U-Boot proper,
+such as the RAM size. This can sometimes be handled by adding the value to a
+Kconfig which both SPL and U-Boot proper can use. But this does not work for
+values which are detected at runtime.
+
+In some cases other firmware binaries are used alongside U-Boot and these may
+need to pass information to U-Boot or receive information from it. In this case
+there is no shared build system and it is clumsy so have to specify matching
+build options across projects.
+
+U-Boot provides a standard way of passing information between different phases
+(TPL, SPL, U-Boot). This is called `standard passage` since it creates a
+standard passage through which any sort of information can flow.
+
+
+How it works
+------------
+
+The standard passage is very simple. It is really just a way of sending a
+bloblist between programs, either at a fixed address, or using registers to
+indicate the location.
+
+A :doc:`bloblist` is a simple, contiguous data structure containing a number of
+blobs. Each blob has a tag to indicate what it contains. It is designed for
+simple information, like a small C struct. For more complex data, a devicetree
+is preferred since it has bindings and is extensible.
+
+The bloblist is typically set up initially by one of the early phases of U-Boot,
+such as TPL. It starts either at a fixed address or is allocated in memory using
+malloc(). After that, TPL passes the location of the bloblist to SPL (using
+machine register in an architecture-specific way) and SPL passes it to U-Boot
+proper. It is possible to add new blobs to the bloblist at each phase. U-Boot
+proper relocates the bloblist so can expand it if desired.
+
+
+Use by other projects
+---------------------
+
+The standard passage is also intended to be used by other firmware projects,
+particularly if they interface with U-Boot. It allows that project's firmware
+binaries to pass information to U-Boot (if they run before U-Boot) or receive
+information from U-Boot (if they run afterwards).
+
+These projects can copy and modify the bloblist code provided they have a
+compatible license.
+
+
+Allocating tags
+---------------
+
+Tags are defined in the `bloblist.h` header file. For the moment, the U-Boot
+tree is the upstream repository for tags.
+
+Tags may be allocated in the following areas:
+
+BLOBLISTT_AREA_FIRMWARE_TOP
+    A small area for tags of considerable relevance to multiple projects
+
+BLOBLISTT_AREA_FIRMWARE
+    A larger area for tags likely to be relevant to multiple projects either now
+    or in the future
+
+BLOBLISTT_PROJECT_AREA
+    Used for specific projects that want to make sure their tags are correctly
+    ignored by other binaries in the firmware flow. This area should not be
+    used for tags that are used by multiple projects. Instead, use
+    `BLOBLISTT_AREA_FIRMWARE`.
+
+BLOBLISTT_VENDOR_AREA
+    Used for specific vendors that want to make sure their tags are correctly
+    ignored by other binaries in the firmware flow. This area should not be
+    used for tags that are used by multiple vendors. Instead, use
+    `BLOBLISTT_AREA_FIRMWARE`.
+
+BLOBLISTT_PRIVATE_AREA
+    Used for private flags. Do not send patches with these. They are for local
+    or temporary use. Standard firmware binaries which see these tags in the
+    bloblist typically refuse to boot.
+
+To add a new tag for your project, send a patch to the U-Boot project with:
+
+  - your new tag, using the next available number in the area your choose
+  - a header file in include/stdpass/ containing your struct definition if your
+    struct is not actually used in U-Boot
+  - a line of code in `board/sandbox/stdpass_check.c` to use the struct (see
+    that file for instructions)
+
+The struct definition does not need to match the code style or types names used
+in the other project. For example, your project might use a type like
+__UNSIGNED_INT32 which in U-Boot would be written as u32. Types should be sized
+so that the struct is the same on 32- and 64-bit machines. Avoid using __packed
+if possible. Instead try to order members so that it is not necessary.
+
+Conflicts are resolved before applying patches to mainline, so your actual tag
+value may change when the patch is applied. Once your patch is accepted your tag
+is allocated for all time.
+
+Devicetree
+----------
+
+Devicetree has a special place in the standard passage. One of the bloblist tags
+is BLOBLISTT_CONTROL_DTB which indicates that that blob contains a devicetree
+intended to control U-Boot (or other binaries). This devicetree provides
+hardware information and configuration in a generic way using standard bindings,
+so that it is available for any project to use. The bindings are compatible with
+operating systems (including Linux) so there is no need to remove them before
+calling the OS.
+
+In cases where a binary wants to access the devicetree but does not want to
+implement the bloblist feature, the offset of the devicetree within the
+bloblist is provided. This avoids the need to implement bloblists just to
+access the devicetree. This is a convenience feature intended for use in
+degenerate cases.
+
+However U-Boot itself does not permit accepting a devicetree through standard
+passage unless it is part of a valid bloblist. It is easy to turn on the
+bloblist feature in U-Boot, so such a variation would only serve to confuse
+things and encourage degeneration in other projects.
+
+
+Standard passage API
+--------------------
+
+The protocol for passing a bloblist through the standard passage from one
+binary to another is architecture-specific, meaning it works differently on
+32-/64-bit ARM and x86, for example, if only because of the different register
+naming.
+
+The bloblist is mandatory. If there is no information to pass, the bloblist must
+still be provided. Following firmware stages may add blobs to the bloblist,
+making use of the existing space.
+
+The minimum bloblist size is 256 bytes, but 4KB is recommended.
+
+Two registers are used to pass the bloblist and devicetree pointers. Others may
+be used depending on the architecture. The protocol chosen for each architecture
+should be compatible with the Linux protocol, with a way of determining whether
+standard passage is used. This is done not because Linux might start using
+standard passage, but to avoid reinventing the wheel.
+
+For 32-bit ARM:
+
+  =========  ==============================================
+  Register   Contents
+  =========  ==============================================
+  r0         0
+  r1         0xb0075701 (indicates standard passage v1)
+  r2         Address of devicetree
+  r3         Address of bloblist
+  r4         0
+  lr         Return address
+  =========  ==============================================
+
+For 64-bit ARM:
+
+  =========  ===================================================
+  Register   Contents
+  =========  ===================================================
+  x0         Address of devicetree
+  x1         0xb00757a300000001 (indicates standard passage v1)
+  x2         0
+  x3         Address of bloblist
+  x4         0
+  x30        Return address
+  =========  ===================================================
+
+The devicetree is provided as an address but it normally included within the
+bloblist, meaning that searching for the BLOBLISTT_CONTROL_DTB blob with the
+bloblist produces the same result as the devicetree address passed here. Having
+everything in a bloblist makes it easier to manage memory, since it is all in
+one contiguous block.
+
+
+Usage guidelines
+----------------
+
+As mentioned above, blobs should contain small, simple blocks of information,
+typically represented by a C structure. Using it for large or complex structures
+is only permitted if these are defined by a standard byte-accurate form.
+Examples include devicetree, ACPI tables, SMBIOS tables and the like.
+There are also a lot of pre-existing firmware binaries which are quite complex
+but qualify because it is not possible to convert them to devicetree now. Apart
+from those exceptions, keep it simple!
+
+For complex data structures, devicetree can be used. The libfdt library has an
+overhead of around 5-10KB which is small enough that most firmware binaries can
+easily incorporate it. For those that must run in very constrained environments,
+like U-Boot TPL, a simple blob can be used instead, as explained in the
+preceding paragraph.
+
+Devicetree bindings must be defined so that the format of the data is well
+understood. This is done through the `dt-schema`_ project, although this process
+is still in its infancy.
+
+
+EFI
+---
+
+When using EFI a different calling convention is used. For example, with 64-bit
+ARM we have:
+
+  =========  ===================================================
+  Register   Contents
+  =========  ===================================================
+  x0         handle
+  x1         system table
+  x30        Return address
+  =========  ===================================================
+
+It is not possible to pass the bloblist in a register in this case. Instead, a
+config table can be used. The GUID for a bloblist is
+4effe9da-7728-11ec-8df6-136969a780ff
+
+
+Linux and bloblists
+-------------------
+
+It is possible to effectively pass a bloblist to Linux, or other Operating
+Systems. However it is not expected that Linux would actually implement the
+bloblist data structure. How does this work?
+
+The bloblist sits in memory with some things in it, including a devicetree,
+perhaps an SMBIOS table and a TPM log. But when U-Boot calls Linux it puts the
+address/size of those individual things in the devicetree. They don't move and
+are still contiguous in memory, but the bloblist around them is forgotten. Linux
+doesn't know that the three separate things it is picking up are actually part
+of a bloblist structure, since it doesn't care about that. Even a console log
+can work the same way. There is no need to teach Linux about bloblist when it
+already has a perfectly good means to accept these items (via devicetree).
+
+ACPI can operate in a similar way. The ACPI tables can point to things that
+happen to be in a bloblist, but without any knowledge of that needed in Linux,
+grub, etc. In fact the ACPI tables themselves may well be in a bloblist, as they
+are in U-Boot.
+
+
+Private firmware
+----------------
+
+Standard passage is intended to operate with open-source firmware. It may be
+that closed-source firmware may use standard passage, or happen to work with it.
+If so, that is a happy coincidence, but the focus here is on open-source
+firmware.
+
+
+Updates
+-------
+
+Updates and patches to this documentation are welcome. Please submit them to
+the U-Boot project in the normal way.
+
+
+Design notes
+------------
+
+This section describes some of the reasons behind the design decisions implied
+by this feature.
+
+Why devicetree?
+~~~~~~~~~~~~~~~
+
+Firmware is getting large and complicated, with a concomitant need for more
+complex communication between binaries. We don't want to use C structs to pass
+around complex data, nor invent new binary formats for everything that comes up.
+The devicetree provides a useful format and is already widely used in firmware.
+It supports bindings and provides validation to check for compliance, by virtue
+of the Linux project and `dt-schema`_. It is easily extensible, being basically
+an efficient, hierarchical, ordered dictionary.
+
+Some examples of how complex and annoying binary formats can become are SMBIOS
+tables and Intel's Video BIOS tables. The world does not need another binary
+format.
+
+
+Why not *just* devicetree?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some early firmware binaries run in very little memory and only need to pass a
+few values on to later phases. Devicetree is too heavy-weight for these cases.
+For example, it is generally not possible for TPL to access a devicetree, which
+is one of the motivations for the of-platdata feature.
+
+
+Why not protobuf, YAML, JSON?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+They are not as efficient and either use a lot more code or require parsing
+before use. Devicetree happens to be a nice compromise.
+
+
+Why not something else?
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Possibly. Please propose it.
+
+
+Why not UUIDs?
+~~~~~~~~~~~~~~
+
+Why use a simple integer tag instead of an 'industry-standard' UUID? Many
+reasons:
+
+- Code should be as readable as possible. GUIDs require something like::
+
+    EFI_GUID(0x6dadf1d1, 0xd4cc, 0x4910, \
+        0xbb, 0x6e, 0x82, 0xb1, 0xfd, 0x80, 0xff, 0x3d)
+
+  which is much harder to read than::
+
+    enum {
+        BLOBLISTT_SPL_HANDOFF = 123,
+    };
+
+- UUIDs are more like a hash than a sequence number. Git uses them, although a
+  short form of the hash is commonly shown. Why use a hash to identify
+  something when we only have a small number of items?
+
+- We don't need to worry about collisions in open source software. We can have
+  a shared repo and allocate sequence numbers from there. UUIDs come from the
+  idea that everyone is working independently so people need to be able to
+  allocate their own numbers and be sure that they will not conflict. This is
+  needed in the PC BIOS industry where there is little shared source /
+  cooperation. It is not helpful with open source.
+
+- UUIDs come across as just obfuscation. Does anyone know what these values
+  mean? How would we look them up? Who owns which one? Is there a central
+  registry?::
+
+    EFI_GUID(0x721acf02, 0x4d77, 0x4c2a, 0xb3, 0xdc, 0x27, 0x0b, 0x7b, 0xa9, 0xe4, 0xb0)
+    EFI_GUID(0xa034147d, 0x690c, 0x4154, 0x8d, 0xe6, 0xc0, 0x44, 0x64, 0x1d, 0xe9, 0x42)
+    EFI_GUID(0xbbcff46c, 0xc8d3, 0x4113, 0x89, 0x85, 0xb9, 0xd4, 0xf3, 0xb3, 0xf6, 0x4e)
+    EFI_GUID(0x69a79759, 0x1373, 0x4367, 0xa6, 0xc4, 0xc7, 0xf5, 0x9e, 0xfd, 0x98, 0x6e)
+    EFI_GUID(0xd038747c, 0xd00c, 0x4980, 0xb3, 0x19, 0x49, 0x01, 0x99, 0xa4, 0x7d, 0x55)
+    EFI_GUID(0x9c7c3aa7, 0x5332, 0x4917, 0x82, 0xb9, 0x56, 0xa5, 0xf3, 0xe6, 0x2a, 0x07)
+
+- It is overkill to use 16 bytes for a unique identifier in a shared project.
+  It is about 10^38. Modern SoCs cannot keep that in a register and there is no
+  C int type to represent it on most common hardware today! Having to check that
+  adds time and code to no benefit. In early boot, space and time are
+  particularly precious.
+
+
+Why contiguous?
+~~~~~~~~~~~~~~~
+
+It is easier to allocate a single block of data than to allocate lots of little
+blocks. It is easy to relocate if needed (a simple copy of a block of memory).
+It can be expanded by relocating it. If we absolutely need to create a linked
+list then pointers to external data can be added to a blob.
+
+
+Why bloblist?
+~~~~~~~~~~~~~
+
+Bloblist is a simple format with an integer tag. It avoids UUIDs and meets the
+requirements above. Some tweaks may be desirable to the format, but that can be
+worked out in code review.
+
+
+Why pass the devicetree offset?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In cases where a binary wants to access the devicetree but does not want to
+implement the bloblist feature, the offset of the devicetree within the
+bloblist is provided. This avoids the need to implement bloblists just to
+access the devicetree. This is a convenience feature intended for use in
+degenerate cases.
+
+
+Why use registers to pass values between binaries?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It seems like the obvious solution. We could use a shared memory region with
+shared configuration between projects, but that is error prone and difficult to
+keep in sync.
+
+
+Why not add magic values to indicate that standard passage is used?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We could put a magic value in a register to tell the next phase that the
+standard-passage information is available (in other registers). But making it
+a build-time option saves at least one register and makes things a little more
+deterministic at built time. If we know we can rely on it, it is easier to
+use.
+
+
+.. _`dt-schema`: https://github.com/devicetree-org/dt-schema
-- 
2.34.1.703.g22d0c6ccf7-goog


  parent reply	other threads:[~2022-01-17 15:06 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-17 15:04 [PATCH v2 00/16] passage: Define a standard for firmware data flow Simon Glass
2022-01-17 15:04 ` [PATCH v2 01/16] spl: Tidy up the header includes Simon Glass
2022-01-17 15:04 ` [PATCH v2 02/16] arm: qemu: Add an SPL build Simon Glass
2022-01-17 15:04 ` [PATCH v2 03/16] spl: Rename jump_to_image_no_args() Simon Glass
2022-01-17 15:04 ` [PATCH v2 04/16] passage: Support an incoming passage Simon Glass
2022-01-17 15:04 ` [PATCH v2 05/16] passage: Support a control devicetree Simon Glass
2022-01-17 15:04 ` [PATCH v2 06/16] passage: arm: Accept a passage from the previous phase Simon Glass
2022-01-17 15:04 ` [PATCH v2 07/16] passage: spl: Support adding the dtb to the passage bloblist Simon Glass
2022-01-17 15:04 ` [PATCH v2 08/16] passage: spl: Support passing the passage to U-Boot Simon Glass
2022-01-17 15:04 ` [PATCH v2 09/16] passage: arm: Add the arch-specific standard passage impl Simon Glass
2022-01-17 15:04 ` [PATCH v2 10/16] passage: Add a qemu test for ARM Simon Glass
2022-01-17 15:04 ` [PATCH v2 11/16] sandbox: Add a way of checking structs for standard passage Simon Glass
2022-01-17 15:04 ` Simon Glass [this message]
2022-01-17 16:39   ` [PATCH v2 12/16] passage: Add documentation Mark Kettenis
2022-01-17 15:04 ` [PATCH v2 13/16] passage: Add docs for spl_handoff Simon Glass
2022-01-17 15:04 ` [PATCH v2 14/16] x86: Move Intel GNVS file into the common include directory Simon Glass
2022-01-17 15:04 ` [PATCH v2 15/16] passage: Add checks for pre-existing blobs Simon Glass
2022-01-17 15:04 ` [PATCH v2 16/16] WIP: RFC: Add a gitlab test Simon Glass

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220117080353.v2.12.I91d5b9ae45e8d1081b1e165620ad1946bd69af00@changeid \
    --to=sjg@chromium.org \
    --cc=bill.mills@linaro.org \
    --cc=francois.ozog@linaro.org \
    --cc=ilias.apalodimas@linaro.org \
    --cc=mario.six@gdsys.cc \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=xypron.glpk@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.