.. SPDX-License-Identifier: GPL-2.0+
.. Copyright (c) 2022 Linaro Limited

FWU Multi Bank Updates in U-Boot
================================

The FWU Multi Bank Update feature implements the firmware update
mechanism described in the PSA Firmware Update for A-profile Arm
Architecture specification [1]. Certain aspects of the Dependable
Boot specification [2] are also implemented. The feature provides a
mechanism to have multiple banks of updatable firmware images and for
updating the firmware images on the non-booted bank. On a successful
update, the platform boots from the updated bank on subsequent
boot. The UEFI capsule-on-disk update feature is used for performing
the actual updates of the updatable firmware images.

The bookkeeping of the updatable images is done through a structure
called metadata. Currently, the FWU metadata supports identification
of images based on image GUIDs stored on a GPT partitioned storage
media. There are plans to extend the metadata structure for non GPT
partitioned devices as well.

Accessing the FWU metadata is done through generic API's which are
defined in a driver which complies with the U-Boot's driver model. A
new uclass UCLASS_FWU_MDATA has been added for accessing the FWU
metadata. Individual drivers can be added based on the type of storage
media, and its partitioning method. Details of the storage device
containing the FWU metadata partitions are specified through a U-Boot
specific device tree property `fwu-mdata-store`. Please refer to
U-Boot :download:`fwu-mdata-gpt.yaml
</device-tree-bindings/firmware/fwu-mdata-gpt.yaml>`
for the device tree bindings.

Enabling the FWU Multi Bank Update feature
------------------------------------------

The feature can be enabled by specifying the following configs::

    CONFIG_EFI_CAPSULE_ON_DISK=y
    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y
    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y

    CONFIG_FWU_MULTI_BANK_UPDATE=y
    CONFIG_FWU_MDATA=y
    CONFIG_FWU_MDATA_GPT_BLK=y
    CONFIG_FWU_NUM_BANKS=<val>
    CONFIG_FWU_NUM_IMAGES_PER_BANK=<val>

    CONFIG_FWU_MDATA_V1=y or CONFIG_FWU_MDATA_V2=y

in the .config file

By enabling the CONFIG_CMD_FWU_METADATA config option, the
fwu_mdata_read command can be used to check the current state of the
FWU metadata structure.

The first group of configuration settings enable the UEFI
capsule-on-disk update functionality. The second group of configs
enable the FWU Multi Bank Update functionality. Please refer to the
section :ref:`uefi_capsule_update_ref` for more details on generation
of the UEFI capsule.

FWU Metadata
------------

U-Boot supports both versions(1 and 2) of the FWU metadata defined in
the two revisions of the specification. Support can be enabled for
either of the two versions through a config flag. The mkfwumdata tool
can generate metadata for both the supported versions.

Setting up the device for GPT partitioned storage
-------------------------------------------------

Before enabling the functionality in U-Boot, a GPT partitioned storage
device is required. Assuming a GPT partitioned storage device, the
storage media needs to be partitioned with the correct number of
partitions, given the number of banks and number of images per bank
that the platform is going to support. Each updatable firmware image
will be stored on a separate partition. In addition, the two copies
of the FWU metadata will be stored on two separate partitions. These
partitions need to be created at the time of the platform's
provisioning.

As an example, a platform supporting two banks with each bank
containing three images would need to have 2 * 3 = 6 partitions plus
the two metadata partitions, or 8 partitions. In addition the storage
media can have additional partitions of non-updatable images, like the
EFI System Partition(ESP), a partition for the root file system
etc. An example list of images on the storage medium would be

* FWU metadata 1
* U-Boot 1
* OP-TEE 1
* FWU metadata 2
* OP-TEE 2
* U-Boot 2
* ESP
* rootfs

When generating the partitions, a few aspects need to be taken care
of. Each GPT partition entry in the GPT header has two GUIDs::

* PartitionTypeGUID
* UniquePartitionGUID

The PartitionTypeGUID value should correspond to the
``image_type_guid`` field of the FWU metadata. This field is used to
identify a given type of updatable firmware image, e.g. U-Boot,
OP-TEE, FIP etc. This GUID should also be used for specifying the
`--guid` parameter when generating the capsule.

The UniquePartitionGUID value should correspond to the ``image_guid``
field in the FWU metadata. This GUID is used to identify images of a
given image type in different banks.

The FWU specification defines the GUID value to be used for the
metadata partitions. This would be the PartitionTypeGUID for the
metadata partitions. Similarly, the UEFI specification defines the ESP
GUID to be be used.

When generating the metadata, the ``image_type_guid`` and the
``image_guid`` values should match the *PartitionTypeGUID* and the
*UniquePartitionGUID* values respectively.

Performing the Update
---------------------

Once the storage media has been partitioned and populated with the
metadata partitions, the UEFI capsule-on-disk update functionality can
be used for performing the update. Refer to the section
:ref:`uefi_capsule_update_ref` for details on how the update can be
invoked.

On a successful update, the FWU metadata gets updated to reflect the
bank from which the platform would be booting on subsequent boot.

Based on the value of bit15 of the Flags member of the capsule header,
the updated images would either be accepted by the U-Boot's UEFI
implementation, or by the Operating System. If the Operating System is
accepting the firmware images, it does so by generating an empty
*accept* capsule. The Operating System can also reject the updated
firmware by generating a *revert* capsule. The empty capsule can be
applied by using the exact same procedure used for performing the
capsule-on-disk update.

The task of accepting the different firmware images, post an update
may be done by multiple, separate components in the Operating
System. To help identify the firmware image that is being accepted,
the accept capsule passes the image GUID of the firmware image being
accepted. The relevant code in U-Boot then sets the Accept bit of the
corresponding firmware image for which the accept capsule was
found. Only when all the firmware components in a bank have been
accepted does the platform transition from trial state to regular
state.

The revert capsule on the other hand does not pass any image GUID,
since reverting any image of the bank has the same result of the
platform booting from the other bank on subsequent boot.

In the scenario that bit15 of the Flags member of the capsule header
has not been set, the images being updated are accepted by the
U-Boot's UEFI firmware implementation by default, on successful
update of the image.

Generating an empty capsule
---------------------------

The empty capsule can be generated using the mkeficapsule utility. To
build the tool, enable::

    CONFIG_TOOLS_MKEFICAPSULE=y

Run the following commands to generate the accept/revert capsules:

.. code-block:: bash

    $ ./tools/mkeficapsule \
      [--fw-accept --guid <image guid>] | \
      [--fw-revert] \
      <capsule_file_name>

Some examples of using the mkeficapsule tool for generation of the
empty capsule would be:

.. code-block:: bash

    $ ./tools/mkeficapsule --fw-accept --guid <image guid> \
    <accept_capsule_name>
    $ ./tools/mkeficapsule --fw-revert <revert_capsule_name>

Links
-----

* [1] https://developer.arm.com/documentation/den0118/ - FWU Specification
* [2] https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf - Dependable Boot Specification
