diff mbox series

[v5,23/23] sandbox: fwu: Add support for testing FWU feature on sandbox

Message ID 20220609123010.1017463-24-sughosh.ganu@linaro.org
State New
Headers show
Series FWU: Add FWU Multi Bank Update feature support | expand

Commit Message

Sughosh Ganu June 9, 2022, 12:30 p.m. UTC
Add a python test script for testing the FWU Multi Bank Update
functionality on the sandbox platform. The script has test cases for
updation of the u-boot binary and the u-boot environment image to the
non active bank.

The FWU metadata is being stored on the SPI NOR flash, along with the
updatable images, and the FWU metadata driver for MTD devices is being
used for accessing the metadata. Certain FWU boottime checks are
bypassed due to the unavailability of the EFI variable access very
early in the boot on the sandbox platform -- the variable access is
only available once the block disk image has been bound through the
host interface.

The FWU Multi Bank feature being enabled on the sandbox64 platform is
enabling the RAW Firmware Management Protocol(FMP) instance, therefore
the FIT FMP instance is being removed -- the FIT FMP is already being
tested on the sandbox flattree variant.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 arch/sandbox/Kconfig                          |   6 +
 arch/sandbox/dts/test.dts                     |  45 ++-
 board/sandbox/sandbox.c                       |  49 +++
 configs/sandbox64_defconfig                   |  12 +-
 include/fwu.h                                 |   2 +
 lib/fwu_updates/Kconfig                       |   2 +-
 lib/fwu_updates/fwu.c                         |  18 +-
 lib/fwu_updates/fwu_mtd.c                     |  10 +-
 .../test_capsule_firmware_fit.py              |   1 -
 .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
 test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
 .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
 12 files changed, 587 insertions(+), 13 deletions(-)
 create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
 create mode 100644 test/py/tests/test_fwu_updates/conftest.py
 create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py

Comments

AKASHI Takahiro June 15, 2022, 5:37 a.m. UTC | #1
On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> Add a python test script for testing the FWU Multi Bank Update
> functionality on the sandbox platform. The script has test cases for
> updation of the u-boot binary and the u-boot environment image to the
> non active bank.
> 
> The FWU metadata is being stored on the SPI NOR flash, along with the
> updatable images, and the FWU metadata driver for MTD devices is being
> used for accessing the metadata. Certain FWU boottime checks are
> bypassed due to the unavailability of the EFI variable access very
> early in the boot on the sandbox platform -- the variable access is
> only available once the block disk image has been bound through the
> host interface.
> 
> The FWU Multi Bank feature being enabled on the sandbox64 platform is
> enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> the FIT FMP instance is being removed -- the FIT FMP is already being
> tested on the sandbox flattree variant.

IMO,
Thinking of the importance of this feature, FIT FMP should also be
tested *with FWU*.

> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  arch/sandbox/Kconfig                          |   6 +
>  arch/sandbox/dts/test.dts                     |  45 ++-
>  board/sandbox/sandbox.c                       |  49 +++
>  configs/sandbox64_defconfig                   |  12 +-
>  include/fwu.h                                 |   2 +
>  lib/fwu_updates/Kconfig                       |   2 +-
>  lib/fwu_updates/fwu.c                         |  18 +-
>  lib/fwu_updates/fwu_mtd.c                     |  10 +-
>  .../test_capsule_firmware_fit.py              |   1 -
>  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
>  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
>  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
>  12 files changed, 587 insertions(+), 13 deletions(-)
>  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
>  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
>  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> 
> diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
> index 5f55c7f28e..2985572083 100644
> --- a/arch/sandbox/Kconfig
> +++ b/arch/sandbox/Kconfig
> @@ -84,3 +84,9 @@ config SYS_FDT_LOAD_ADDR
>  	  See `doc/arch/sandbox.rst` for more information.
>  
>  endmenu
> +
> +config FWU_NUM_BANKS
> +       default 2
> +
> +config FWU_NUM_IMAGES_PER_BANK
> +	default 2
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index 8f93775ff4..f11fa8733f 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -1145,11 +1145,48 @@
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&pinmux_spi0_pins>;
>  
> -		spi.bin@0 {
> +		spi0: spi.bin@0 {
>  			reg = <0>;
>  			compatible = "spansion,m25p16", "jedec,spi-nor";
>  			spi-max-frequency = <40000000>;
>  			sandbox,filename = "spi.bin";
> +
> +			partitions {
> +				compatible = "fixed-partitions";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				uuid = "af9e8c96-bec5-48be-9dab-3491c04b1366";
> +
> +				partition@0 {
> +					label = "Metadata";
> +					reg = <0x0 0x20000>;
> +				};
> +
> +				/* FWU Multi bank update partitions */
> +				partition@100000 {
> +					label = "U-Boot-Bank0";
> +					reg = <0x100000 0x10000>;
> +					uuid = "a8f61787-5d68-4c9d-9e4a-37bb0df99da7";
> +				};
> +
> +				partition@120000 {
> +					label = "U-Boot-ENV-Bank0";
> +					reg = <0x120000 0x10000>;
> +					uuid = "ea9d59af-e0e8-4ef5-9b16-4c80ff67524c";
> +				};
> +
> +				partition@140000 {
> +					label = "U-Boot-Bank1";
> +					reg = <0x140000 0x10000>;
> +					uuid = "52377abf-c4e4-4d0b-aafd-ba081a500847";
> +				};
> +
> +				partition@160000 {
> +					label = "U-Boot-ENV-Bank1";
> +					reg = <0x160000 0x10000>;
> +					uuid = "4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3";
> +				};
> +			};
>  		};
>  		spi.bin@1 {
>  			reg = <1>;
> @@ -1633,6 +1670,12 @@
>  			compatible = "sandbox,regmap_test";
>  		};
>  	};
> +
> +	fwu-mdata {
> +		compatible = "u-boot,fwu-mdata-mtd";
> +		fwu-mdata-store = <&spi0>;
> +		mdata-offsets = <0x0 0x10000>;
> +	};
>  };
>  
>  #include "sandbox_pmic.dtsi"
> diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
> index e054f300c4..222c36d301 100644
> --- a/board/sandbox/sandbox.c
> +++ b/board/sandbox/sandbox.c
> @@ -6,13 +6,18 @@
>  #include <common.h>
>  #include <cpu_func.h>
>  #include <cros_ec.h>
> +#include <dfu.h>
>  #include <dm.h>
>  #include <efi.h>
>  #include <efi_loader.h>
>  #include <env_internal.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
>  #include <init.h>
>  #include <led.h>
> +#include <mtd.h>
>  #include <os.h>
> +#include <uuid.h>
>  #include <asm/global_data.h>
>  #include <asm/test.h>
>  #include <asm/u-boot-sandbox.h>
> @@ -51,8 +56,15 @@ struct efi_fw_image fw_images[] = {
>  };
>  
>  struct efi_capsule_update_info update_info = {
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +	.dfu_string = "mtd nor0=u-boot-bin-a raw 0x100000 0x10000;"
> +		"u-boot-env-a raw 0x120000 0x10000;"
> +		"u-boot-bin-b raw 0x140000 0x10000;"
> +		"u-boot-env-b raw 0x160000 0x10000",
> +#else
>  	.dfu_string = "sf 0:0=u-boot-bin raw 0x100000 0x50000;"
>  		"u-boot-env raw 0x150000 0x200000",
> +#endif
>  	.images = fw_images,
>  };
>  
> @@ -155,3 +167,40 @@ int board_late_init(void)
>  	return 0;
>  }
>  #endif
> +
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
> +			 efi_guid_t *image_id, int *alt_num)
> +{
> +	return fwu_get_mtd_alt_num(image_id, alt_num, "nor0", 1);
> +}
> +
> +int fwu_plat_get_update_index(u32 *update_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +
> +	if (ret < 0)
> +		return -1;
> +
> +	*update_idx = active_idx ^= 0x1;
> +
> +	return ret;
> +}
> +
> +void fwu_plat_get_bootidx(void *boot_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +	u32 *bootidx = boot_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +
> +	if (ret < 0)
> +		*bootidx = -1;
> +
> +	*bootidx = active_idx;
> +}
> +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
> index d7f22b39ae..7a813b46a5 100644
> --- a/configs/sandbox64_defconfig
> +++ b/configs/sandbox64_defconfig
> @@ -244,9 +244,19 @@ CONFIG_LZ4=y
>  CONFIG_ERRNO_STR=y
>  CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
>  CONFIG_EFI_CAPSULE_ON_DISK=y
> -CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
>  CONFIG_EFI_SECURE_BOOT=y
>  CONFIG_TEST_FDTDEC=y
>  CONFIG_UNIT_TEST=y
>  CONFIG_UT_TIME=y
>  CONFIG_UT_DM=y
> +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
> +CONFIG_DM_FWU_MDATA=y
> +CONFIG_FWU_MULTI_BANK_UPDATE=y
> +CONFIG_FWU_MDATA_MTD=y
> +CONFIG_CMD_FWU_METADATA=y
> +CONFIG_TOOLS_MKFWUMDATA=y
> +CONFIG_DM_SPI_FLASH=y
> +CONFIG_CMD_MTD=y
> +CONFIG_DFU_MTD=y
> +CONFIG_DM_MTD=y
> +CONFIG_SPI_FLASH_MTD=y
> diff --git a/include/fwu.h b/include/fwu.h
> index fadbfedd07..9e550182eb 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -8,6 +8,8 @@
>  
>  #include <blk.h>
>  #include <efi.h>
> +#include <fwu_mdata.h>
> +#include <mtd.h>
>  
>  #include <linux/types.h>
>  
> diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> index 6de28e0c9c..43bed7729c 100644
> --- a/lib/fwu_updates/Kconfig
> +++ b/lib/fwu_updates/Kconfig
> @@ -2,7 +2,7 @@ config FWU_MULTI_BANK_UPDATE
>  	bool "Enable FWU Multi Bank Update Feature"
>  	depends on EFI_HAVE_CAPSULE_SUPPORT
>  	select PARTITION_TYPE_GUID
> -	select EFI_SETUP_EARLY
> +	select EFI_SETUP_EARLY if !SANDBOX
>  	help
>  	  Feature for updating firmware images on platforms having
>  	  multiple banks(copies) of the firmware images. One of the
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> index 422ef58661..f2c10d836b 100644
> --- a/lib/fwu_updates/fwu.c
> +++ b/lib/fwu_updates/fwu.c
> @@ -185,12 +185,22 @@ int fwu_boottime_checks(void)
>  		return 0;
>  	}
>  
> -	if (efi_init_obj_list() != EFI_SUCCESS)
> -		return 0;
> +	/*
> +	 * On the sandbox platform, the EFI variable
> +	 * access is available only after binding the
> +	 * disk image with the host interface. Skip
> +	 * the Trial State check on sandbox.
> +	 */
> +	if (!IS_ENABLED(CONFIG_SANDBOX)) {
> +		if (efi_init_obj_list() != EFI_SUCCESS)
> +			return 0;
>  
> -	ret = fwu_trial_state_check();
> -	if (!ret)
> +		ret = fwu_trial_state_check();
> +		if (!ret)
> +			boottime_check = 1;
> +	} else {
>  		boottime_check = 1;
> +	}
>  
>  	return 0;
>  }
> diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
> index 3137f8635c..3a9ad70203 100644
> --- a/lib/fwu_updates/fwu_mtd.c
> +++ b/lib/fwu_updates/fwu_mtd.c
> @@ -84,11 +84,11 @@ int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
>  int gen_image_alt_info(char *buf, size_t len, int sidx,
>  		       struct fwu_image_entry *img, struct mtd_info *mtd)
>  {
> -	char *p = buf, *end = buf + len;
> -	char uuidbuf[UUID_STR_LEN + 1];
> -	ofnode node, parts_node;
> -	const char *suuid;
>  	int i;
> +	const char *suuid;
> +	ofnode node, parts_node;
> +	char uuidbuf[UUID_STR_LEN + 1];
> +	char *p = buf, *end = buf + len;
>  
>  	/* Find partition node under given MTD device. */
>  	parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
> @@ -145,7 +145,7 @@ int gen_image_alt_info(char *buf, size_t len, int sidx,
>  
>  int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
>  {
> -	struct fwu_mdata *mdata;
> +	struct fwu_mdata *mdata = NULL;
>  	int i, l, ret;
>  
>  	ret = fwu_get_mdata(&mdata);
> diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> index 5bef84958b..93bc5ed44b 100644
> --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> @@ -13,7 +13,6 @@ import pytest
>  from capsule_defs import *
>  
>  
> -@pytest.mark.boardspec('sandbox64')
>  @pytest.mark.boardspec('sandbox_flattree')
>  @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
>  @pytest.mark.buildconfigspec('efi_capsule_on_disk')
> diff --git a/test/py/tests/test_fwu_updates/capsule_defs.py b/test/py/tests/test_fwu_updates/capsule_defs.py
> new file mode 100644
> index 0000000000..59b40f11bd
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/capsule_defs.py
> @@ -0,0 +1,10 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +
> +# Directories
> +CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
> +CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
> +
> +# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
> +# you need build a newer version on your own.
> +# The path must terminate with '/' if it is not null.
> +EFITOOLS_PATH = ''
> diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> new file mode 100644
> index 0000000000..cdf824c3be
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/conftest.py
> @@ -0,0 +1,78 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +# Copyright (c) 2020, Linaro Limited
> +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>

If this file is exactly same as test_efi_capsule/conftest.py,
why not move all the tests (test_fwu_updates.py) to test_efi_capsule?

The basic scenario of updating firmware, u-boot.bin and u-boot.env,
is also the same, isn't it? The only difference is whether FWU_MULTI_BANK_UPDATE
is enabled or not.

-Takahiro Akashi

> +
> +import os
> +import os.path
> +import re
> +from subprocess import call, check_call, check_output, CalledProcessError
> +import pytest
> +from capsule_defs import *
> +
> +#
> +# Fixture for UEFI capsule test
> +#
> +
> +@pytest.fixture(scope='session')
> +def efi_capsule_data(request, u_boot_config):
> +    """Set up a file system to be used in UEFI capsule and
> +       authentication test.
> +
> +    Args:
> +        request: Pytest request object.
> +        u_boot_config: U-boot configuration.
> +
> +    Return:
> +        A path to disk image to be used for testing
> +    """
> +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> +
> +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> +    data_dir = mnt_point + CAPSULE_DATA_DIR
> +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> +
> +    try:
> +        # Create a target device
> +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> +
> +        check_call('rm -rf %s' % mnt_point, shell=True)
> +        check_call('mkdir -p %s' % data_dir, shell=True)
> +        check_call('mkdir -p %s' % install_dir, shell=True)
> +
> +        # Create capsule files
> +        # two regions: one for u-boot.bin and the other for u-boot.env
> +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> +
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +
> +        # Create a disk image with EFI system partition
> +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> +                   (mnt_point, image_path), shell=True)
> +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> +                   image_path, shell=True)
> +
> +    except CalledProcessError as exception:
> +        pytest.skip('Setup failed: %s' % exception.cmd)
> +        return
> +    else:
> +        yield image_path
> +    finally:
> +        call('rm -rf %s' % mnt_point, shell=True)
> +        call('rm -f %s' % image_path, shell=True)
> +        call('rm -f ./spi.bin', shell=True)
> diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> new file mode 100644
> index 0000000000..d9dff3afaf
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> @@ -0,0 +1,367 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +# Copyright (c) 2022, Linaro Limited
> +#
> +# FWU Multi Bank Firmware Update Test
> +
> +"""
> +This test verifies FWU Multi Bank firmware update for raw images
> +"""
> +
> +from subprocess import check_call, check_output, CalledProcessError
> +import pytest
> +from capsule_defs import *
> +
> +
> +@pytest.mark.boardspec('sandbox64')
> +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> +@pytest.mark.buildconfigspec('dfu')
> +@pytest.mark.buildconfigspec('dfu_sf')
> +@pytest.mark.buildconfigspec('cmd_efidebug')
> +@pytest.mark.buildconfigspec('cmd_fat')
> +@pytest.mark.buildconfigspec('cmd_memory')
> +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> +@pytest.mark.buildconfigspec('cmd_sf')
> +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> +@pytest.mark.slow
> +class TestEfiCapsuleFirmwareRaw(object):
> +    def test_fwu_updates_fw1(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 $filesize',
> +                'sf write 4000000 10000 $filesize'])
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:New' in ''.join(output)
> +
> +    def test_fwu_updates_fw2(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 120000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 160000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 120000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 160000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 100',
> +                'sf write 4000000 10000 100'])
> +
> +            output = u_boot_console.run_command(
> +               'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +            assert 'Test02' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +            assert 'Test02' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 120000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 160000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-b:New' in ''.join(output)
> +
> +    def test_fwu_updates_fw3(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 120000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 160000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 120000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 160000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 100',
> +                'sf write 4000000 10000 100'])
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test03' in ''.join(output)
> +            assert 'Test04' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test03' in ''.join(output)
> +            assert 'Test04' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 120000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-a:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 160000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> -- 
> 2.25.1
>
AKASHI Takahiro June 15, 2022, 6:30 a.m. UTC | #2
On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> Add a python test script for testing the FWU Multi Bank Update
> functionality on the sandbox platform. The script has test cases for
> updation of the u-boot binary and the u-boot environment image to the
> non active bank.

