diff mbox series

[v5,16/17] test/py: add a test for uefi firmware update capsule of FIT image

Message ID 20200803054355.17356-17-takahiro.akashi@linaro.org
State New
Headers show
Series efi_loader: add capsule update support | expand

Commit Message

AKASHI Takahiro Aug. 3, 2020, 5:43 a.m. UTC
The test can run on sandbox build and it attempts to execute a firmware
update via a capsule-on-disk, using a FIT image capsule,
CONFIG_EFI_CAPSULE_FIT.

To run this test successfully, you need configure U-Boot specifically;
See test_capsule_firmware.py for requirements, and hence it won't run
on Travis CI.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

---
 test/py/tests/test_efi_capsule/conftest.py    |  69 +++++++
 test/py/tests/test_efi_capsule/defs.py        |  12 ++
 .../test_efi_capsule/test_capsule_firmware.py | 178 ++++++++++++++++++
 .../tests/test_efi_capsule/uboot_bin_env.its  |  36 ++++
 4 files changed, 295 insertions(+)
 create mode 100644 test/py/tests/test_efi_capsule/conftest.py
 create mode 100644 test/py/tests/test_efi_capsule/defs.py
 create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware.py
 create mode 100644 test/py/tests/test_efi_capsule/uboot_bin_env.its

-- 
2.27.0

Comments

Heinrich Schuchardt Aug. 31, 2020, 11:44 a.m. UTC | #1
On 03.08.20 07:43, AKASHI Takahiro wrote:
> The test can run on sandbox build and it attempts to execute a firmware

> update via a capsule-on-disk, using a FIT image capsule,

> CONFIG_EFI_CAPSULE_FIT.

>

> To run this test successfully, you need configure U-Boot specifically;

> See test_capsule_firmware.py for requirements, and hence it won't run

> on Travis CI.

>

> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

> ---

>  test/py/tests/test_efi_capsule/conftest.py    |  69 +++++++

>  test/py/tests/test_efi_capsule/defs.py        |  12 ++

>  .../test_efi_capsule/test_capsule_firmware.py | 178 ++++++++++++++++++

>  .../tests/test_efi_capsule/uboot_bin_env.its  |  36 ++++

>  4 files changed, 295 insertions(+)

>  create mode 100644 test/py/tests/test_efi_capsule/conftest.py

>  create mode 100644 test/py/tests/test_efi_capsule/defs.py

>  create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware.py

>  create mode 100644 test/py/tests/test_efi_capsule/uboot_bin_env.its

>

> diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py

> new file mode 100644

> index 000000000000..4e7c36f04ba5

> --- /dev/null

> +++ b/test/py/tests/test_efi_capsule/conftest.py

> @@ -0,0 +1,69 @@

> +# 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 defs import *

> +

> +#

> +# Fixture for UEFI secure boot test

> +#

> +

> +

> +@pytest.fixture(scope='session')

> +def efi_capsule_data(request, u_boot_config):

> +    """Set up a file system to be used in UEFI capsule test.

> +

> +    Args:

> +        request: Pytest request object.

> +        u_boot_config: U-boot configuration.

> +

> +    Return:

> +        A path to disk image to be used for testing

> +    """

> +    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:Old > u-boot.bin.old; echo -n u-boot:New > u-boot.bin.new; echo -n u-boot-env:Old -> u-boot.env.old; echo -n u-boot-env:New > u-boot.env.new' % data_dir,

> +                   shell=True)

> +        check_call('sed -e \"s?BINFILE1?u-boot.bin.new?\" -e \"s?BINFILE2?u-boot.env.new?\" %s/test/py/tests/test_efi_capsule/uboot_bin_env.its > %s/uboot_bin_env.its' %

> +                   (u_boot_config.source_dir, data_dir),

> +                   shell=True)

> +        check_call('cd %s; %s/tools/mkimage -f uboot_bin_env.its uboot_bin_env.itb' %

> +                   (data_dir, u_boot_config.build_dir),

> +                   shell=True)

