1# SPDX-License-Identifier:      GPL-2.0+
2# Copyright (c) 2020, Linaro Limited
3# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
4
5"""Fixture for UEFI capsule test."""
6
7import os
8
9from subprocess import call, check_call, CalledProcessError
10import pytest
11from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR, EFITOOLS_PATH
12
13@pytest.fixture(scope='session')
14def efi_capsule_data(request, u_boot_config):
15    """Set up a file system and return path to image.
16
17    The function sets up a file system to be used in UEFI capsule and
18    authentication test and returns a path to disk image to be used
19    for testing.
20
21    request -- Pytest request object.
22    u_boot_config -- U-Boot configuration.
23    """
24    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
25    data_dir = mnt_point + CAPSULE_DATA_DIR
26    install_dir = mnt_point + CAPSULE_INSTALL_DIR
27    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
28
29    try:
30        # Create a target device
31        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
32
33        check_call('rm -rf %s' % mnt_point, shell=True)
34        check_call('mkdir -p %s' % data_dir, shell=True)
35        check_call('mkdir -p %s' % install_dir, shell=True)
36
37        capsule_auth_enabled = u_boot_config.buildconfig.get(
38                    'config_efi_capsule_authenticate')
39        key_dir = u_boot_config.source_dir + '/board/sandbox'
40        if capsule_auth_enabled:
41            # Get the keys from the board directory
42            check_call('cp %s/capsule_priv_key_good.key %s/SIGNER.key'
43                       % (key_dir, data_dir), shell=True)
44            check_call('cp %s/capsule_pub_key_good.crt %s/SIGNER.crt'
45                       % (key_dir, data_dir), shell=True)
46            check_call('cp %s/capsule_pub_esl_good.esl %s/SIGNER.esl'
47                       % (key_dir, data_dir), shell=True)
48
49            check_call('cp %s/capsule_priv_key_bad.key %s/SIGNER2.key'
50                       % (key_dir, data_dir), shell=True)
51            check_call('cp %s/capsule_pub_key_bad.crt %s/SIGNER2.crt'
52                       % (key_dir, data_dir), shell=True)
53
54        # Update dtb to add the version information
55        check_call('cd %s; '
56                   'cp %s/test/py/tests/test_efi_capsule/version.dts .'
57                   % (data_dir, u_boot_config.source_dir), shell=True)
58
59        if capsule_auth_enabled:
60            check_call('cd %s; '
61                       'cp %s/arch/sandbox/dts/test.dtb test_sig.dtb'
62                       % (data_dir, u_boot_config.build_dir), shell=True)
63            check_call('cd %s; '
64                       'dtc -@ -I dts -O dtb -o version.dtbo version.dts; '
65                       'fdtoverlay -i test_sig.dtb '
66                            '-o test_ver.dtb version.dtbo'
67                       % (data_dir), shell=True)
68        else:
69            check_call('cd %s; '
70                       'dtc -@ -I dts -O dtb -o version.dtbo version.dts; '
71                       'fdtoverlay -i %s/arch/sandbox/dts/test.dtb '
72                            '-o test_ver.dtb version.dtbo'
73                       % (data_dir, u_boot_config.build_dir), shell=True)
74
75        # two regions: one for u-boot.bin and the other for u-boot.env
76        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,
77                   shell=True)
78
79        pythonpath = os.environ.get('PYTHONPATH', '')
80        os.environ['PYTHONPATH'] = pythonpath + ':' + '%s/scripts/dtc/pylibfdt' % u_boot_config.build_dir
81        check_call('cd %s; '
82                   'cc -E -I %s/include -x assembler-with-cpp -o capsule_gen_tmp.dts %s/test/py/tests/test_efi_capsule/capsule_gen_binman.dts; '
83                   'dtc -I dts -O dtb capsule_gen_tmp.dts -o capsule_binman.dtb;'
84                   % (data_dir, u_boot_config.source_dir, u_boot_config.source_dir), shell=True)
85        check_call('cd %s; '
86                   './tools/binman/binman --toolpath %s/tools build -u -d %s/capsule_binman.dtb -O %s -m --allow-missing -I %s -I ./board/sandbox -I ./arch/sandbox/dts'
87                   % (u_boot_config.source_dir, u_boot_config.build_dir, data_dir, data_dir, data_dir), shell=True)
88        check_call('cp %s/Test* %s' % (u_boot_config.build_dir, data_dir), shell=True)
89        os.environ['PYTHONPATH'] = pythonpath
90
91        # Create a disk image with EFI system partition
92        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
93                   (mnt_point, image_path), shell=True)
94        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
95                   image_path, shell=True)
96
97    except CalledProcessError as exception:
98        pytest.skip('Setup failed: %s' % exception.cmd)
99        return
100    else:
101        yield image_path
102    finally:
103        call('rm -rf %s' % mnt_point, shell=True)
104        call('rm -f %s' % image_path, shell=True)
105        call('rm -f ./spi.bin', shell=True)
106