IIUC, your test doesn't not exercise neither accept-capsule nor
revert capsule.
I think those tests are crucial for verifying the code.

-Takahiro Akashi

> The FWU metadata is being stored on the SPI NOR flash, along with the
> updatable images, and the FWU metadata driver for MTD devices is being
> used for accessing the metadata. Certain FWU boottime checks are
> bypassed due to the unavailability of the EFI variable access very
> early in the boot on the sandbox platform -- the variable access is
> only available once the block disk image has been bound through the
> host interface.
> 
> The FWU Multi Bank feature being enabled on the sandbox64 platform is
> enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> the FIT FMP instance is being removed -- the FIT FMP is already being
> tested on the sandbox flattree variant.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  arch/sandbox/Kconfig                          |   6 +
>  arch/sandbox/dts/test.dts                     |  45 ++-
>  board/sandbox/sandbox.c                       |  49 +++
>  configs/sandbox64_defconfig                   |  12 +-
>  include/fwu.h                                 |   2 +
>  lib/fwu_updates/Kconfig                       |   2 +-
>  lib/fwu_updates/fwu.c                         |  18 +-
>  lib/fwu_updates/fwu_mtd.c                     |  10 +-
>  .../test_capsule_firmware_fit.py              |   1 -
>  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
>  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
>  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
>  12 files changed, 587 insertions(+), 13 deletions(-)
>  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
>  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
>  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> 
> diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
> index 5f55c7f28e..2985572083 100644
> --- a/arch/sandbox/Kconfig
> +++ b/arch/sandbox/Kconfig
> @@ -84,3 +84,9 @@ config SYS_FDT_LOAD_ADDR
>  	  See `doc/arch/sandbox.rst` for more information.
>  
>  endmenu
> +
> +config FWU_NUM_BANKS
> +       default 2
> +
> +config FWU_NUM_IMAGES_PER_BANK
> +	default 2
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index 8f93775ff4..f11fa8733f 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -1145,11 +1145,48 @@
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&pinmux_spi0_pins>;
>  
> -		spi.bin@0 {
> +		spi0: spi.bin@0 {
>  			reg = <0>;
>  			compatible = "spansion,m25p16", "jedec,spi-nor";
>  			spi-max-frequency = <40000000>;
>  			sandbox,filename = "spi.bin";
> +
> +			partitions {
> +				compatible = "fixed-partitions";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				uuid = "af9e8c96-bec5-48be-9dab-3491c04b1366";
> +
> +				partition@0 {
> +					label = "Metadata";
> +					reg = <0x0 0x20000>;
> +				};
> +
> +				/* FWU Multi bank update partitions */
> +				partition@100000 {
> +					label = "U-Boot-Bank0";
> +					reg = <0x100000 0x10000>;
> +					uuid = "a8f61787-5d68-4c9d-9e4a-37bb0df99da7";
> +				};
> +
> +				partition@120000 {
> +					label = "U-Boot-ENV-Bank0";
> +					reg = <0x120000 0x10000>;
> +					uuid = "ea9d59af-e0e8-4ef5-9b16-4c80ff67524c";
> +				};
> +
> +				partition@140000 {
> +					label = "U-Boot-Bank1";
> +					reg = <0x140000 0x10000>;
> +					uuid = "52377abf-c4e4-4d0b-aafd-ba081a500847";
> +				};
> +
> +				partition@160000 {
> +					label = "U-Boot-ENV-Bank1";
> +					reg = <0x160000 0x10000>;
> +					uuid = "4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3";
> +				};
> +			};
>  		};
>  		spi.bin@1 {
>  			reg = <1>;
> @@ -1633,6 +1670,12 @@
>  			compatible = "sandbox,regmap_test";
>  		};
>  	};
> +
> +	fwu-mdata {
> +		compatible = "u-boot,fwu-mdata-mtd";
> +		fwu-mdata-store = <&spi0>;
> +		mdata-offsets = <0x0 0x10000>;
> +	};
>  };
>  
>  #include "sandbox_pmic.dtsi"
> diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
> index e054f300c4..222c36d301 100644
> --- a/board/sandbox/sandbox.c
> +++ b/board/sandbox/sandbox.c
> @@ -6,13 +6,18 @@
>  #include <common.h>
>  #include <cpu_func.h>
>  #include <cros_ec.h>
> +#include <dfu.h>
>  #include <dm.h>
>  #include <efi.h>
>  #include <efi_loader.h>
>  #include <env_internal.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
>  #include <init.h>
>  #include <led.h>
> +#include <mtd.h>
>  #include <os.h>
> +#include <uuid.h>
>  #include <asm/global_data.h>
>  #include <asm/test.h>
>  #include <asm/u-boot-sandbox.h>
> @@ -51,8 +56,15 @@ struct efi_fw_image fw_images[] = {
>  };
>  
>  struct efi_capsule_update_info update_info = {
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +	.dfu_string = "mtd nor0=u-boot-bin-a raw 0x100000 0x10000;"
> +		"u-boot-env-a raw 0x120000 0x10000;"
> +		"u-boot-bin-b raw 0x140000 0x10000;"
> +		"u-boot-env-b raw 0x160000 0x10000",
> +#else
>  	.dfu_string = "sf 0:0=u-boot-bin raw 0x100000 0x50000;"
>  		"u-boot-env raw 0x150000 0x200000",
> +#endif
>  	.images = fw_images,
>  };
>  
> @@ -155,3 +167,40 @@ int board_late_init(void)
>  	return 0;
>  }
>  #endif
> +
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
> +			 efi_guid_t *image_id, int *alt_num)
> +{
> +	return fwu_get_mtd_alt_num(image_id, alt_num, "nor0", 1);
> +}
> +
> +int fwu_plat_get_update_index(u32 *update_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +
> +	if (ret < 0)
> +		return -1;
> +
> +	*update_idx = active_idx ^= 0x1;
> +
> +	return ret;
> +}
> +
> +void fwu_plat_get_bootidx(void *boot_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +	u32 *bootidx = boot_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +
> +	if (ret < 0)
> +		*bootidx = -1;
> +
> +	*bootidx = active_idx;
> +}
> +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
> index d7f22b39ae..7a813b46a5 100644
> --- a/configs/sandbox64_defconfig
> +++ b/configs/sandbox64_defconfig
> @@ -244,9 +244,19 @@ CONFIG_LZ4=y
>  CONFIG_ERRNO_STR=y
>  CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
>  CONFIG_EFI_CAPSULE_ON_DISK=y
> -CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
>  CONFIG_EFI_SECURE_BOOT=y
>  CONFIG_TEST_FDTDEC=y
>  CONFIG_UNIT_TEST=y
>  CONFIG_UT_TIME=y
>  CONFIG_UT_DM=y
> +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
> +CONFIG_DM_FWU_MDATA=y
> +CONFIG_FWU_MULTI_BANK_UPDATE=y
> +CONFIG_FWU_MDATA_MTD=y
> +CONFIG_CMD_FWU_METADATA=y
> +CONFIG_TOOLS_MKFWUMDATA=y
> +CONFIG_DM_SPI_FLASH=y
> +CONFIG_CMD_MTD=y
> +CONFIG_DFU_MTD=y
> +CONFIG_DM_MTD=y
> +CONFIG_SPI_FLASH_MTD=y
> diff --git a/include/fwu.h b/include/fwu.h
> index fadbfedd07..9e550182eb 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -8,6 +8,8 @@
>  
>  #include <blk.h>
>  #include <efi.h>
> +#include <fwu_mdata.h>
> +#include <mtd.h>
>  
>  #include <linux/types.h>
>  
> diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> index 6de28e0c9c..43bed7729c 100644
> --- a/lib/fwu_updates/Kconfig
> +++ b/lib/fwu_updates/Kconfig
> @@ -2,7 +2,7 @@ config FWU_MULTI_BANK_UPDATE
>  	bool "Enable FWU Multi Bank Update Feature"
>  	depends on EFI_HAVE_CAPSULE_SUPPORT
>  	select PARTITION_TYPE_GUID
> -	select EFI_SETUP_EARLY
> +	select EFI_SETUP_EARLY if !SANDBOX
>  	help
>  	  Feature for updating firmware images on platforms having
>  	  multiple banks(copies) of the firmware images. One of the
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> index 422ef58661..f2c10d836b 100644
> --- a/lib/fwu_updates/fwu.c
> +++ b/lib/fwu_updates/fwu.c
> @@ -185,12 +185,22 @@ int fwu_boottime_checks(void)
>  		return 0;
>  	}
>  
> -	if (efi_init_obj_list() != EFI_SUCCESS)
> -		return 0;
> +	/*
> +	 * On the sandbox platform, the EFI variable
> +	 * access is available only after binding the
> +	 * disk image with the host interface. Skip
> +	 * the Trial State check on sandbox.
> +	 */
> +	if (!IS_ENABLED(CONFIG_SANDBOX)) {
> +		if (efi_init_obj_list() != EFI_SUCCESS)
> +			return 0;
>  
> -	ret = fwu_trial_state_check();
> -	if (!ret)
> +		ret = fwu_trial_state_check();
> +		if (!ret)
> +			boottime_check = 1;
> +	} else {
>  		boottime_check = 1;
> +	}
>  
>  	return 0;
>  }
> diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
> index 3137f8635c..3a9ad70203 100644
> --- a/lib/fwu_updates/fwu_mtd.c
> +++ b/lib/fwu_updates/fwu_mtd.c
> @@ -84,11 +84,11 @@ int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
>  int gen_image_alt_info(char *buf, size_t len, int sidx,
>  		       struct fwu_image_entry *img, struct mtd_info *mtd)
>  {
> -	char *p = buf, *end = buf + len;
> -	char uuidbuf[UUID_STR_LEN + 1];
> -	ofnode node, parts_node;
> -	const char *suuid;
>  	int i;
> +	const char *suuid;
> +	ofnode node, parts_node;
> +	char uuidbuf[UUID_STR_LEN + 1];
> +	char *p = buf, *end = buf + len;
>  
>  	/* Find partition node under given MTD device. */
>  	parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
> @@ -145,7 +145,7 @@ int gen_image_alt_info(char *buf, size_t len, int sidx,
>  
>  int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
>  {
> -	struct fwu_mdata *mdata;
> +	struct fwu_mdata *mdata = NULL;
>  	int i, l, ret;
>  
>  	ret = fwu_get_mdata(&mdata);
> diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> index 5bef84958b..93bc5ed44b 100644
> --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> @@ -13,7 +13,6 @@ import pytest
>  from capsule_defs import *
>  
>  
> -@pytest.mark.boardspec('sandbox64')
>  @pytest.mark.boardspec('sandbox_flattree')
>  @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
>  @pytest.mark.buildconfigspec('efi_capsule_on_disk')
> diff --git a/test/py/tests/test_fwu_updates/capsule_defs.py b/test/py/tests/test_fwu_updates/capsule_defs.py
> new file mode 100644
> index 0000000000..59b40f11bd
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/capsule_defs.py
> @@ -0,0 +1,10 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +
> +# Directories
> +CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
> +CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
> +
> +# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
> +# you need build a newer version on your own.
> +# The path must terminate with '/' if it is not null.
> +EFITOOLS_PATH = ''
> diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> new file mode 100644
> index 0000000000..cdf824c3be
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/conftest.py
> @@ -0,0 +1,78 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +# Copyright (c) 2020, Linaro Limited
> +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> +
> +import os
> +import os.path
> +import re
> +from subprocess import call, check_call, check_output, CalledProcessError
> +import pytest
> +from capsule_defs import *
> +
> +#
> +# Fixture for UEFI capsule test
> +#
> +
> +@pytest.fixture(scope='session')
> +def efi_capsule_data(request, u_boot_config):
> +    """Set up a file system to be used in UEFI capsule and
> +       authentication test.
> +
> +    Args:
> +        request: Pytest request object.
> +        u_boot_config: U-boot configuration.
> +
> +    Return:
> +        A path to disk image to be used for testing
> +    """
> +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> +
> +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> +    data_dir = mnt_point + CAPSULE_DATA_DIR
> +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> +
> +    try:
> +        # Create a target device
> +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> +
> +        check_call('rm -rf %s' % mnt_point, shell=True)
> +        check_call('mkdir -p %s' % data_dir, shell=True)
> +        check_call('mkdir -p %s' % install_dir, shell=True)
> +
> +        # Create capsule files
> +        # two regions: one for u-boot.bin and the other for u-boot.env
> +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> +
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +
> +        # Create a disk image with EFI system partition
> +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> +                   (mnt_point, image_path), shell=True)
> +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> +                   image_path, shell=True)
> +
> +    except CalledProcessError as exception:
> +        pytest.skip('Setup failed: %s' % exception.cmd)
> +        return
> +    else:
> +        yield image_path
> +    finally:
> +        call('rm -rf %s' % mnt_point, shell=True)
> +        call('rm -f %s' % image_path, shell=True)
> +        call('rm -f ./spi.bin', shell=True)
> diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> new file mode 100644
> index 0000000000..d9dff3afaf
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> @@ -0,0 +1,367 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +# Copyright (c) 2022, Linaro Limited
> +#
> +# FWU Multi Bank Firmware Update Test
> +
> +"""
> +This test verifies FWU Multi Bank firmware update for raw images
> +"""
> +
> +from subprocess import check_call, check_output, CalledProcessError
> +import pytest
> +from capsule_defs import *
> +
> +
> +@pytest.mark.boardspec('sandbox64')
> +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> +@pytest.mark.buildconfigspec('dfu')
> +@pytest.mark.buildconfigspec('dfu_sf')
> +@pytest.mark.buildconfigspec('cmd_efidebug')
> +@pytest.mark.buildconfigspec('cmd_fat')
> +@pytest.mark.buildconfigspec('cmd_memory')
> +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> +@pytest.mark.buildconfigspec('cmd_sf')
> +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> +@pytest.mark.slow
> +class TestEfiCapsuleFirmwareRaw(object):
> +    def test_fwu_updates_fw1(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 $filesize',
> +                'sf write 4000000 10000 $filesize'])
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:New' in ''.join(output)
> +
> +    def test_fwu_updates_fw2(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 120000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 160000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 120000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 160000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 100',
> +                'sf write 4000000 10000 100'])
> +
> +            output = u_boot_console.run_command(
> +               'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +            assert 'Test02' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +            assert 'Test02' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 120000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 160000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-b:New' in ''.join(output)
> +
> +    def test_fwu_updates_fw3(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 120000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 160000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 120000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 160000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 100',
> +                'sf write 4000000 10000 100'])
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test03' in ''.join(output)
> +            assert 'Test04' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test03' in ''.join(output)
> +            assert 'Test04' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 120000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-a:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 160000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> -- 
> 2.25.1
>
Sughosh Ganu June 15, 2022, 12:10 p.m. UTC | #3
On Wed, 15 Jun 2022 at 11:07, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> > Add a python test script for testing the FWU Multi Bank Update
> > functionality on the sandbox platform. The script has test cases for
> > updation of the u-boot binary and the u-boot environment image to the
> > non active bank.
> >
> > The FWU metadata is being stored on the SPI NOR flash, along with the
> > updatable images, and the FWU metadata driver for MTD devices is being
> > used for accessing the metadata. Certain FWU boottime checks are
> > bypassed due to the unavailability of the EFI variable access very
> > early in the boot on the sandbox platform -- the variable access is
> > only available once the block disk image has been bound through the
> > host interface.
> >
> > The FWU Multi Bank feature being enabled on the sandbox64 platform is
> > enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> > the FIT FMP instance is being removed -- the FIT FMP is already being
> > tested on the sandbox flattree variant.
>
> IMO,
> Thinking of the importance of this feature, FIT FMP should also be
> tested *with FWU*.