> +        check_call('cd %s; %s/tools/mkeficapsule --fit uboot_bin_env.itb --version 1 --index 1 Test01' %

> +                   (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_efi_capsule/defs.py b/test/py/tests/test_efi_capsule/defs.py

> new file mode 100644

> index 000000000000..2c5b0ee49beb

> --- /dev/null

> +++ b/test/py/tests/test_efi_capsule/defs.py

> @@ -0,0 +1,12 @@

> +# SPDX-License-Identifier:      GPL-2.0+

> +

> +# Size in MiB

> +EFI_BOOTDEV_IMAGE_SIZE = 16

> +EFI_BOOTDEV_PART_SIZE = 8

> +

> +# Owner guid

> +GUID = '11111111-2222-3333-4444-123456789abc'

> +

> +# Directories

> +CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'

> +CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'

> diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware.py b/test/py/tests/test_efi_capsule/test_capsule_firmware.py

> new file mode 100644

> index 000000000000..1673a4877778

> --- /dev/null

> +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware.py

> @@ -0,0 +1,178 @@

> +# SPDX-License-Identifier:      GPL-2.0+

> +# Copyright (c) 2020, Linaro Limited

> +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>

> +#

> +# U-Boot UEFI: Firmware Update Test

> +

> +"""

> +This test verifies capsule-on-disk firmware update

> +"""

> +

> +from subprocess import check_call, check_output, CalledProcessError

> +import pytest

> +from defs import *

> +

> +

> +@pytest.mark.boardspec('sandbox')

> +@pytest.mark.buildconfigspec('efi_capsule_firmware_fit')

> +@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.slow

> +class TestEfiCapsuleFirmwareFit(object):

> +    def test_efi_capsule_fw1(

> +            self, u_boot_config, u_boot_console, efi_capsule_data):

> +        """

> +        Test Case 1 - Update U-Boot and U-Boot environment on SPI Flash

> +                      but with OsIndications unset

> +                      No update should happen

> +                      0x100000-0x150000: U-Boot binary (but dummy)

> +                      0x150000-0x200000: U-Boot environment (but dummy)

> +        """

> +        # "-T" (or "-D") is required to enable spi flash on sandbox

> +        u_boot_console.restart_uboot_with_flags('-T')

> +

> +        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 1 TEST host 0:1 /helloworld.efi ""',

> +                'efidebug boot order 1',

> +                'env set -e OsIndications',

> +                'env set dfu_alt_info sf 0:0=u-boot-bin raw 0x100000 0x50000\;u-boot-env raw 0x150000 0x200000',


This results in a warning:

DeprecationWarning: invalid escape sequence \;

The test is never executed on Gitlab:

https://gitlab.denx.de/u-boot/custodians/u-boot-efi/-/jobs/144884
test/py/tests/test_efi_capsule/test_capsule_firmware.py sss



> +                'env save'])

> +

> +            # initialize contents

> +            output = u_boot_console.run_command_list([

> +                'sf probe 0:0',

> +                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,

> +                'sf write 4000000 100000 10',

> +                'sf read 5000000 100000 10',

> +                'md.b 5000000 10'])

> +            assert 'Old' in ''.join(output)

> +            output = u_boot_console.run_command_list([

> +                'sf probe 0:0',

> +                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,

> +                'sf write 4000000 150000 10',

> +                'sf read 5000000 150000 10',

> +                'md.b 5000000 10'])

> +            assert 'Old' 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_flags('-T')

> +

> +        capsule_early = u_boot_config.buildconfig.get(

> +            'config_efi_capsule_on_disk_early')

> +        with u_boot_console.log.section('Test Case 1-b, after reboot'):

> +            if not capsule_early:

> +                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(

> +                    'env print -e -all Capsule0000')

> +

> +            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)

> +

> +            output = u_boot_console.run_command_list([

> +                'sf probe 0:0',

> +                'sf read 4000000 100000 10',

> +                'md.b 4000000 10'])

> +            assert 'u-boot:Old' in ''.join(output)

> +

> +            output = u_boot_console.run_command_list([

> +                'sf read 4000000 150000 10',

> +                'md.b 4000000 10'])

> +            assert 'u-boot-env:Old' in ''.join(output)

> +

> +    def test_efi_capsule_fw2(

> +            self, u_boot_config, u_boot_console, efi_capsule_data):

> +        """

> +        Test Case 2 - Update U-Boot and U-Boot environment on SPI Flash

> +                      0x100000-0x150000: U-Boot binary (but dummy)

> +                      0x150000-0x200000: U-Boot environment (but dummy)

> +        """

> +        # "-T" (or "-D") is required to enable spi flash on sandbox

