1# SPDX-License-Identifier:      GPL-2.0+
2# Copyright (c) 2021, Linaro Limited
3# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
4
5"""U-Boot UEFI: Firmware Update (Signed capsule with raw images) Test
6This test verifies capsule-on-disk firmware update
7with signed capsule files containing raw images
8"""
9
10import pytest
11from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
12
13@pytest.mark.boardspec('sandbox')
14@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
15@pytest.mark.buildconfigspec('efi_capsule_authenticate')
16@pytest.mark.buildconfigspec('dfu')
17@pytest.mark.buildconfigspec('dfu_sf')
18@pytest.mark.buildconfigspec('cmd_efidebug')
19@pytest.mark.buildconfigspec('cmd_fat')
20@pytest.mark.buildconfigspec('cmd_memory')
21@pytest.mark.buildconfigspec('cmd_nvedit_efi')
22@pytest.mark.buildconfigspec('cmd_sf')
23@pytest.mark.slow
24class TestEfiCapsuleFirmwareSignedRaw():
25    """Firmware Update (Signed capsule with raw images) Test
26    """
27
28    def test_efi_capsule_auth1(
29            self, u_boot_config, u_boot_console, efi_capsule_data):
30        """Test Case 1 - Update U-Boot on SPI Flash, raw image format
31        0x100000-0x150000: U-Boot binary (but dummy)
32
33        If the capsule is properly signed, the authentication
34        should pass and the firmware be updated.
35        """
36        disk_img = efi_capsule_data
37        with u_boot_console.log.section('Test Case 1-a, before reboot'):
38            output = u_boot_console.run_command_list([
39                'host bind 0 %s' % disk_img,
40                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
41                'efidebug boot order 1',
42                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
43                'env set dfu_alt_info '
44                        '"sf 0:0=u-boot-bin raw 0x100000 '
45                        '0x50000;u-boot-env raw 0x150000 0x200000"',
46                'env save'])
47
48            # initialize content
49            output = u_boot_console.run_command_list([
50                'sf probe 0:0',
51                'fatload host 0:1 4000000 %s/u-boot.bin.old'
52                        % CAPSULE_DATA_DIR,
53                'sf write 4000000 100000 10',
54                'sf read 5000000 100000 10',
55                'md.b 5000000 10'])
56            assert 'Old' in ''.join(output)
57
58            # place a capsule file
59            output = u_boot_console.run_command_list([
60                'fatload host 0:1 4000000 %s/Test11' % CAPSULE_DATA_DIR,
61                'fatwrite host 0:1 4000000 %s/Test11 $filesize'
62                        % CAPSULE_INSTALL_DIR,
63                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
64            assert 'Test11' in ''.join(output)
65
66        # reboot
67        mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
68        u_boot_console.config.dtb = mnt_point + CAPSULE_DATA_DIR \
69                                    + '/test_sig.dtb'
70        u_boot_console.restart_uboot()
71
72        capsule_early = u_boot_config.buildconfig.get(
73            'config_efi_capsule_on_disk_early')
74        with u_boot_console.log.section('Test Case 1-b, after reboot'):
75            if not capsule_early:
76                # make sure that dfu_alt_info exists even persistent variables
77                # are not available.
78                output = u_boot_console.run_command_list([
79                    'env set dfu_alt_info '
80                            '"sf 0:0=u-boot-bin raw 0x100000 '
81                            '0x50000;u-boot-env raw 0x150000 0x200000"',
82                    'host bind 0 %s' % disk_img,
83                    'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
84                assert 'Test11' in ''.join(output)
85
86                # need to run uefi command to initiate capsule handling
87                output = u_boot_console.run_command(
88                    'env print -e Capsule0000', wait_for_reboot = True)
89
90            output = u_boot_console.run_command_list([
91                'host bind 0 %s' % disk_img,
92                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
93            assert 'Test11' not in ''.join(output)
94
95            output = u_boot_console.run_command_list([
96                'sf probe 0:0',
97                'sf read 4000000 100000 10',
98                'md.b 4000000 10'])
99            assert 'u-boot:New' in ''.join(output)
100
101    def test_efi_capsule_auth2(
102            self, u_boot_config, u_boot_console, efi_capsule_data):
103        """Test Case 2 - Update U-Boot on SPI Flash, raw image format
104        0x100000-0x150000: U-Boot binary (but dummy)
105
106        If the capsule is signed but with an invalid key,
107        the authentication should fail and the firmware
108        not be updated.
109        """
110        disk_img = efi_capsule_data
111        with u_boot_console.log.section('Test Case 2-a, before reboot'):
112            output = u_boot_console.run_command_list([
113                'host bind 0 %s' % disk_img,
114                'printenv -e PlatformLangCodes', # workaround for terminal size determination
115                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
116                'efidebug boot order 1',
117                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
118                'env set dfu_alt_info '
119                        '"sf 0:0=u-boot-bin raw 0x100000 '
120                        '0x50000;u-boot-env raw 0x150000 0x200000"',
121                'env save'])
122
123            # initialize content
124            output = u_boot_console.run_command_list([
125                'sf probe 0:0',
126                'fatload host 0:1 4000000 %s/u-boot.bin.old'
127                        % CAPSULE_DATA_DIR,
128                'sf write 4000000 100000 10',
129                'sf read 5000000 100000 10',
130                'md.b 5000000 10'])
131            assert 'Old' in ''.join(output)
132
133            # place a capsule file
134            output = u_boot_console.run_command_list([
135                'fatload host 0:1 4000000 %s/Test12' % CAPSULE_DATA_DIR,
136                'fatwrite host 0:1 4000000 %s/Test12 $filesize'
137                                % CAPSULE_INSTALL_DIR,
138                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
139            assert 'Test12' in ''.join(output)
140
141        # reboot
142        mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
143        u_boot_console.config.dtb = mnt_point + CAPSULE_DATA_DIR \
144                                    + '/test_sig.dtb'
145        u_boot_console.restart_uboot()
146
147        capsule_early = u_boot_config.buildconfig.get(
148            'config_efi_capsule_on_disk_early')
149        with u_boot_console.log.section('Test Case 2-b, after reboot'):
150            if not capsule_early:
151                # make sure that dfu_alt_info exists even persistent variables
152                # are not available.
153                output = u_boot_console.run_command_list([
154                    'env set dfu_alt_info '
155                        '"sf 0:0=u-boot-bin raw 0x100000 '
156                        '0x50000;u-boot-env raw 0x150000 0x200000"',
157                    'host bind 0 %s' % disk_img,
158                    'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
159                assert 'Test12' in ''.join(output)
160
161                # need to run uefi command to initiate capsule handling
162                output = u_boot_console.run_command(
163                    'env print -e Capsule0000', wait_for_reboot = True)
164
165            # deleted any way
166            output = u_boot_console.run_command_list([
167                'host bind 0 %s' % disk_img,
168                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
169            assert 'Test12' not in ''.join(output)
170
171            # TODO: check CapsuleStatus in CapsuleXXXX
172
173            output = u_boot_console.run_command_list([
174                'sf probe 0:0',
175                'sf read 4000000 100000 10',
176                'md.b 4000000 10'])
177            assert 'u-boot:Old' in ''.join(output)
178
179    def test_efi_capsule_auth3(
180            self, u_boot_config, u_boot_console, efi_capsule_data):
181        """Test Case 3 - Update U-Boot on SPI Flash, raw image format
182        0x100000-0x150000: U-Boot binary (but dummy)
183
184        If the capsule is not signed, the authentication
185        should fail and the firmware not be updated.
186        """
187        disk_img = efi_capsule_data
188        with u_boot_console.log.section('Test Case 3-a, before reboot'):
189            output = u_boot_console.run_command_list([
190                'host bind 0 %s' % disk_img,
191                'printenv -e PlatformLangCodes', # workaround for terminal size determination
192                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
193                'efidebug boot order 1',
194                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
195                'env set dfu_alt_info '
196                        '"sf 0:0=u-boot-bin raw 0x100000 '
197                        '0x50000;u-boot-env raw 0x150000 0x200000"',
198                'env save'])
199
200            # initialize content
201            output = u_boot_console.run_command_list([
202                'sf probe 0:0',
203                'fatload host 0:1 4000000 %s/u-boot.bin.old'
204                        % CAPSULE_DATA_DIR,
205                'sf write 4000000 100000 10',
206                'sf read 5000000 100000 10',
207                'md.b 5000000 10'])
208            assert 'Old' in ''.join(output)
209
210            # place a capsule file
211            output = u_boot_console.run_command_list([
212                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
213                'fatwrite host 0:1 4000000 %s/Test02 $filesize'
214                            % CAPSULE_INSTALL_DIR,
215                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
216            assert 'Test02' in ''.join(output)
217
218        # reboot
219        mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
220        u_boot_console.config.dtb = mnt_point + CAPSULE_DATA_DIR \
221                                    + '/test_sig.dtb'
222        u_boot_console.restart_uboot()
223
224        capsule_early = u_boot_config.buildconfig.get(
225            'config_efi_capsule_on_disk_early')
226        with u_boot_console.log.section('Test Case 3-b, after reboot'):
227            if not capsule_early:
228                # make sure that dfu_alt_info exists even persistent variables
229                # are not available.
230                output = u_boot_console.run_command_list([
231                    'env set dfu_alt_info '
232                            '"sf 0:0=u-boot-bin raw 0x100000 '
233                            '0x50000;u-boot-env raw 0x150000 0x200000"',
234                    'host bind 0 %s' % disk_img,
235                    'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
236                assert 'Test02' in ''.join(output)
237
238                # need to run uefi command to initiate capsule handling
239                output = u_boot_console.run_command(
240                    'env print -e Capsule0000', wait_for_reboot = True)
241
242            # deleted anyway
243            output = u_boot_console.run_command_list([
244                'host bind 0 %s' % disk_img,
245                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
246            assert 'Test02' not in ''.join(output)
247
248            # TODO: check CapsuleStatus in CapsuleXXXX
249
250            output = u_boot_console.run_command_list([
251                'sf probe 0:0',
252                'sf read 4000000 100000 10',
253                'md.b 4000000 10'])
254            assert 'u-boot:Old' in ''.join(output)
255