How will the FWU update feature work for FIT images? As I understand
FIT, it is a way of packaging different firmware images into a single
package. At the time of writing the images, the FIT image parser would
check the image configuration, and write the images to their
respective locations. As you are aware, for the FWU feature, the
information about the images, and the update bank is obtained from the
structure called metadata. How does the FIT update mechanism map with
the FWU metadata which is used to identify which bank needs to be
updated. The bank to which the image is to be written translates into
the DFU alt_num value for that image, and this gets computed at
runtime. In the case of the FIT image, as per my understanding, the
alt_num value is irrelevant. So my question is, how do we map the
information obtained from the FWU metadata to tell the FIT image
writing function(fit_update) which locations do the images need to be
written to. I think this needs some more thought.

>
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  arch/sandbox/Kconfig                          |   6 +
> >  arch/sandbox/dts/test.dts                     |  45 ++-
> >  board/sandbox/sandbox.c                       |  49 +++
> >  configs/sandbox64_defconfig                   |  12 +-
> >  include/fwu.h                                 |   2 +
> >  lib/fwu_updates/Kconfig                       |   2 +-
> >  lib/fwu_updates/fwu.c                         |  18 +-
> >  lib/fwu_updates/fwu_mtd.c                     |  10 +-
> >  .../test_capsule_firmware_fit.py              |   1 -
> >  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> >  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
> >  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
> >  12 files changed, 587 insertions(+), 13 deletions(-)
> >  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> >  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> >  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> >

<snip>

> > diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> > new file mode 100644
> > index 0000000000..cdf824c3be
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/conftest.py
> > @@ -0,0 +1,78 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +# Copyright (c) 2020, Linaro Limited
> > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
>
> If this file is exactly same as test_efi_capsule/conftest.py,
> why not move all the tests (test_fwu_updates.py) to test_efi_capsule?

The files are not exactly the same. There is use of the mkfwumdata
utility used for FWU tests, along with the capsule files that are
being generated. I had tried putting the code under the
test_efi_capsule directory, but the result was getting cluttered.
Which is why I decided to put the changes separately under the
test_fwu_updates directory.

>
> The basic scenario of updating firmware, u-boot.bin and u-boot.env,
> is also the same, isn't it? The only difference is whether FWU_MULTI_BANK_UPDATE
> is enabled or not.

There are two capsule files per image, one per bank. Also, the FWU
metadata is being written to the SPI NOR device, which is being
formatted as a MTD partitioned device. The underlying update mechanism
is the same, yes.

-sughosh