> +        u_boot_console.restart_uboot_with_flags('-T')

> +

> +        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 1 TEST host 0:1 /helloworld.efi ""',

> +                'efidebug boot order 1',

> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',

> +                'env set dfu_alt_info sf 0:0=u-boot-bin raw 0x100000 0x50000\;u-boot-env raw 0x150000 0x200000',


Invalid escape sequence \;

Best regards

Heinrich

> +                'env save'])

> +

> +            # initialize contents

> +            output = u_boot_console.run_command_list([

> +                'sf probe 0:0',

> +                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,

> +                'sf write 4000000 100000 10',

> +                'sf read 5000000 100000 10',

> +                'md.b 5000000 10'])

> +            assert 'Old' in ''.join(output)

> +            output = u_boot_console.run_command_list([

> +                'sf probe 0:0',

> +                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,

> +                'sf write 4000000 150000 10',

> +                'sf read 5000000 150000 10',

> +                'md.b 5000000 10'])

> +            assert 'Old' 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_flags('-T')

> +

> +        capsule_early = u_boot_config.buildconfig.get(

> +            'config_efi_capsule_on_disk_early')

> +        with u_boot_console.log.section('Test Case 2-b, after reboot'):

> +            if not capsule_early:

> +                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(

> +                    'env print -e -all Capsule0000')

> +

> +            output = u_boot_console.run_command_list([

> +                'host bind 0 %s' % disk_img,

> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])

> +            assert 'Test01' not 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:New' in ''.join(output)

> +

> +            output = u_boot_console.run_command_list([

> +                'sf read 4000000 150000 10',

> +                'md.b 4000000 10'])

> +            assert 'u-boot-env:New' in ''.join(output)

> diff --git a/test/py/tests/test_efi_capsule/uboot_bin_env.its b/test/py/tests/test_efi_capsule/uboot_bin_env.its

> new file mode 100644

> index 000000000000..31e2f8049f9a

> --- /dev/null

> +++ b/test/py/tests/test_efi_capsule/uboot_bin_env.its

> @@ -0,0 +1,36 @@

> +/*

> + * Automatic software update for U-Boot

> + * Make sure the flashing addresses ('load' prop) is correct for your board!

> + */

> +

> +/dts-v1/;

> +

> +/ {

> +	description = "Automatic U-Boot environment update";

> +	#address-cells = <2>;

> +

> +	images {

> +		u-boot-bin@100000 {

> +			description = "U-Boot binary on SPI Flash";

> +			data = /incbin/("BINFILE1");

> +			compression = "none";

> +			type = "firmware";

> +			arch = "sandbox";

> +			load = <0>;

> +			hash-1 {

> +				algo = "sha1";

> +			};

> +		};

> +		u-boot-env@150000 {

> +			description = "U-Boot environment on SPI Flash";

> +			data = /incbin/("BINFILE2");

> +			compression = "none";

> +			type = "firmware";

> +			arch = "sandbox";

> +			load = <0>;

> +			hash-1 {

> +				algo = "sha1";

> +			};

> +		};

> +	};

> +};

>
AKASHI Takahiro Sept. 1, 2020, 5:20 a.m. UTC | #2
Heinrich,

On Mon, Aug 31, 2020 at 01:44:44PM +0200, Heinrich Schuchardt wrote:
> On 03.08.20 07:43, AKASHI Takahiro wrote:

> > The test can run on sandbox build and it attempts to execute a firmware

> > update via a capsule-on-disk, using a FIT image capsule,

> > CONFIG_EFI_CAPSULE_FIT.

> >

> > To run this test successfully, you need configure U-Boot specifically;

> > See test_capsule_firmware.py for requirements, and hence it won't run

> > on Travis CI.

> >

> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

> > ---

> >  test/py/tests/test_efi_capsule/conftest.py    |  69 +++++++

> >  test/py/tests/test_efi_capsule/defs.py        |  12 ++

> >  .../test_efi_capsule/test_capsule_firmware.py | 178 ++++++++++++++++++

> >  .../tests/test_efi_capsule/uboot_bin_env.its  |  36 ++++

> >  4 files changed, 295 insertions(+)

> >  create mode 100644 test/py/tests/test_efi_capsule/conftest.py

> >  create mode 100644 test/py/tests/test_efi_capsule/defs.py

> >  create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware.py

