1# SPDX-License-Identifier:      GPL-2.0+
2# Copyright (c) 2020, Linaro Limited
3# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
4
5""" U-Boot UEFI: Firmware Update Test
6This test verifies capsule-on-disk firmware update for raw images
7"""
8
9import pytest
10from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
11
12@pytest.mark.boardspec('sandbox')
13@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
14@pytest.mark.buildconfigspec('efi_capsule_on_disk')
15@pytest.mark.buildconfigspec('dfu')
16@pytest.mark.buildconfigspec('dfu_sf')
17@pytest.mark.buildconfigspec('cmd_efidebug')
18@pytest.mark.buildconfigspec('cmd_fat')
19@pytest.mark.buildconfigspec('cmd_memory')
20@pytest.mark.buildconfigspec('cmd_nvedit_efi')
21@pytest.mark.buildconfigspec('cmd_sf')
22@pytest.mark.slow
23class TestEfiCapsuleFirmwareRaw:
24    """ Tests verifying capsule-on-disk firmware update for raw images
25    """
26
27    def test_efi_capsule_fw1(
28            self, u_boot_config, u_boot_console, efi_capsule_data):
29        """ Test Case 1
30        Update U-Boot and U-Boot environment on SPI Flash
31        but with an incorrect GUID value in the capsule
32        No update should happen
33        0x100000-0x150000: U-Boot binary (but dummy)
34        0x150000-0x200000: U-Boot environment (but dummy)
35        """
36
37        # other tests might have run and the
38        # system might not be in a clean state.
39        # Restart before starting the tests.
40        u_boot_console.restart_uboot()
41
42        disk_img = efi_capsule_data
43        with u_boot_console.log.section('Test Case 1-a, before reboot'):
44            output = u_boot_console.run_command_list([
45                'host bind 0 %s' % disk_img,
46                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
47                'efidebug boot order 1',
48                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
49                'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
50                'env save'])
51
52            # initialize contents
53            output = u_boot_console.run_command_list([
54                'sf probe 0:0',
55                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
56                'sf write 4000000 100000 10',
57                'sf read 5000000 100000 10',
58                'md.b 5000000 10'])
59            assert 'Old' in ''.join(output)
60            output = u_boot_console.run_command_list([
61                'sf probe 0:0',
62                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,
63                'sf write 4000000 150000 10',
64                'sf read 5000000 150000 10',
65                'md.b 5000000 10'])
66            assert 'Old' in ''.join(output)
67
68            # place a capsule file
69            output = u_boot_console.run_command_list([
70                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
71                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
72                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
73            assert 'Test03' in ''.join(output)
74
75        # reboot
76        u_boot_console.restart_uboot()
77
78        capsule_early = u_boot_config.buildconfig.get(
79            'config_efi_capsule_on_disk_early')
80
81        with u_boot_console.log.section('Test Case 1-b, after reboot'):
82            if not capsule_early:
83                # make sure that dfu_alt_info exists even persistent variables
84                # are not available.
85                output = u_boot_console.run_command_list([
86                    'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
87                    'host bind 0 %s' % disk_img,
88                    'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
89                assert 'Test03' in ''.join(output)
90
91                # need to run uefi command to initiate capsule handling
92                output = u_boot_console.run_command(
93                    'env print -e Capsule0000', wait_for_reboot = True)
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:Old' in ''.join(output)
100
101            output = u_boot_console.run_command_list([
102                'sf read 4000000 150000 10',
103                'md.b 4000000 10'])
104            assert 'u-boot-env:Old' in ''.join(output)
105
106    def test_efi_capsule_fw2(
107            self, u_boot_config, u_boot_console, efi_capsule_data):
108        """ Test Case 2
109        Update U-Boot and U-Boot environment on SPI Flash but with OsIndications unset
110        No update should happen
111        0x100000-0x150000: U-Boot binary (but dummy)
112        0x150000-0x200000: U-Boot environment (but dummy)
113        """
114        disk_img = efi_capsule_data
115        with u_boot_console.log.section('Test Case 2-a, before reboot'):
116            output = u_boot_console.run_command_list([
117                'host bind 0 %s' % disk_img,
118                'printenv -e PlatformLangCodes', # workaround for terminal size determination
119                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
120                'efidebug boot order 1',
121                'env set -e OsIndications',
122                'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
123                'env save'])
124
125            # initialize contents
126            output = u_boot_console.run_command_list([
127                'sf probe 0:0',
128                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
129                'sf write 4000000 100000 10',
130                'sf read 5000000 100000 10',
131                'md.b 5000000 10'])
132            assert 'Old' in ''.join(output)
133            output = u_boot_console.run_command_list([
134                'sf probe 0:0',
135                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,
136                'sf write 4000000 150000 10',
137                'sf read 5000000 150000 10',
138                'md.b 5000000 10'])
139            assert 'Old' in ''.join(output)
140
141            # place the capsule files
142            output = u_boot_console.run_command_list([
143                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
144                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
145                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
146            assert 'Test01' in ''.join(output)
147
148            output = u_boot_console.run_command_list([
149                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
150                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
151                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
152            assert 'Test02' in ''.join(output)
153
154        # reboot
155        u_boot_console.restart_uboot()
156
157        capsule_early = u_boot_config.buildconfig.get(
158            'config_efi_capsule_on_disk_early')
159        with u_boot_console.log.section('Test Case 2-b, after reboot'):
160            if not capsule_early:
161                # make sure that dfu_alt_info exists even persistent variables
162                # are not available.
163                output = u_boot_console.run_command_list([
164                    'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
165                    'host bind 0 %s' % disk_img,
166                    'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
167                assert 'Test01' in ''.join(output)
168                assert 'Test02' in ''.join(output)
169
170                # need to run uefi command to initiate capsule handling
171                output = u_boot_console.run_command(
172                    'env print -e Capsule0000')
173
174            output = u_boot_console.run_command_list([
175                'host bind 0 %s' % disk_img,
176                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
177            assert 'Test01' in ''.join(output)
178            assert 'Test02' in ''.join(output)
179
180            output = u_boot_console.run_command_list([
181                'sf probe 0:0',
182                'sf read 4000000 100000 10',
183                'md.b 4000000 10'])
184            assert 'u-boot:Old' in ''.join(output)
185
186            output = u_boot_console.run_command_list([
187                'sf read 4000000 150000 10',
188                'md.b 4000000 10'])
189            assert 'u-boot-env:Old' in ''.join(output)
190
191    def test_efi_capsule_fw3(
192            self, u_boot_config, u_boot_console, efi_capsule_data):
193        """ Test Case 3
194        Update U-Boot on SPI Flash, raw image format
195        0x100000-0x150000: U-Boot binary (but dummy)
196        """
197        disk_img = efi_capsule_data
198        with u_boot_console.log.section('Test Case 3-a, before reboot'):
199            output = u_boot_console.run_command_list([
200                'host bind 0 %s' % disk_img,
201                'printenv -e PlatformLangCodes', # workaround for terminal size determination
202                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
203                'efidebug boot order 1',
204                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
205                'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
206                'env save'])
207
208            # initialize contents
209            output = u_boot_console.run_command_list([
210                'sf probe 0:0',
211                'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
212                'sf write 4000000 100000 10',
213                'sf read 5000000 100000 10',
214                'md.b 5000000 10'])
215            assert 'Old' in ''.join(output)
216
217            output = u_boot_console.run_command_list([
218                'sf probe 0:0',
219                'fatload host 0:1 4000000 %s/u-boot.env.old' % CAPSULE_DATA_DIR,
220                'sf write 4000000 150000 10',
221                'sf read 5000000 100000 10',
222                'md.b 5000000 10'])
223            assert 'Old' in ''.join(output)
224
225            # place the capsule files
226            output = u_boot_console.run_command_list([
227                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
228                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
229                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
230            assert 'Test01' in ''.join(output)
231
232            output = u_boot_console.run_command_list([
233                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
234                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
235                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
236            assert 'Test02' in ''.join(output)
237
238        capsule_early = u_boot_config.buildconfig.get(
239            'config_efi_capsule_on_disk_early')
240        capsule_auth = u_boot_config.buildconfig.get(
241            'config_efi_capsule_authenticate')
242
243        # reboot
244        u_boot_console.restart_uboot(expect_reset = capsule_early)
245
246        with u_boot_console.log.section('Test Case 3-b, after reboot'):
247            if not capsule_early:
248                # make sure that dfu_alt_info exists even persistent variables
249                # are not available.
250                output = u_boot_console.run_command_list([
251                    'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
252                    'host bind 0 %s' % disk_img,
253                    'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
254                assert 'Test01' in ''.join(output)
255                assert 'Test02' in ''.join(output)
256
257                # need to run uefi command to initiate capsule handling
258                output = u_boot_console.run_command(
259                    'env print -e Capsule0000', wait_for_reboot = True)
260
261            # make sure the dfu_alt_info exists because it is required for making ESRT.
262            output = u_boot_console.run_command_list([
263                'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
264                'efidebug capsule esrt'])
265
266            # ensure that SANDBOX_UBOOT_ENV_IMAGE_GUID is in the ESRT.
267            assert '5A7021F5-FEF2-48B4-AABA-832E777418C0' in ''.join(output)
268
269            # ensure that SANDBOX_UBOOT_IMAGE_GUID is in the ESRT.
270            assert '09D7CF52-0720-4710-91D1-08469B7FE9C8' in ''.join(output)
271
272            output = u_boot_console.run_command_list([
273                'host bind 0 %s' % disk_img,
274                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
275            assert 'Test01' not in ''.join(output)
276            assert 'Test02' not in ''.join(output)
277
278            output = u_boot_console.run_command_list([
279                'sf probe 0:0',
280                'sf read 4000000 100000 10',
281                'md.b 4000000 10'])
282            if capsule_auth:
283                assert 'u-boot:Old' in ''.join(output)
284            else:
285                assert 'u-boot:New' in ''.join(output)
286
287            output = u_boot_console.run_command_list([
288                'sf probe 0:0',
289                'sf read 4000000 150000 10',
290                'md.b 4000000 10'])
291            if capsule_auth:
292                assert 'u-boot-env:Old' in ''.join(output)
293            else:
294                assert 'u-boot-env:New' in ''.join(output)
295