>
> -Takahiro Akashi
>
> > +
> > +import os
> > +import os.path
> > +import re
> > +from subprocess import call, check_call, check_output, CalledProcessError
> > +import pytest
> > +from capsule_defs import *
> > +
> > +#
> > +# Fixture for UEFI capsule test
> > +#
> > +
> > +@pytest.fixture(scope='session')
> > +def efi_capsule_data(request, u_boot_config):
> > +    """Set up a file system to be used in UEFI capsule and
> > +       authentication test.
> > +
> > +    Args:
> > +        request: Pytest request object.
> > +        u_boot_config: U-boot configuration.
> > +
> > +    Return:
> > +        A path to disk image to be used for testing
> > +    """
> > +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> > +
> > +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> > +    data_dir = mnt_point + CAPSULE_DATA_DIR
> > +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> > +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> > +
> > +    try:
> > +        # Create a target device
> > +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> > +
> > +        check_call('rm -rf %s' % mnt_point, shell=True)
> > +        check_call('mkdir -p %s' % data_dir, shell=True)
> > +        check_call('mkdir -p %s' % install_dir, shell=True)
> > +
> > +        # Create capsule files
> > +        # two regions: one for u-boot.bin and the other for u-boot.env
> > +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > +
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +
> > +        # Create a disk image with EFI system partition
> > +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> > +                   (mnt_point, image_path), shell=True)
> > +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> > +                   image_path, shell=True)
> > +
> > +    except CalledProcessError as exception:
> > +        pytest.skip('Setup failed: %s' % exception.cmd)
> > +        return
> > +    else:
> > +        yield image_path
> > +    finally:
> > +        call('rm -rf %s' % mnt_point, shell=True)
> > +        call('rm -f %s' % image_path, shell=True)
> > +        call('rm -f ./spi.bin', shell=True)
> > diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > new file mode 100644
> > index 0000000000..d9dff3afaf
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > @@ -0,0 +1,367 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +# Copyright (c) 2022, Linaro Limited
> > +#
> > +# FWU Multi Bank Firmware Update Test
> > +
> > +"""
> > +This test verifies FWU Multi Bank firmware update for raw images
> > +"""
> > +
> > +from subprocess import check_call, check_output, CalledProcessError
> > +import pytest
> > +from capsule_defs import *
> > +
> > +
> > +@pytest.mark.boardspec('sandbox64')
> > +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> > +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > +@pytest.mark.buildconfigspec('dfu')
> > +@pytest.mark.buildconfigspec('dfu_sf')
> > +@pytest.mark.buildconfigspec('cmd_efidebug')
> > +@pytest.mark.buildconfigspec('cmd_fat')
> > +@pytest.mark.buildconfigspec('cmd_memory')
> > +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> > +@pytest.mark.buildconfigspec('cmd_sf')
> > +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> > +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> > +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> > +@pytest.mark.slow
> > +class TestEfiCapsuleFirmwareRaw(object):
> > +    def test_fwu_updates_fw1(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> > +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> > +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 $filesize',
> > +                'sf write 4000000 10000 $filesize'])
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:New' in ''.join(output)
> > +
> > +    def test_fwu_updates_fw2(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 120000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 160000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 120000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 160000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 100',
> > +                'sf write 4000000 10000 100'])
> > +
> > +            output = u_boot_console.run_command(
> > +               'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +            assert 'Test02' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +            assert 'Test02' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 120000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 160000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-b:New' in ''.join(output)
> > +
> > +    def test_fwu_updates_fw3(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 120000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 160000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 120000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 160000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 100',
> > +                'sf write 4000000 10000 100'])
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test03' in ''.join(output)
> > +            assert 'Test04' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test03' in ''.join(output)
> > +            assert 'Test04' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 120000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-a:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 160000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > --
> > 2.25.1
> >
Sughosh Ganu June 15, 2022, 12:13 p.m. UTC | #4
On Wed, 15 Jun 2022 at 12:00, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> > Add a python test script for testing the FWU Multi Bank Update
> > functionality on the sandbox platform. The script has test cases for
> > updation of the u-boot binary and the u-boot environment image to the
> > non active bank.
>
> IIUC, your test doesn't not exercise neither accept-capsule nor
> revert capsule.
> I think those tests are crucial for verifying the code.

Yes, this is on my todo list. By default, all the images get accepted
by the firmware itself, which is being done in u-boot. In case the
oemflag bit 15 is set to 1 in the capsule header, the image acceptance
is done through the accept capsule. I will need to add support for
passing the oemflag parameter to the mkeficapsule, and then I can test
this. Will keep this on my todo list, and try to put it in the
upcoming versions.

-sughosh

>
> -Takahiro Akashi
>
> > The FWU metadata is being stored on the SPI NOR flash, along with the
> > updatable images, and the FWU metadata driver for MTD devices is being
> > used for accessing the metadata. Certain FWU boottime checks are
> > bypassed due to the unavailability of the EFI variable access very
> > early in the boot on the sandbox platform -- the variable access is
> > only available once the block disk image has been bound through the
> > host interface.
> >
> > The FWU Multi Bank feature being enabled on the sandbox64 platform is
> > enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> > the FIT FMP instance is being removed -- the FIT FMP is already being
> > tested on the sandbox flattree variant.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  arch/sandbox/Kconfig                          |   6 +
> >  arch/sandbox/dts/test.dts                     |  45 ++-
> >  board/sandbox/sandbox.c                       |  49 +++
> >  configs/sandbox64_defconfig                   |  12 +-
> >  include/fwu.h                                 |   2 +
> >  lib/fwu_updates/Kconfig                       |   2 +-
> >  lib/fwu_updates/fwu.c                         |  18 +-
> >  lib/fwu_updates/fwu_mtd.c                     |  10 +-
> >  .../test_capsule_firmware_fit.py              |   1 -
> >  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> >  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
> >  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
> >  12 files changed, 587 insertions(+), 13 deletions(-)
> >  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> >  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> >  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> >
> > diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
> > index 5f55c7f28e..2985572083 100644
> > --- a/arch/sandbox/Kconfig
> > +++ b/arch/sandbox/Kconfig
> > @@ -84,3 +84,9 @@ config SYS_FDT_LOAD_ADDR
> >         See `doc/arch/sandbox.rst` for more information.
> >
> >  endmenu
> > +
> > +config FWU_NUM_BANKS
> > +       default 2
> > +
> > +config FWU_NUM_IMAGES_PER_BANK
> > +     default 2
> > diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> > index 8f93775ff4..f11fa8733f 100644
> > --- a/arch/sandbox/dts/test.dts
> > +++ b/arch/sandbox/dts/test.dts
> > @@ -1145,11 +1145,48 @@
> >               pinctrl-names = "default";
> >               pinctrl-0 = <&pinmux_spi0_pins>;
> >
> > -             spi.bin@0 {
> > +             spi0: spi.bin@0 {
> >                       reg = <0>;
> >                       compatible = "spansion,m25p16", "jedec,spi-nor";
> >                       spi-max-frequency = <40000000>;
> >                       sandbox,filename = "spi.bin";
> > +
> > +                     partitions {
> > +                             compatible = "fixed-partitions";
> > +                             #address-cells = <1>;
> > +                             #size-cells = <1>;
> > +                             uuid = "af9e8c96-bec5-48be-9dab-3491c04b1366";
> > +
> > +                             partition@0 {
> > +                                     label = "Metadata";
> > +                                     reg = <0x0 0x20000>;
> > +                             };
> > +
> > +                             /* FWU Multi bank update partitions */
> > +                             partition@100000 {
> > +                                     label = "U-Boot-Bank0";
> > +                                     reg = <0x100000 0x10000>;
> > +                                     uuid = "a8f61787-5d68-4c9d-9e4a-37bb0df99da7";
> > +                             };
> > +
> > +                             partition@120000 {
> > +                                     label = "U-Boot-ENV-Bank0";
> > +                                     reg = <0x120000 0x10000>;
> > +                                     uuid = "ea9d59af-e0e8-4ef5-9b16-4c80ff67524c";
> > +                             };
> > +
> > +                             partition@140000 {
> > +                                     label = "U-Boot-Bank1";
> > +                                     reg = <0x140000 0x10000>;
> > +                                     uuid = "52377abf-c4e4-4d0b-aafd-ba081a500847";
> > +                             };
> > +
> > +                             partition@160000 {
> > +                                     label = "U-Boot-ENV-Bank1";
> > +                                     reg = <0x160000 0x10000>;
> > +                                     uuid = "4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3";
> > +                             };
> > +                     };
> >               };
> >               spi.bin@1 {
> >                       reg = <1>;
> > @@ -1633,6 +1670,12 @@
> >                       compatible = "sandbox,regmap_test";
> >               };
> >       };
> > +
> > +     fwu-mdata {
> > +             compatible = "u-boot,fwu-mdata-mtd";
> > +             fwu-mdata-store = <&spi0>;
> > +             mdata-offsets = <0x0 0x10000>;
> > +     };
> >  };
> >
> >  #include "sandbox_pmic.dtsi"
> > diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
> > index e054f300c4..222c36d301 100644
> > --- a/board/sandbox/sandbox.c
> > +++ b/board/sandbox/sandbox.c
> > @@ -6,13 +6,18 @@
> >  #include <common.h>
> >  #include <cpu_func.h>
> >  #include <cros_ec.h>
> > +#include <dfu.h>
> >  #include <dm.h>
> >  #include <efi.h>
> >  #include <efi_loader.h>
> >  #include <env_internal.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> >  #include <init.h>
> >  #include <led.h>
> > +#include <mtd.h>
> >  #include <os.h>
> > +#include <uuid.h>
> >  #include <asm/global_data.h>
> >  #include <asm/test.h>
> >  #include <asm/u-boot-sandbox.h>
> > @@ -51,8 +56,15 @@ struct efi_fw_image fw_images[] = {
> >  };
> >
> >  struct efi_capsule_update_info update_info = {
> > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > +     .dfu_string = "mtd nor0=u-boot-bin-a raw 0x100000 0x10000;"
> > +             "u-boot-env-a raw 0x120000 0x10000;"
> > +             "u-boot-bin-b raw 0x140000 0x10000;"
> > +             "u-boot-env-b raw 0x160000 0x10000",
> > +#else
> >       .dfu_string = "sf 0:0=u-boot-bin raw 0x100000 0x50000;"
> >               "u-boot-env raw 0x150000 0x200000",
> > +#endif
> >       .images = fw_images,
> >  };
> >
> > @@ -155,3 +167,40 @@ int board_late_init(void)
> >       return 0;
> >  }
> >  #endif
> > +
> > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > +int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
> > +                      efi_guid_t *image_id, int *alt_num)
> > +{
> > +     return fwu_get_mtd_alt_num(image_id, alt_num, "nor0", 1);
> > +}
> > +
> > +int fwu_plat_get_update_index(u32 *update_idx)
> > +{
> > +     int ret;
> > +     u32 active_idx;
> > +
> > +     ret = fwu_get_active_index(&active_idx);
> > +
> > +     if (ret < 0)
> > +             return -1;
> > +
> > +     *update_idx = active_idx ^= 0x1;
> > +
> > +     return ret;
> > +}
> > +
> > +void fwu_plat_get_bootidx(void *boot_idx)
> > +{
> > +     int ret;
> > +     u32 active_idx;
> > +     u32 *bootidx = boot_idx;
> > +
> > +     ret = fwu_get_active_index(&active_idx);
> > +
> > +     if (ret < 0)
> > +             *bootidx = -1;
> > +
> > +     *bootidx = active_idx;
> > +}
> > +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> > diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
> > index d7f22b39ae..7a813b46a5 100644
> > --- a/configs/sandbox64_defconfig
> > +++ b/configs/sandbox64_defconfig
> > @@ -244,9 +244,19 @@ CONFIG_LZ4=y
> >  CONFIG_ERRNO_STR=y
> >  CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
> >  CONFIG_EFI_CAPSULE_ON_DISK=y
> > -CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
> >  CONFIG_EFI_SECURE_BOOT=y
> >  CONFIG_TEST_FDTDEC=y
> >  CONFIG_UNIT_TEST=y
> >  CONFIG_UT_TIME=y
> >  CONFIG_UT_DM=y
> > +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
> > +CONFIG_DM_FWU_MDATA=y
> > +CONFIG_FWU_MULTI_BANK_UPDATE=y
> > +CONFIG_FWU_MDATA_MTD=y
> > +CONFIG_CMD_FWU_METADATA=y
> > +CONFIG_TOOLS_MKFWUMDATA=y
> > +CONFIG_DM_SPI_FLASH=y
> > +CONFIG_CMD_MTD=y
> > +CONFIG_DFU_MTD=y
> > +CONFIG_DM_MTD=y
> > +CONFIG_SPI_FLASH_MTD=y
> > diff --git a/include/fwu.h b/include/fwu.h
> > index fadbfedd07..9e550182eb 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -8,6 +8,8 @@
> >
> >  #include <blk.h>
> >  #include <efi.h>
> > +#include <fwu_mdata.h>
> > +#include <mtd.h>
> >
> >  #include <linux/types.h>
> >
> > diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> > index 6de28e0c9c..43bed7729c 100644
> > --- a/lib/fwu_updates/Kconfig
> > +++ b/lib/fwu_updates/Kconfig
> > @@ -2,7 +2,7 @@ config FWU_MULTI_BANK_UPDATE
> >       bool "Enable FWU Multi Bank Update Feature"
> >       depends on EFI_HAVE_CAPSULE_SUPPORT
> >       select PARTITION_TYPE_GUID
> > -     select EFI_SETUP_EARLY
> > +     select EFI_SETUP_EARLY if !SANDBOX
> >       help
> >         Feature for updating firmware images on platforms having
> >         multiple banks(copies) of the firmware images. One of the
> > diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> > index 422ef58661..f2c10d836b 100644
> > --- a/lib/fwu_updates/fwu.c
> > +++ b/lib/fwu_updates/fwu.c
> > @@ -185,12 +185,22 @@ int fwu_boottime_checks(void)
> >               return 0;
> >       }
> >
> > -     if (efi_init_obj_list() != EFI_SUCCESS)
> > -             return 0;
> > +     /*
> > +      * On the sandbox platform, the EFI variable
> > +      * access is available only after binding the
> > +      * disk image with the host interface. Skip
> > +      * the Trial State check on sandbox.
> > +      */
> > +     if (!IS_ENABLED(CONFIG_SANDBOX)) {
> > +             if (efi_init_obj_list() != EFI_SUCCESS)
> > +                     return 0;
> >
> > -     ret = fwu_trial_state_check();
> > -     if (!ret)
> > +             ret = fwu_trial_state_check();
> > +             if (!ret)
> > +                     boottime_check = 1;
> > +     } else {
> >               boottime_check = 1;
> > +     }
> >
> >       return 0;
> >  }
> > diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
> > index 3137f8635c..3a9ad70203 100644
> > --- a/lib/fwu_updates/fwu_mtd.c
> > +++ b/lib/fwu_updates/fwu_mtd.c
> > @@ -84,11 +84,11 @@ int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
> >  int gen_image_alt_info(char *buf, size_t len, int sidx,
> >                      struct fwu_image_entry *img, struct mtd_info *mtd)
> >  {
> > -     char *p = buf, *end = buf + len;
> > -     char uuidbuf[UUID_STR_LEN + 1];
> > -     ofnode node, parts_node;
> > -     const char *suuid;
> >       int i;
> > +     const char *suuid;
> > +     ofnode node, parts_node;
> > +     char uuidbuf[UUID_STR_LEN + 1];
> > +     char *p = buf, *end = buf + len;
> >
> >       /* Find partition node under given MTD device. */
> >       parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
> > @@ -145,7 +145,7 @@ int gen_image_alt_info(char *buf, size_t len, int sidx,
> >
> >  int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
> >  {
> > -     struct fwu_mdata *mdata;
> > +     struct fwu_mdata *mdata = NULL;
> >       int i, l, ret;
> >
> >       ret = fwu_get_mdata(&mdata);
> > diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> > index 5bef84958b..93bc5ed44b 100644
> > --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> > +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> > @@ -13,7 +13,6 @@ import pytest
> >  from capsule_defs import *
> >
> >
> > -@pytest.mark.boardspec('sandbox64')
> >  @pytest.mark.boardspec('sandbox_flattree')
> >  @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
> >  @pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > diff --git a/test/py/tests/test_fwu_updates/capsule_defs.py b/test/py/tests/test_fwu_updates/capsule_defs.py
> > new file mode 100644
> > index 0000000000..59b40f11bd
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/capsule_defs.py
> > @@ -0,0 +1,10 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +
> > +# Directories
> > +CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
> > +CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
> > +
> > +# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
> > +# you need build a newer version on your own.
> > +# The path must terminate with '/' if it is not null.
> > +EFITOOLS_PATH = ''
> > diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> > new file mode 100644
> > index 0000000000..cdf824c3be
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/conftest.py
> > @@ -0,0 +1,78 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +# Copyright (c) 2020, Linaro Limited
> > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > +
> > +import os
> > +import os.path
> > +import re
> > +from subprocess import call, check_call, check_output, CalledProcessError
> > +import pytest
> > +from capsule_defs import *
> > +
> > +#
> > +# Fixture for UEFI capsule test
> > +#
> > +
> > +@pytest.fixture(scope='session')
> > +def efi_capsule_data(request, u_boot_config):
> > +    """Set up a file system to be used in UEFI capsule and
> > +       authentication test.
> > +
> > +    Args:
> > +        request: Pytest request object.
> > +        u_boot_config: U-boot configuration.
> > +
> > +    Return:
> > +        A path to disk image to be used for testing
> > +    """
> > +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> > +
> > +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> > +    data_dir = mnt_point + CAPSULE_DATA_DIR
> > +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> > +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> > +
> > +    try:
> > +        # Create a target device
> > +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> > +
> > +        check_call('rm -rf %s' % mnt_point, shell=True)
> > +        check_call('mkdir -p %s' % data_dir, shell=True)
> > +        check_call('mkdir -p %s' % install_dir, shell=True)
> > +
> > +        # Create capsule files
> > +        # two regions: one for u-boot.bin and the other for u-boot.env
> > +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > +
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +
> > +        # Create a disk image with EFI system partition
> > +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> > +                   (mnt_point, image_path), shell=True)
> > +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> > +                   image_path, shell=True)
> > +
> > +    except CalledProcessError as exception:
> > +        pytest.skip('Setup failed: %s' % exception.cmd)
> > +        return
> > +    else:
> > +        yield image_path
> > +    finally:
> > +        call('rm -rf %s' % mnt_point, shell=True)
> > +        call('rm -f %s' % image_path, shell=True)
> > +        call('rm -f ./spi.bin', shell=True)
> > diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > new file mode 100644
> > index 0000000000..d9dff3afaf
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > @@ -0,0 +1,367 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +# Copyright (c) 2022, Linaro Limited
> > +#
> > +# FWU Multi Bank Firmware Update Test
> > +
> > +"""
> > +This test verifies FWU Multi Bank firmware update for raw images
> > +"""
> > +
> > +from subprocess import check_call, check_output, CalledProcessError
> > +import pytest
> > +from capsule_defs import *
> > +
> > +
> > +@pytest.mark.boardspec('sandbox64')
> > +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> > +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > +@pytest.mark.buildconfigspec('dfu')
> > +@pytest.mark.buildconfigspec('dfu_sf')
> > +@pytest.mark.buildconfigspec('cmd_efidebug')
> > +@pytest.mark.buildconfigspec('cmd_fat')
> > +@pytest.mark.buildconfigspec('cmd_memory')
> > +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> > +@pytest.mark.buildconfigspec('cmd_sf')
> > +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> > +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> > +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> > +@pytest.mark.slow
> > +class TestEfiCapsuleFirmwareRaw(object):
> > +    def test_fwu_updates_fw1(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> > +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> > +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 $filesize',
> > +                'sf write 4000000 10000 $filesize'])
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:New' in ''.join(output)
> > +
> > +    def test_fwu_updates_fw2(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 120000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 160000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 120000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 160000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 100',
> > +                'sf write 4000000 10000 100'])
> > +
> > +            output = u_boot_console.run_command(
> > +               'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +            assert 'Test02' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +            assert 'Test02' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 120000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 160000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-b:New' in ''.join(output)
> > +
> > +    def test_fwu_updates_fw3(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 120000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 160000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 120000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 160000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 100',
> > +                'sf write 4000000 10000 100'])
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test03' in ''.join(output)
> > +            assert 'Test04' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test03' in ''.join(output)
> > +            assert 'Test04' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 120000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-a:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 160000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > --
> > 2.25.1
> >
AKASHI Takahiro June 17, 2022, 1:08 a.m. UTC | #5
Sughosh,