> >  create mode 100644 test/py/tests/test_efi_capsule/uboot_bin_env.its

> >

> > diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py

> > new file mode 100644

> > index 000000000000..4e7c36f04ba5

> > --- /dev/null

> > +++ b/test/py/tests/test_efi_capsule/conftest.py

> > @@ -0,0 +1,69 @@

> > +# 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 defs import *

> > +

> > +#

> > +# Fixture for UEFI secure boot test

> > +#

> > +

> > +

> > +@pytest.fixture(scope='session')

> > +def efi_capsule_data(request, u_boot_config):

> > +    """Set up a file system to be used in UEFI capsule test.

> > +

> > +    Args:

> > +        request: Pytest request object.

> > +        u_boot_config: U-boot configuration.

> > +

> > +    Return:

> > +        A path to disk image to be used for testing

> > +    """

> > +    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:Old > u-boot.bin.old; echo -n u-boot:New > u-boot.bin.new; echo -n u-boot-env:Old -> u-boot.env.old; echo -n u-boot-env:New > u-boot.env.new' % data_dir,

> > +                   shell=True)

> > +        check_call('sed -e \"s?BINFILE1?u-boot.bin.new?\" -e \"s?BINFILE2?u-boot.env.new?\" %s/test/py/tests/test_efi_capsule/uboot_bin_env.its > %s/uboot_bin_env.its' %

> > +                   (u_boot_config.source_dir, data_dir),

> > +                   shell=True)

> > +        check_call('cd %s; %s/tools/mkimage -f uboot_bin_env.its uboot_bin_env.itb' %

> > +                   (data_dir, u_boot_config.build_dir),

> > +                   shell=True)

> > +        check_call('cd %s; %s/tools/mkeficapsule --fit uboot_bin_env.itb --version 1 --index 1 Test01' %

> > +                   (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_efi_capsule/defs.py b/test/py/tests/test_efi_capsule/defs.py

> > new file mode 100644

> > index 000000000000..2c5b0ee49beb

> > --- /dev/null

> > +++ b/test/py/tests/test_efi_capsule/defs.py

> > @@ -0,0 +1,12 @@

> > +# SPDX-License-Identifier:      GPL-2.0+

> > +

> > +# Size in MiB

> > +EFI_BOOTDEV_IMAGE_SIZE = 16

> > +EFI_BOOTDEV_PART_SIZE = 8

> > +

> > +# Owner guid

> > +GUID = '11111111-2222-3333-4444-123456789abc'

> > +

> > +# Directories

> > +CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'

> > +CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'

> > diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware.py b/test/py/tests/test_efi_capsule/test_capsule_firmware.py

> > new file mode 100644

> > index 000000000000..1673a4877778

> > --- /dev/null

> > +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware.py

> > @@ -0,0 +1,178 @@

> > +# SPDX-License-Identifier:      GPL-2.0+

> > +# Copyright (c) 2020, Linaro Limited

> > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>

> > +#

> > +# U-Boot UEFI: Firmware Update Test

> > +

> > +"""

> > +This test verifies capsule-on-disk firmware update

> > +"""

> > +

> > +from subprocess import check_call, check_output, CalledProcessError

> > +import pytest

> > +from defs import *

> > +

> > +

> > +@pytest.mark.boardspec('sandbox')

> > +@pytest.mark.buildconfigspec('efi_capsule_firmware_fit')

> > +@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.slow

> > +class TestEfiCapsuleFirmwareFit(object):

> > +    def test_efi_capsule_fw1(

> > +            self, u_boot_config, u_boot_console, efi_capsule_data):

> > +        """

> > +        Test Case 1 - Update U-Boot and U-Boot environment on SPI Flash

> > +                      but with OsIndications unset

> > +                      No update should happen

> > +                      0x100000-0x150000: U-Boot binary (but dummy)

> > +                      0x150000-0x200000: U-Boot environment (but dummy)

> > +        """

> > +        # "-T" (or "-D") is required to enable spi flash on sandbox

> > +        u_boot_console.restart_uboot_with_flags('-T')

> > +

> > +        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 1 TEST host 0:1 /helloworld.efi ""',

> > +                'efidebug boot order 1',

> > +                'env set -e OsIndications',

> > +                'env set dfu_alt_info sf 0:0=u-boot-bin raw 0x100000 0x50000\;u-boot-env raw 0x150000 0x200000',

> 

> This results in a warning:

> 

> DeprecationWarning: invalid escape sequence \;


I don't think that such a warning eventually prevent running tests,
but will fix them anyway in the next version.

> The test is never executed on Gitlab:

> 

> https://gitlab.denx.de/u-boot/custodians/u-boot-efi/-/jobs/144884

> test/py/tests/test_efi_capsule/test_capsule_firmware.py sss


This is because, as I mentioned briefly in the cover letter,
some specific configurations, i.e. CONFIG_DFU and CONFIG_DFU_SF,
are mandatory to run tests successfully.

I'm not sure whether we should add them to sandbox*_defconfig
just for this purpose.

# We have another issue on virt-make-fs.

## Same comment on patch#17.

-Takahiro Akashi


> 

> 

> > +                'env save'])