On Wed, Jun 15, 2022 at 05:40:12PM +0530, Sughosh Ganu wrote:
> On Wed, 15 Jun 2022 at 11:07, Takahiro Akashi
> <takahiro.akashi@linaro.org> wrote:
> >
> > On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> > > Add a python test script for testing the FWU Multi Bank Update
> > > functionality on the sandbox platform. The script has test cases for
> > > updation of the u-boot binary and the u-boot environment image to the
> > > non active bank.
> > >
> > > The FWU metadata is being stored on the SPI NOR flash, along with the
> > > updatable images, and the FWU metadata driver for MTD devices is being
> > > used for accessing the metadata. Certain FWU boottime checks are
> > > bypassed due to the unavailability of the EFI variable access very
> > > early in the boot on the sandbox platform -- the variable access is
> > > only available once the block disk image has been bound through the
> > > host interface.
> > >
> > > The FWU Multi Bank feature being enabled on the sandbox64 platform is
> > > enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> > > the FIT FMP instance is being removed -- the FIT FMP is already being
> > > tested on the sandbox flattree variant.
> >
> > IMO,
> > Thinking of the importance of this feature, FIT FMP should also be
> > tested *with FWU*.
> 
> How will the FWU update feature work for FIT images? As I understand

So are you deliberately designing and proposing a solution that is
incompatible with (or not applicable to) an existing interface (FIT FMP)?

> FIT, it is a way of packaging different firmware images into a single
> package. At the time of writing the images, the FIT image parser would
> check the image configuration, and write the images to their
> respective locations. As you are aware, for the FWU feature, the
> information about the images, and the update bank is obtained from the
> structure called metadata. How does the FIT update mechanism map with
> the FWU metadata which is used to identify which bank needs to be
> updated. The bank to which the image is to be written translates into
> the DFU alt_num value for that image, and this gets computed at
> runtime. In the case of the FIT image, as per my understanding, the
> alt_num value is irrelevant. So my question is, how do we map the
> information obtained from the FWU metadata to tell the FIT image
> writing function(fit_update) which locations do the images need to be
> written to. I think this needs some more thought.
> 
> >
> > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > ---
> > >  arch/sandbox/Kconfig                          |   6 +
> > >  arch/sandbox/dts/test.dts                     |  45 ++-
> > >  board/sandbox/sandbox.c                       |  49 +++
> > >  configs/sandbox64_defconfig                   |  12 +-
> > >  include/fwu.h                                 |   2 +
> > >  lib/fwu_updates/Kconfig                       |   2 +-
> > >  lib/fwu_updates/fwu.c                         |  18 +-
> > >  lib/fwu_updates/fwu_mtd.c                     |  10 +-
> > >  .../test_capsule_firmware_fit.py              |   1 -
> > >  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> > >  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
> > >  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
> > >  12 files changed, 587 insertions(+), 13 deletions(-)
> > >  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> > >  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> > >  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> > >
> 
> <snip>
> 
> > > diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> > > new file mode 100644
> > > index 0000000000..cdf824c3be
> > > --- /dev/null
> > > +++ b/test/py/tests/test_fwu_updates/conftest.py
> > > @@ -0,0 +1,78 @@
> > > +# SPDX-License-Identifier:      GPL-2.0+
> > > +# Copyright (c) 2020, Linaro Limited
> > > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >
> > If this file is exactly same as test_efi_capsule/conftest.py,
> > why not move all the tests (test_fwu_updates.py) to test_efi_capsule?
> 
> The files are not exactly the same. There is use of the mkfwumdata
> utility used for FWU tests, along with the capsule files that are
> being generated. I had tried putting the code under the
> test_efi_capsule directory, but the result was getting cluttered.

Okay, but from my curiosity, how cluttered was it?
It seems to me that you are simply adding extra setup steps.

My simple concern is that, if there is a fair amount of common code
between two tests, it should be unified for maintainability.

-Takahiro Akashi

> Which is why I decided to put the changes separately under the
> test_fwu_updates directory.
> 
> >
> > The basic scenario of updating firmware, u-boot.bin and u-boot.env,
> > is also the same, isn't it? The only difference is whether FWU_MULTI_BANK_UPDATE
> > is enabled or not.
> 
> There are two capsule files per image, one per bank. Also, the FWU
> metadata is being written to the SPI NOR device, which is being
> formatted as a MTD partitioned device. The underlying update mechanism
> is the same, yes.
> 
> -sughosh
> 
> >
> > -Takahiro Akashi
> >
> > > +
> > > +import os
> > > +import os.path
> > > +import re
> > > +from subprocess import call, check_call, check_output, CalledProcessError
> > > +import pytest
> > > +from capsule_defs import *
> > > +
> > > +#
> > > +# Fixture for UEFI capsule test
> > > +#
> > > +
> > > +@pytest.fixture(scope='session')
> > > +def efi_capsule_data(request, u_boot_config):
> > > +    """Set up a file system to be used in UEFI capsule and
> > > +       authentication test.
> > > +
> > > +    Args:
> > > +        request: Pytest request object.
> > > +        u_boot_config: U-boot configuration.
> > > +
> > > +    Return:
> > > +        A path to disk image to be used for testing
> > > +    """
> > > +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> > > +
> > > +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> > > +    data_dir = mnt_point + CAPSULE_DATA_DIR
> > > +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> > > +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> > > +
> > > +    try:
> > > +        # Create a target device
> > > +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> > > +
> > > +        check_call('rm -rf %s' % mnt_point, shell=True)
> > > +        check_call('mkdir -p %s' % data_dir, shell=True)
> > > +        check_call('mkdir -p %s' % install_dir, shell=True)
> > > +
> > > +        # Create capsule files
> > > +        # two regions: one for u-boot.bin and the other for u-boot.env
> > > +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> > > +                   shell=True)
> > > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > > +
> > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> > > +                   (data_dir, u_boot_config.build_dir),
> > > +                   shell=True)
> > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> > > +                   (data_dir, u_boot_config.build_dir),
> > > +                   shell=True)
> > > +
> > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> > > +                   (data_dir, u_boot_config.build_dir),
> > > +                   shell=True)
> > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> > > +                   (data_dir, u_boot_config.build_dir),
> > > +                   shell=True)
> > > +
> > > +        # Create a disk image with EFI system partition
> > > +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> > > +                   (mnt_point, image_path), shell=True)
> > > +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> > > +                   image_path, shell=True)
> > > +
> > > +    except CalledProcessError as exception:
> > > +        pytest.skip('Setup failed: %s' % exception.cmd)
> > > +        return
> > > +    else:
> > > +        yield image_path
> > > +    finally:
> > > +        call('rm -rf %s' % mnt_point, shell=True)
> > > +        call('rm -f %s' % image_path, shell=True)
> > > +        call('rm -f ./spi.bin', shell=True)
> > > diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > new file mode 100644
> > > index 0000000000..d9dff3afaf
> > > --- /dev/null
> > > +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > @@ -0,0 +1,367 @@
> > > +# SPDX-License-Identifier:      GPL-2.0+
> > > +# Copyright (c) 2022, Linaro Limited
> > > +#
> > > +# FWU Multi Bank Firmware Update Test
> > > +
> > > +"""
> > > +This test verifies FWU Multi Bank firmware update for raw images
> > > +"""
> > > +
> > > +from subprocess import check_call, check_output, CalledProcessError
> > > +import pytest
> > > +from capsule_defs import *
> > > +
> > > +
> > > +@pytest.mark.boardspec('sandbox64')
> > > +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> > > +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > > +@pytest.mark.buildconfigspec('dfu')
> > > +@pytest.mark.buildconfigspec('dfu_sf')
> > > +@pytest.mark.buildconfigspec('cmd_efidebug')
> > > +@pytest.mark.buildconfigspec('cmd_fat')
> > > +@pytest.mark.buildconfigspec('cmd_memory')
> > > +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> > > +@pytest.mark.buildconfigspec('cmd_sf')
> > > +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> > > +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> > > +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> > > +@pytest.mark.slow
> > > +class TestEfiCapsuleFirmwareRaw(object):
> > > +    def test_fwu_updates_fw1(
> > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > +        """
> > > +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> > > +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> > > +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> > > +        """
> > > +
> > > +        # other tests might have run and the
> > > +        # system might not be in a clean state.
> > > +        # Restart before starting the tests.
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        disk_img = efi_capsule_data
> > > +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > +                'efidebug boot order 1',
> > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > +                'env save'])
> > > +
> > > +            # initialize contents
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 100000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 140000 10'])
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 100000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5100000 140000 10',
> > > +                'md.b 5100000 10'
> > > +                ])
> > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 0 $filesize',
> > > +                'sf write 4000000 10000 $filesize'])
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x0' in ''.join(output)
> > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > +
> > > +            # place a capsule file
> > > +            output = u_boot_console.run_command_list([
> > > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test01' in ''.join(output)
> > > +
> > > +        # reboot
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> > > +            # make sure that dfu_alt_info exists even persistent variables
> > > +            # are not available.
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test01' in ''.join(output)
> > > +
> > > +            # need to run uefi command to initiate capsule handling
> > > +            output = u_boot_console.run_command(
> > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x1' in ''.join(output)
> > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 100000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 140000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-b:New' in ''.join(output)
> > > +
> > > +    def test_fwu_updates_fw2(
> > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > +        """
> > > +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> > > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > > +        """
> > > +
> > > +        # other tests might have run and the
> > > +        # system might not be in a clean state.
> > > +        # Restart before starting the tests.
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        disk_img = efi_capsule_data
> > > +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > +                'efidebug boot order 1',
> > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > +                'env save'])
> > > +
> > > +            # initialize contents
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 100000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 120000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 140000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 160000 10'])
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 100000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 120000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5100000 140000 10',
> > > +                'md.b 5100000 10'
> > > +                ])
> > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 160000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 0 100',
> > > +                'sf write 4000000 10000 100'])
> > > +
> > > +            output = u_boot_console.run_command(
> > > +               'fwu_mdata_read')
> > > +            assert 'active_index: 0x0' in ''.join(output)
> > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > +
> > > +            # place a capsule file
> > > +            output = u_boot_console.run_command_list([
> > > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test01' in ''.join(output)
> > > +            assert 'Test02' in ''.join(output)
> > > +
> > > +        # reboot
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> > > +            # make sure that dfu_alt_info exists even persistent variables
> > > +            # are not available.
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test01' in ''.join(output)
> > > +            assert 'Test02' in ''.join(output)
> > > +
> > > +            # need to run uefi command to initiate capsule handling
> > > +            output = u_boot_console.run_command(
> > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x1' in ''.join(output)
> > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 100000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 120000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 140000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-b:New' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 160000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-env-b:New' in ''.join(output)
> > > +
> > > +    def test_fwu_updates_fw3(
> > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > +        """
> > > +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> > > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > > +        """
> > > +
> > > +        # other tests might have run and the
> > > +        # system might not be in a clean state.
> > > +        # Restart before starting the tests.
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        disk_img = efi_capsule_data
> > > +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > +                'efidebug boot order 1',
> > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > +                'env save'])
> > > +
> > > +            # initialize contents
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 100000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 120000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 140000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 160000 10'])
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 100000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 120000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5100000 140000 10',
> > > +                'md.b 5100000 10'
> > > +                ])
> > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 160000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 0 100',
> > > +                'sf write 4000000 10000 100'])
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x1' in ''.join(output)
> > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > +
> > > +            # place a capsule file
> > > +            output = u_boot_console.run_command_list([
> > > +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test03' in ''.join(output)
> > > +            assert 'Test04' in ''.join(output)
> > > +
> > > +        # reboot
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> > > +            # make sure that dfu_alt_info exists even persistent variables
> > > +            # are not available.
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test03' in ''.join(output)
> > > +            assert 'Test04' in ''.join(output)
> > > +
> > > +            # need to run uefi command to initiate capsule handling
> > > +            output = u_boot_console.run_command(
> > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x0' in ''.join(output)
> > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 100000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-a:New' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 120000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-env-a:New' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 140000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 160000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > --
> > > 2.25.1
> > >
Sughosh Ganu June 17, 2022, 7:57 a.m. UTC | #6
On Fri, 17 Jun 2022 at 06:38, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> Sughosh,
>
> On Wed, Jun 15, 2022 at 05:40:12PM +0530, Sughosh Ganu wrote:
> > On Wed, 15 Jun 2022 at 11:07, Takahiro Akashi
> > <takahiro.akashi@linaro.org> wrote:
> > >
> > > On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> > > > Add a python test script for testing the FWU Multi Bank Update
> > > > functionality on the sandbox platform. The script has test cases for
> > > > updation of the u-boot binary and the u-boot environment image to the
> > > > non active bank.
> > > >
> > > > The FWU metadata is being stored on the SPI NOR flash, along with the
> > > > updatable images, and the FWU metadata driver for MTD devices is being
> > > > used for accessing the metadata. Certain FWU boottime checks are
> > > > bypassed due to the unavailability of the EFI variable access very
> > > > early in the boot on the sandbox platform -- the variable access is
> > > > only available once the block disk image has been bound through the
> > > > host interface.
> > > >
> > > > The FWU Multi Bank feature being enabled on the sandbox64 platform is
> > > > enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> > > > the FIT FMP instance is being removed -- the FIT FMP is already being
> > > > tested on the sandbox flattree variant.
> > >
> > > IMO,
> > > Thinking of the importance of this feature, FIT FMP should also be
> > > tested *with FWU*.
> >
> > How will the FWU update feature work for FIT images? As I understand
>
> So are you deliberately designing and proposing a solution that is
> incompatible with (or not applicable to) an existing interface (FIT FMP)?

Heh, why would anyone do that? The very fact that we are introducing
support on two platforms, one with a GPT layout, and another with MTD
is because the idea is to encourage adoption on multiple platforms.
Secondly, this is a specification from Arm which was driven by Jose
Marinho, and I believe he has incorporated feedback from various
engineers for drafting the specification -- this specification is not
limited only to platforms booting with u-boot. The main issue, as I
see it, is that the FWU metadata is doing the bookkeeping for images
that are present on the platform's storage device, and this just does
not map with FIT which is a packaging mechanism. However, this being
software, you can make changes to the fit_update function and
incorporate the information from the metadata to write to the relevant
locations. However, this needs to be thought through.

>
> > FIT, it is a way of packaging different firmware images into a single
> > package. At the time of writing the images, the FIT image parser would
> > check the image configuration, and write the images to their
> > respective locations. As you are aware, for the FWU feature, the
> > information about the images, and the update bank is obtained from the
> > structure called metadata. How does the FIT update mechanism map with
> > the FWU metadata which is used to identify which bank needs to be
> > updated. The bank to which the image is to be written translates into
> > the DFU alt_num value for that image, and this gets computed at
> > runtime. In the case of the FIT image, as per my understanding, the
> > alt_num value is irrelevant. So my question is, how do we map the
> > information obtained from the FWU metadata to tell the FIT image
> > writing function(fit_update) which locations do the images need to be
> > written to. I think this needs some more thought.
> >
> > >
> > > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > > ---
> > > >  arch/sandbox/Kconfig                          |   6 +
> > > >  arch/sandbox/dts/test.dts                     |  45 ++-
> > > >  board/sandbox/sandbox.c                       |  49 +++
> > > >  configs/sandbox64_defconfig                   |  12 +-
> > > >  include/fwu.h                                 |   2 +
> > > >  lib/fwu_updates/Kconfig                       |   2 +-
> > > >  lib/fwu_updates/fwu.c                         |  18 +-
> > > >  lib/fwu_updates/fwu_mtd.c                     |  10 +-
> > > >  .../test_capsule_firmware_fit.py              |   1 -
> > > >  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> > > >  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
> > > >  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
> > > >  12 files changed, 587 insertions(+), 13 deletions(-)
> > > >  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> > > >  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> > > >  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > >
> >
> > <snip>
> >
> > > > diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> > > > new file mode 100644
> > > > index 0000000000..cdf824c3be
> > > > --- /dev/null
> > > > +++ b/test/py/tests/test_fwu_updates/conftest.py
> > > > @@ -0,0 +1,78 @@
> > > > +# SPDX-License-Identifier:      GPL-2.0+
> > > > +# Copyright (c) 2020, Linaro Limited
> > > > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > >
> > > If this file is exactly same as test_efi_capsule/conftest.py,
> > > why not move all the tests (test_fwu_updates.py) to test_efi_capsule?
> >
> > The files are not exactly the same. There is use of the mkfwumdata
> > utility used for FWU tests, along with the capsule files that are
> > being generated. I had tried putting the code under the
> > test_efi_capsule directory, but the result was getting cluttered.
>
> Okay, but from my curiosity, how cluttered was it?
> It seems to me that you are simply adding extra setup steps.

Yes, I am adding extra commands to be called, but I found the multiple
commands for creation of the u-boot, u-boot-env and the same images
per bank subsequently to be adding some confusion. Same for the
capsule file creation as well.

>
> My simple concern is that, if there is a fair amount of common code
> between two tests, it should be unified for maintainability.

Yes, I understand, which is why I had even started with putting these
commands under the capsule test's conftest.py file.

-sughosh

>
> -Takahiro Akashi
>
> > Which is why I decided to put the changes separately under the
> > test_fwu_updates directory.
> >
> > >
> > > The basic scenario of updating firmware, u-boot.bin and u-boot.env,
> > > is also the same, isn't it? The only difference is whether FWU_MULTI_BANK_UPDATE
> > > is enabled or not.
> >
> > There are two capsule files per image, one per bank. Also, the FWU
> > metadata is being written to the SPI NOR device, which is being
> > formatted as a MTD partitioned device. The underlying update mechanism
> > is the same, yes.
> >
> > -sughosh
> >
> > >
> > > -Takahiro Akashi
> > >
> > > > +
> > > > +import os
> > > > +import os.path
> > > > +import re
> > > > +from subprocess import call, check_call, check_output, CalledProcessError
> > > > +import pytest
> > > > +from capsule_defs import *
> > > > +
> > > > +#
> > > > +# Fixture for UEFI capsule test
> > > > +#
> > > > +
> > > > +@pytest.fixture(scope='session')
> > > > +def efi_capsule_data(request, u_boot_config):
> > > > +    """Set up a file system to be used in UEFI capsule and
> > > > +       authentication test.
> > > > +
> > > > +    Args:
> > > > +        request: Pytest request object.
> > > > +        u_boot_config: U-boot configuration.
> > > > +
> > > > +    Return:
> > > > +        A path to disk image to be used for testing
> > > > +    """
> > > > +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> > > > +
> > > > +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> > > > +    data_dir = mnt_point + CAPSULE_DATA_DIR
> > > > +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> > > > +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> > > > +
> > > > +    try:
> > > > +        # Create a target device
> > > > +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> > > > +
> > > > +        check_call('rm -rf %s' % mnt_point, shell=True)
> > > > +        check_call('mkdir -p %s' % data_dir, shell=True)
> > > > +        check_call('mkdir -p %s' % install_dir, shell=True)
> > > > +
> > > > +        # Create capsule files
> > > > +        # two regions: one for u-boot.bin and the other for u-boot.env
> > > > +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> > > > +                   shell=True)
> > > > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > > > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > > > +
> > > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> > > > +                   (data_dir, u_boot_config.build_dir),
> > > > +                   shell=True)
> > > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> > > > +                   (data_dir, u_boot_config.build_dir),
> > > > +                   shell=True)
> > > > +
> > > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> > > > +                   (data_dir, u_boot_config.build_dir),
> > > > +                   shell=True)
> > > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> > > > +                   (data_dir, u_boot_config.build_dir),
> > > > +                   shell=True)
> > > > +
> > > > +        # Create a disk image with EFI system partition
> > > > +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> > > > +                   (mnt_point, image_path), shell=True)
> > > > +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> > > > +                   image_path, shell=True)
> > > > +
> > > > +    except CalledProcessError as exception:
> > > > +        pytest.skip('Setup failed: %s' % exception.cmd)
> > > > +        return
> > > > +    else:
> > > > +        yield image_path
> > > > +    finally:
> > > > +        call('rm -rf %s' % mnt_point, shell=True)
> > > > +        call('rm -f %s' % image_path, shell=True)
> > > > +        call('rm -f ./spi.bin', shell=True)
> > > > diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > > new file mode 100644
> > > > index 0000000000..d9dff3afaf
> > > > --- /dev/null
> > > > +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > > @@ -0,0 +1,367 @@
> > > > +# SPDX-License-Identifier:      GPL-2.0+
> > > > +# Copyright (c) 2022, Linaro Limited
> > > > +#
> > > > +# FWU Multi Bank Firmware Update Test
> > > > +
> > > > +"""
> > > > +This test verifies FWU Multi Bank firmware update for raw images
> > > > +"""
> > > > +
> > > > +from subprocess import check_call, check_output, CalledProcessError
> > > > +import pytest
> > > > +from capsule_defs import *
> > > > +
> > > > +
> > > > +@pytest.mark.boardspec('sandbox64')
> > > > +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> > > > +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > > > +@pytest.mark.buildconfigspec('dfu')
> > > > +@pytest.mark.buildconfigspec('dfu_sf')
> > > > +@pytest.mark.buildconfigspec('cmd_efidebug')
> > > > +@pytest.mark.buildconfigspec('cmd_fat')
> > > > +@pytest.mark.buildconfigspec('cmd_memory')
> > > > +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> > > > +@pytest.mark.buildconfigspec('cmd_sf')
> > > > +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> > > > +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> > > > +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> > > > +@pytest.mark.slow
> > > > +class TestEfiCapsuleFirmwareRaw(object):
> > > > +    def test_fwu_updates_fw1(
> > > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > > +        """
> > > > +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> > > > +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> > > > +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> > > > +        """
> > > > +
> > > > +        # other tests might have run and the
> > > > +        # system might not be in a clean state.
> > > > +        # Restart before starting the tests.
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        disk_img = efi_capsule_data
> > > > +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > > +                'efidebug boot order 1',
> > > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > > +                'env save'])
> > > > +
> > > > +            # initialize contents
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 100000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 140000 10'])
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 100000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5100000 140000 10',
> > > > +                'md.b 5100000 10'
> > > > +                ])
> > > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 0 $filesize',
> > > > +                'sf write 4000000 10000 $filesize'])
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x0' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > > +
> > > > +            # place a capsule file
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test01' in ''.join(output)
> > > > +
> > > > +        # reboot
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> > > > +            # make sure that dfu_alt_info exists even persistent variables
> > > > +            # are not available.
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test01' in ''.join(output)
> > > > +
> > > > +            # need to run uefi command to initiate capsule handling
> > > > +            output = u_boot_console.run_command(
> > > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x1' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 100000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 140000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-b:New' in ''.join(output)
> > > > +
> > > > +    def test_fwu_updates_fw2(
> > > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > > +        """
> > > > +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> > > > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > > > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > > > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > > > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > > > +        """
> > > > +
> > > > +        # other tests might have run and the
> > > > +        # system might not be in a clean state.
> > > > +        # Restart before starting the tests.
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        disk_img = efi_capsule_data
> > > > +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > > +                'efidebug boot order 1',
> > > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > > +                'env save'])
> > > > +
> > > > +            # initialize contents
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 100000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 120000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 140000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 160000 10'])
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 100000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 120000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5100000 140000 10',
> > > > +                'md.b 5100000 10'
> > > > +                ])
> > > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 160000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 0 100',
> > > > +                'sf write 4000000 10000 100'])
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +               'fwu_mdata_read')
> > > > +            assert 'active_index: 0x0' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > > +
> > > > +            # place a capsule file
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test01' in ''.join(output)
> > > > +            assert 'Test02' in ''.join(output)
> > > > +
> > > > +        # reboot
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> > > > +            # make sure that dfu_alt_info exists even persistent variables
> > > > +            # are not available.
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test01' in ''.join(output)
> > > > +            assert 'Test02' in ''.join(output)
> > > > +
> > > > +            # need to run uefi command to initiate capsule handling
> > > > +            output = u_boot_console.run_command(
> > > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x1' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 100000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 120000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 140000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-b:New' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 160000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-env-b:New' in ''.join(output)
> > > > +
> > > > +    def test_fwu_updates_fw3(
> > > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > > +        """
> > > > +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> > > > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > > > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > > > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > > > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > > > +        """
> > > > +
> > > > +        # other tests might have run and the
> > > > +        # system might not be in a clean state.
> > > > +        # Restart before starting the tests.
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        disk_img = efi_capsule_data
> > > > +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > > +                'efidebug boot order 1',
> > > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > > +                'env save'])
> > > > +
> > > > +            # initialize contents
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 100000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 120000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 140000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 160000 10'])
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 100000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 120000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5100000 140000 10',
> > > > +                'md.b 5100000 10'
> > > > +                ])
> > > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 160000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 0 100',
> > > > +                'sf write 4000000 10000 100'])
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x1' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > > +
> > > > +            # place a capsule file
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test03' in ''.join(output)
> > > > +            assert 'Test04' in ''.join(output)
> > > > +
> > > > +        # reboot
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> > > > +            # make sure that dfu_alt_info exists even persistent variables
> > > > +            # are not available.
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test03' in ''.join(output)
> > > > +            assert 'Test04' in ''.join(output)
> > > > +
> > > > +            # need to run uefi command to initiate capsule handling
> > > > +            output = u_boot_console.run_command(
> > > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x0' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 100000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-a:New' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 120000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-env-a:New' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 140000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 160000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > > --
> > > > 2.25.1
> > > >
diff mbox series

Patch

diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 5f55c7f28e..2985572083 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -84,3 +84,9 @@  config SYS_FDT_LOAD_ADDR
 	  See `doc/arch/sandbox.rst` for more information.
 
 endmenu
+
+config FWU_NUM_BANKS
+       default 2
+
+config FWU_NUM_IMAGES_PER_BANK
+	default 2
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 8f93775ff4..f11fa8733f 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1145,11 +1145,48 @@ 
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinmux_spi0_pins>;
 
-		spi.bin@0 {
+		spi0: spi.bin@0 {
 			reg = <0>;
 			compatible = "spansion,m25p16", "jedec,spi-nor";
 			spi-max-frequency = <40000000>;
 			sandbox,filename = "spi.bin";
+
+			partitions {
+				compatible = "fixed-partitions";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				uuid = "af9e8c96-bec5-48be-9dab-3491c04b1366";
+
+				partition@0 {
+					label = "Metadata";
+					reg = <0x0 0x20000>;
+				};
+
+				/* FWU Multi bank update partitions */
+				partition@100000 {
+					label = "U-Boot-Bank0";
+					reg = <0x100000 0x10000>;
+					uuid = "a8f61787-5d68-4c9d-9e4a-37bb0df99da7";
+				};
+
+				partition@120000 {
+					label = "U-Boot-ENV-Bank0";
+					reg = <0x120000 0x10000>;
+					uuid = "ea9d59af-e0e8-4ef5-9b16-4c80ff67524c";
+				};
+
+				partition@140000 {
+					label = "U-Boot-Bank1";
+					reg = <0x140000 0x10000>;
+					uuid = "52377abf-c4e4-4d0b-aafd-ba081a500847";
+				};
+
+				partition@160000 {
+					label = "U-Boot-ENV-Bank1";
+					reg = <0x160000 0x10000>;
+					uuid = "4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3";
+				};
+			};
 		};
 		spi.bin@1 {
 			reg = <1>;
@@ -1633,6 +1670,12 @@ 
 			compatible = "sandbox,regmap_test";
 		};
 	};
+
+	fwu-mdata {
+		compatible = "u-boot,fwu-mdata-mtd";
+		fwu-mdata-store = <&spi0>;
+		mdata-offsets = <0x0 0x10000>;
+	};
 };
 
 #include "sandbox_pmic.dtsi"
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
index e054f300c4..222c36d301 100644
--- a/board/sandbox/sandbox.c
+++ b/board/sandbox/sandbox.c
@@ -6,13 +6,18 @@ 
 #include <common.h>
 #include <cpu_func.h>
 #include <cros_ec.h>