> > +

> > +            # initialize contents

> > +            output = u_boot_console.run_command_list([

> > +                'sf probe 0:0',

> > +                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,

> > +                'sf write 4000000 100000 10',

> > +                'sf read 5000000 100000 10',

> > +                'md.b 5000000 10'])

> > +            assert 'Old' in ''.join(output)

> > +            output = u_boot_console.run_command_list([

> > +                'sf probe 0:0',

> > +                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,

> > +                'sf write 4000000 150000 10',

> > +                'sf read 5000000 150000 10',

> > +                'md.b 5000000 10'])

> > +            assert 'Old' 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_flags('-T')

> > +

> > +        capsule_early = u_boot_config.buildconfig.get(

> > +            'config_efi_capsule_on_disk_early')

> > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):

> > +            if not capsule_early:

> > +                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(

> > +                    'env print -e -all Capsule0000')

> > +

> > +            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)

> > +

> > +            output = u_boot_console.run_command_list([

> > +                'sf probe 0:0',

> > +                'sf read 4000000 100000 10',

> > +                'md.b 4000000 10'])

> > +            assert 'u-boot:Old' in ''.join(output)

> > +

> > +            output = u_boot_console.run_command_list([

> > +                'sf read 4000000 150000 10',

> > +                'md.b 4000000 10'])

> > +            assert 'u-boot-env:Old' in ''.join(output)

> > +

> > +    def test_efi_capsule_fw2(

> > +            self, u_boot_config, u_boot_console, efi_capsule_data):

> > +        """

> > +        Test Case 2 - Update U-Boot and U-Boot environment on SPI Flash

> > +                      0x100000-0x150000: U-Boot binary (but dummy)

> > +                      0x150000-0x200000: U-Boot environment (but dummy)

> > +        """

> > +        # "-T" (or "-D") is required to enable spi flash on sandbox

> > +        u_boot_console.restart_uboot_with_flags('-T')

> > +

> > +        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 1 TEST host 0:1 /helloworld.efi ""',

> > +                'efidebug boot order 1',

> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',

> > +                'env set dfu_alt_info sf 0:0=u-boot-bin raw 0x100000 0x50000\;u-boot-env raw 0x150000 0x200000',

> 

> Invalid escape sequence \;

> 

> Best regards

> 

> Heinrich

> 

> > +                'env save'])

> > +

> > +            # initialize contents

> > +            output = u_boot_console.run_command_list([

> > +                'sf probe 0:0',

> > +                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,

> > +                'sf write 4000000 100000 10',

> > +                'sf read 5000000 100000 10',

> > +                'md.b 5000000 10'])

> > +            assert 'Old' in ''.join(output)

> > +            output = u_boot_console.run_command_list([

> > +                'sf probe 0:0',

> > +                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,

> > +                'sf write 4000000 150000 10',

> > +                'sf read 5000000 150000 10',

> > +                'md.b 5000000 10'])

> > +            assert 'Old' 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_flags('-T')

> > +

> > +        capsule_early = u_boot_config.buildconfig.get(

> > +            'config_efi_capsule_on_disk_early')

> > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):

> > +            if not capsule_early:

> > +                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(

> > +                    'env print -e -all Capsule0000')

> > +

> > +            output = u_boot_console.run_command_list([

> > +                'host bind 0 %s' % disk_img,

> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])

> > +            assert 'Test01' not 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:New' in ''.join(output)

> > +