+#include <dfu.h>
 #include <dm.h>
 #include <efi.h>
 #include <efi_loader.h>
 #include <env_internal.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
 #include <init.h>
 #include <led.h>
+#include <mtd.h>
 #include <os.h>
+#include <uuid.h>
 #include <asm/global_data.h>
 #include <asm/test.h>
 #include <asm/u-boot-sandbox.h>
@@ -51,8 +56,15 @@  struct efi_fw_image fw_images[] = {
 };
 
 struct efi_capsule_update_info update_info = {
+#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
+	.dfu_string = "mtd nor0=u-boot-bin-a raw 0x100000 0x10000;"
+		"u-boot-env-a raw 0x120000 0x10000;"
+		"u-boot-bin-b raw 0x140000 0x10000;"
+		"u-boot-env-b raw 0x160000 0x10000",
+#else
 	.dfu_string = "sf 0:0=u-boot-bin raw 0x100000 0x50000;"
 		"u-boot-env raw 0x150000 0x200000",
+#endif
 	.images = fw_images,
 };
 
@@ -155,3 +167,40 @@  int board_late_init(void)
 	return 0;
 }
 #endif
+
+#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
+int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
+			 efi_guid_t *image_id, int *alt_num)
+{
+	return fwu_get_mtd_alt_num(image_id, alt_num, "nor0", 1);
+}
+
+int fwu_plat_get_update_index(u32 *update_idx)
+{
+	int ret;
+	u32 active_idx;
+
+	ret = fwu_get_active_index(&active_idx);
+
+	if (ret < 0)
+		return -1;
+
+	*update_idx = active_idx ^= 0x1;
+
+	return ret;
+}
+
+void fwu_plat_get_bootidx(void *boot_idx)
+{
+	int ret;
+	u32 active_idx;
+	u32 *bootidx = boot_idx;
+
+	ret = fwu_get_active_index(&active_idx);
+
+	if (ret < 0)
+		*bootidx = -1;
+
+	*bootidx = active_idx;
+}
+#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index d7f22b39ae..7a813b46a5 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -244,9 +244,19 @@  CONFIG_LZ4=y
 CONFIG_ERRNO_STR=y
 CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
 CONFIG_EFI_CAPSULE_ON_DISK=y
-CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
 CONFIG_EFI_SECURE_BOOT=y
 CONFIG_TEST_FDTDEC=y
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
+CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
+CONFIG_DM_FWU_MDATA=y
+CONFIG_FWU_MULTI_BANK_UPDATE=y
+CONFIG_FWU_MDATA_MTD=y
+CONFIG_CMD_FWU_METADATA=y
+CONFIG_TOOLS_MKFWUMDATA=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_CMD_MTD=y
+CONFIG_DFU_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_SPI_FLASH_MTD=y
diff --git a/include/fwu.h b/include/fwu.h
index fadbfedd07..9e550182eb 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -8,6 +8,8 @@ 
 
 #include <blk.h>
 #include <efi.h>
+#include <fwu_mdata.h>
+#include <mtd.h>
 
 #include <linux/types.h>
 
diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
index 6de28e0c9c..43bed7729c 100644
--- a/lib/fwu_updates/Kconfig
+++ b/lib/fwu_updates/Kconfig
@@ -2,7 +2,7 @@  config FWU_MULTI_BANK_UPDATE
 	bool "Enable FWU Multi Bank Update Feature"
 	depends on EFI_HAVE_CAPSULE_SUPPORT
 	select PARTITION_TYPE_GUID
-	select EFI_SETUP_EARLY
+	select EFI_SETUP_EARLY if !SANDBOX
 	help
 	  Feature for updating firmware images on platforms having
 	  multiple banks(copies) of the firmware images. One of the
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 422ef58661..f2c10d836b 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -185,12 +185,22 @@  int fwu_boottime_checks(void)
 		return 0;
 	}
 
-	if (efi_init_obj_list() != EFI_SUCCESS)
-		return 0;
+	/*
+	 * On the sandbox platform, the EFI variable
+	 * access is available only after binding the
+	 * disk image with the host interface. Skip
+	 * the Trial State check on sandbox.
+	 */
+	if (!IS_ENABLED(CONFIG_SANDBOX)) {
+		if (efi_init_obj_list() != EFI_SUCCESS)
+			return 0;
 
-	ret = fwu_trial_state_check();
-	if (!ret)
+		ret = fwu_trial_state_check();
+		if (!ret)
+			boottime_check = 1;
+	} else {
 		boottime_check = 1;
+	}
 
 	return 0;
 }
diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
index 3137f8635c..3a9ad70203 100644
--- a/lib/fwu_updates/fwu_mtd.c
+++ b/lib/fwu_updates/fwu_mtd.c
@@ -84,11 +84,11 @@  int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
 int gen_image_alt_info(char *buf, size_t len, int sidx,
 		       struct fwu_image_entry *img, struct mtd_info *mtd)
 {
-	char *p = buf, *end = buf + len;
-	char uuidbuf[UUID_STR_LEN + 1];
-	ofnode node, parts_node;
-	const char *suuid;
 	int i;
+	const char *suuid;
+	ofnode node, parts_node;
+	char uuidbuf[UUID_STR_LEN + 1];
+	char *p = buf, *end = buf + len;
 
 	/* Find partition node under given MTD device. */
 	parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
@@ -145,7 +145,7 @@  int gen_image_alt_info(char *buf, size_t len, int sidx,
 
 int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
 {
-	struct fwu_mdata *mdata;
+	struct fwu_mdata *mdata = NULL;
 	int i, l, ret;
 
 	ret = fwu_get_mdata(&mdata);
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
index 5bef84958b..93bc5ed44b 100644
--- a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
+++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
@@ -13,7 +13,6 @@  import pytest
 from capsule_defs import *
 
 
-@pytest.mark.boardspec('sandbox64')
 @pytest.mark.boardspec('sandbox_flattree')
 @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
 @pytest.mark.buildconfigspec('efi_capsule_on_disk')
diff --git a/test/py/tests/test_fwu_updates/capsule_defs.py b/test/py/tests/test_fwu_updates/capsule_defs.py
new file mode 100644
index 0000000000..59b40f11bd
--- /dev/null
+++ b/test/py/tests/test_fwu_updates/capsule_defs.py
@@ -0,0 +1,10 @@ 
+# SPDX-License-Identifier:      GPL-2.0+
+
+# Directories
+CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
+CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
+
+# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
+# you need build a newer version on your own.
+# The path must terminate with '/' if it is not null.
+EFITOOLS_PATH = ''
diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
new file mode 100644
index 0000000000..cdf824c3be
--- /dev/null
+++ b/test/py/tests/test_fwu_updates/conftest.py
@@ -0,0 +1,78 @@ 
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2020, Linaro Limited
+# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+
+import os
+import os.path
+import re
+from subprocess import call, check_call, check_output, CalledProcessError
+import pytest
+from capsule_defs import *
+
+#
+# Fixture for UEFI capsule test
+#
+
+@pytest.fixture(scope='session')
+def efi_capsule_data(request, u_boot_config):
+    """Set up a file system to be used in UEFI capsule and
+       authentication test.
+
+    Args:
+        request: Pytest request object.
+        u_boot_config: U-boot configuration.
+
+    Return:
+        A path to disk image to be used for testing
+    """
+    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
+
+    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
+    data_dir = mnt_point + CAPSULE_DATA_DIR
+    install_dir = mnt_point + CAPSULE_INSTALL_DIR
+    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
+
+    try:
+        # Create a target device
+        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
+
+        check_call('rm -rf %s' % mnt_point, shell=True)
+        check_call('mkdir -p %s' % data_dir, shell=True)
+        check_call('mkdir -p %s' % install_dir, shell=True)
+
+        # Create capsule files
+        # two regions: one for u-boot.bin and the other for u-boot.env
+        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
+                   shell=True)
+        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
+        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
+
+        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+
+        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+
+        # Create a disk image with EFI system partition
+        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
+                   (mnt_point, image_path), shell=True)
+        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
+                   image_path, shell=True)
+
+    except CalledProcessError as exception:
+        pytest.skip('Setup failed: %s' % exception.cmd)
+        return
+    else:
+        yield image_path
+    finally:
+        call('rm -rf %s' % mnt_point, shell=True)
+        call('rm -f %s' % image_path, shell=True)
+        call('rm -f ./spi.bin', shell=True)
diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
new file mode 100644
index 0000000000..d9dff3afaf
--- /dev/null
+++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
@@ -0,0 +1,367 @@ 
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2022, Linaro Limited
+#
+# FWU Multi Bank Firmware Update Test
+
+"""
+This test verifies FWU Multi Bank firmware update for raw images
+"""
+
+from subprocess import check_call, check_output, CalledProcessError
+import pytest
+from capsule_defs import *
+
+
+@pytest.mark.boardspec('sandbox64')
+@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
+@pytest.mark.buildconfigspec('efi_capsule_on_disk')
+@pytest.mark.buildconfigspec('dfu')
+@pytest.mark.buildconfigspec('dfu_sf')
+@pytest.mark.buildconfigspec('cmd_efidebug')
+@pytest.mark.buildconfigspec('cmd_fat')
+@pytest.mark.buildconfigspec('cmd_memory')
+@pytest.mark.buildconfigspec('cmd_nvedit_efi')
+@pytest.mark.buildconfigspec('cmd_sf')
+@pytest.mark.buildconfigspec('fwu_multi_bank_update')
+@pytest.mark.buildconfigspec('dm_fwu_mdata')
+@pytest.mark.buildconfigspec('fwu_mdata_mtd')
+@pytest.mark.slow
+class TestEfiCapsuleFirmwareRaw(object):
+    def test_fwu_updates_fw1(
+            self, u_boot_config, u_boot_console, efi_capsule_data):
+        """
+        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
+                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
+                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
+        """
+
+        # other tests might have run and the
+        # system might not be in a clean state.
+        # Restart before starting the tests.
+        u_boot_console.restart_uboot()
+
+        disk_img = efi_capsule_data
+        with u_boot_console.log.section('Test Case 1-a, before reboot'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
+                'efidebug boot order 1',
+                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
+                'env save'])
+
+            # initialize contents
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 100000 10',
+                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 140000 10'])
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 100000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5100000 140000 10',
+                'md.b 5100000 10'
+                ])
+            assert 'u-boot-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
+                'sf write 4000000 0 $filesize',
+                'sf write 4000000 10000 $filesize'])
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x0' in ''.join(output)
+            assert 'previous_active_index: 0x1' in ''.join(output)
+
+            # place a capsule file
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' in ''.join(output)
+
+        # reboot
+        u_boot_console.restart_uboot()
+
+        with u_boot_console.log.section('Test Case 1-b, after reboot'):
+            # make sure that dfu_alt_info exists even persistent variables
+            # are not available.
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' in ''.join(output)
+
+            # need to run uefi command to initiate capsule handling
+            output = u_boot_console.run_command(
+                'efidebug capsule disk-update', wait_for_reboot = True)
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x1' in ''.join(output)
+            assert 'previous_active_index: 0x0' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 100000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 140000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-b:New' in ''.join(output)
+
+    def test_fwu_updates_fw2(
+            self, u_boot_config, u_boot_console, efi_capsule_data):
+        """
+        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
+                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
+                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
+                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
+                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
+        """
+
+        # other tests might have run and the
+        # system might not be in a clean state.
+        # Restart before starting the tests.
+        u_boot_console.restart_uboot()
+
+        disk_img = efi_capsule_data
+        with u_boot_console.log.section('Test Case 2-a, before reboot'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
+                'efidebug boot order 1',
+                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
+                'env save'])
+
+            # initialize contents
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 100000 10',
+                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 120000 10',
+                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 140000 10',
+                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 160000 10'])
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 100000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 120000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-env-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5100000 140000 10',
+                'md.b 5100000 10'
+                ])
+            assert 'u-boot-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 160000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-env-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
+                'sf write 4000000 0 100',
+                'sf write 4000000 10000 100'])
+
+            output = u_boot_console.run_command(
+               'fwu_mdata_read')
+            assert 'active_index: 0x0' in ''.join(output)
+            assert 'previous_active_index: 0x1' in ''.join(output)
+
+            # place a capsule file
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' in ''.join(output)
+            assert 'Test02' in ''.join(output)
+
+        # reboot
+        u_boot_console.restart_uboot()
+
+        with u_boot_console.log.section('Test Case 2-b, after reboot'):
+            # make sure that dfu_alt_info exists even persistent variables
+            # are not available.
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' in ''.join(output)
+            assert 'Test02' in ''.join(output)
+
+            # need to run uefi command to initiate capsule handling
+            output = u_boot_console.run_command(
+                'efidebug capsule disk-update', wait_for_reboot = True)
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x1' in ''.join(output)
+            assert 'previous_active_index: 0x0' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 100000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 120000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 140000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-b:New' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 160000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env-b:New' in ''.join(output)
+
+    def test_fwu_updates_fw3(
+            self, u_boot_config, u_boot_console, efi_capsule_data):
+        """
+        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
+                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
+                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
+                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
+                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
+        """
+
+        # other tests might have run and the
+        # system might not be in a clean state.
+        # Restart before starting the tests.
+        u_boot_console.restart_uboot()
+
+        disk_img = efi_capsule_data
+        with u_boot_console.log.section('Test Case 3-a, before reboot'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
+                'efidebug boot order 1',
+                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
+                'env save'])
+
+            # initialize contents
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 100000 10',
+                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 120000 10',
+                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 140000 10',
+                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 160000 10'])
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 100000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 120000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-env-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5100000 140000 10',
+                'md.b 5100000 10'
+                ])
+            assert 'u-boot-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 160000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-env-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
+                'sf write 4000000 0 100',
+                'sf write 4000000 10000 100'])
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x1' in ''.join(output)
+            assert 'previous_active_index: 0x0' in ''.join(output)
+
+            # place a capsule file
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test03' in ''.join(output)
+            assert 'Test04' in ''.join(output)
+
+        # reboot
+        u_boot_console.restart_uboot()
+
+        with u_boot_console.log.section('Test Case 3-b, after reboot'):
+            # make sure that dfu_alt_info exists even persistent variables
+            # are not available.
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test03' in ''.join(output)
+            assert 'Test04' in ''.join(output)
+
+            # need to run uefi command to initiate capsule handling
+            output = u_boot_console.run_command(
+                'efidebug capsule disk-update', wait_for_reboot = True)
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x0' in ''.join(output)
+            assert 'previous_active_index: 0x1' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 100000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-a:New' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 120000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env-a:New' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 140000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 160000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env-b:Old' in ''.join(output)