> > +            output = u_boot_console.run_command_list([

> > +                'sf read 4000000 150000 10',

> > +                'md.b 4000000 10'])

> > +            assert 'u-boot-env:New' in ''.join(output)

> > diff --git a/test/py/tests/test_efi_capsule/uboot_bin_env.its b/test/py/tests/test_efi_capsule/uboot_bin_env.its

> > new file mode 100644

> > index 000000000000..31e2f8049f9a

> > --- /dev/null

> > +++ b/test/py/tests/test_efi_capsule/uboot_bin_env.its

> > @@ -0,0 +1,36 @@

> > +/*

> > + * Automatic software update for U-Boot

> > + * Make sure the flashing addresses ('load' prop) is correct for your board!

> > + */

> > +

> > +/dts-v1/;

> > +

> > +/ {

> > +	description = "Automatic U-Boot environment update";

> > +	#address-cells = <2>;

> > +

> > +	images {

> > +		u-boot-bin@100000 {

> > +			description = "U-Boot binary on SPI Flash";

> > +			data = /incbin/("BINFILE1");

> > +			compression = "none";

> > +			type = "firmware";

> > +			arch = "sandbox";

> > +			load = <0>;

> > +			hash-1 {

> > +				algo = "sha1";

> > +			};

> > +		};

> > +		u-boot-env@150000 {

> > +			description = "U-Boot environment on SPI Flash";

> > +			data = /incbin/("BINFILE2");

> > +			compression = "none";

> > +			type = "firmware";

> > +			arch = "sandbox";

> > +			load = <0>;

> > +			hash-1 {

> > +				algo = "sha1";

> > +			};

> > +		};

> > +	};

> > +};

> >

>
diff mbox series

Patch

diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py
new file mode 100644
index 000000000000..4e7c36f04ba5
--- /dev/null
+++ b/test/py/tests/test_efi_capsule/conftest.py
@@ -0,0 +1,69 @@ 
+# 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 defs import *
+
+#
+# Fixture for UEFI secure boot test
+#
+
+
+@pytest.fixture(scope='session')
+def efi_capsule_data(request, u_boot_config):
+    """Set up a file system to be used in UEFI capsule test.
+
+    Args:
+        request: Pytest request object.
+        u_boot_config: U-boot configuration.
+
+    Return:
+        A path to disk image to be used for testing
+    """
+    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:Old > u-boot.bin.old; echo -n u-boot:New > u-boot.bin.new; echo -n u-boot-env:Old -> u-boot.env.old; echo -n u-boot-env:New > u-boot.env.new' % data_dir,
+                   shell=True)
+        check_call('sed -e \"s?BINFILE1?u-boot.bin.new?\" -e \"s?BINFILE2?u-boot.env.new?\" %s/test/py/tests/test_efi_capsule/uboot_bin_env.its > %s/uboot_bin_env.its' %
+                   (u_boot_config.source_dir, data_dir),
+                   shell=True)
+        check_call('cd %s; %s/tools/mkimage -f uboot_bin_env.its uboot_bin_env.itb' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+        check_call('cd %s; %s/tools/mkeficapsule --fit uboot_bin_env.itb --version 1 --index 1 Test01' %
+                   (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_efi_capsule/defs.py b/test/py/tests/test_efi_capsule/defs.py
new file mode 100644
index 000000000000..2c5b0ee49beb
--- /dev/null
+++ b/test/py/tests/test_efi_capsule/defs.py
@@ -0,0 +1,12 @@ 
+# SPDX-License-Identifier:      GPL-2.0+
+
+# Size in MiB
+EFI_BOOTDEV_IMAGE_SIZE = 16
+EFI_BOOTDEV_PART_SIZE = 8
+
+# Owner guid
+GUID = '11111111-2222-3333-4444-123456789abc'
+
+# Directories
+CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
+CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware.py b/test/py/tests/test_efi_capsule/test_capsule_firmware.py
new file mode 100644
index 000000000000..1673a4877778
--- /dev/null
+++ b/test/py/tests/test_efi_capsule/test_capsule_firmware.py
@@ -0,0 +1,178 @@ 
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2020, Linaro Limited
+# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+#
+# U-Boot UEFI: Firmware Update Test
+
+"""
+This test verifies capsule-on-disk firmware update
+"""
+
+from subprocess import check_call, check_output, CalledProcessError
+import pytest
+from defs import *
+
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
+@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.slow
+class TestEfiCapsuleFirmwareFit(object):
+    def test_efi_capsule_fw1(
+            self, u_boot_config, u_boot_console, efi_capsule_data):
+        """
+        Test Case 1 - Update U-Boot and U-Boot environment on SPI Flash
+                      but with OsIndications unset
+                      No update should happen
+                      0x100000-0x150000: U-Boot binary (but dummy)
+                      0x150000-0x200000: U-Boot environment (but dummy)
+        """
+        # "-T" (or "-D") is required to enable spi flash on sandbox
+        u_boot_console.restart_uboot_with_flags('-T')
+
+        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 1 TEST host 0:1 /helloworld.efi ""',
+                'efidebug boot order 1',
+                'env set -e OsIndications',
+                'env set dfu_alt_info sf 0:0=u-boot-bin raw 0x100000 0x50000\;u-boot-env raw 0x150000 0x200000',
+                'env save'])
+
+            # initialize contents
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 100000 10',
+                'sf read 5000000 100000 10',
+                'md.b 5000000 10'])
+            assert 'Old' in ''.join(output)
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 150000 10',
+                'sf read 5000000 150000 10',
+                'md.b 5000000 10'])
+            assert 'Old' 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_flags('-T')
+
+        capsule_early = u_boot_config.buildconfig.get(
+            'config_efi_capsule_on_disk_early')
+        with u_boot_console.log.section('Test Case 1-b, after reboot'):
+            if not capsule_early:
+                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(
+                    'env print -e -all Capsule0000')
+
+            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)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 100000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 150000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env:Old' in ''.join(output)
+
+    def test_efi_capsule_fw2(
+            self, u_boot_config, u_boot_console, efi_capsule_data):
+        """
+        Test Case 2 - Update U-Boot and U-Boot environment on SPI Flash
+                      0x100000-0x150000: U-Boot binary (but dummy)
+                      0x150000-0x200000: U-Boot environment (but dummy)
+        """
+        # "-T" (or "-D") is required to enable spi flash on sandbox
+        u_boot_console.restart_uboot_with_flags('-T')
+
+        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 1 TEST host 0:1 /helloworld.efi ""',
+                'efidebug boot order 1',
+                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
+                'env set dfu_alt_info sf 0:0=u-boot-bin raw 0x100000 0x50000\;u-boot-env raw 0x150000 0x200000',
+                'env save'])
+
+            # initialize contents
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 100000 10',
+                'sf read 5000000 100000 10',
+                'md.b 5000000 10'])
+            assert 'Old' in ''.join(output)
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 150000 10',
+                'sf read 5000000 150000 10',
+                'md.b 5000000 10'])
+            assert 'Old' 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_flags('-T')
+
+        capsule_early = u_boot_config.buildconfig.get(
+            'config_efi_capsule_on_disk_early')
+        with u_boot_console.log.section('Test Case 2-b, after reboot'):
+            if not capsule_early:
+                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(
+                    'env print -e -all Capsule0000')
+
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' not 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:New' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 150000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env:New' in ''.join(output)
diff --git a/test/py/tests/test_efi_capsule/uboot_bin_env.its b/test/py/tests/test_efi_capsule/uboot_bin_env.its
new file mode 100644
index 000000000000..31e2f8049f9a
--- /dev/null
+++ b/test/py/tests/test_efi_capsule/uboot_bin_env.its
@@ -0,0 +1,36 @@ 
+/*
+ * Automatic software update for U-Boot
+ * Make sure the flashing addresses ('load' prop) is correct for your board!
+ */
+
+/dts-v1/;
+
+/ {
+	description = "Automatic U-Boot environment update";
+	#address-cells = <2>;
+
+	images {
+		u-boot-bin@100000 {
+			description = "U-Boot binary on SPI Flash";
+			data = /incbin/("BINFILE1");
+			compression = "none";
+			type = "firmware";
+			arch = "sandbox";
+			load = <0>;
+			hash-1 {
+				algo = "sha1";
+			};
+		};
+		u-boot-env@150000 {
+			description = "U-Boot environment on SPI Flash";
+			data = /incbin/("BINFILE2");
+			compression = "none";
+			type = "firmware";
+			arch = "sandbox";
+			load = <0>;
+			hash-1 {
+				algo = "sha1";
+			};
+		};
+	};
+};