Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 1 | # SPDX-License-Identifier: GPL-2.0+ |
| 2 | # Copyright (c) 2020 |
| 3 | # Author: Sam Protsenko <joe.skb7@gmail.com> |
| 4 | |
| 5 | # Test U-Boot's "abootimg" commands. |
| 6 | |
| 7 | import os |
| 8 | import pytest |
| 9 | import u_boot_utils |
| 10 | |
| 11 | """ |
| 12 | These tests rely on disk image (boot.img), which is automatically created by |
| 13 | the test from the stored hex dump. This is done to avoid the dependency on the |
| 14 | most recent mkbootimg tool from AOSP/master. Here is the list of commands which |
| 15 | was used to generate the boot.img and obtain compressed hex dump from it: |
| 16 | |
| 17 | $ echo '/dts-v1/; / { model = "x1"; compatible = "y1,z1"; };' > test1.dts |
| 18 | $ echo '/dts-v1/; / { model = "x2"; compatible = "y2,z2"; };' > test2.dts |
| 19 | $ dtc test1.dts > dt1.dtb |
| 20 | $ dtc test2.dts > dt2.dtb |
| 21 | $ cat dt1.dtb dt2.dtb > dtb.img |
| 22 | $ echo 'kernel payload' > kernel |
| 23 | $ echo 'ramdisk payload' > ramdisk.img |
| 24 | $ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \ |
| 25 | --cmdline "cmdline test" --dtb ./dtb.img \ |
| 26 | --os_version R --os_patch_level 2019-06-05 \ |
| 27 | --header_version 2 --output boot.img |
| 28 | $ gzip -9 boot.img |
| 29 | $ xxd -p boot.img.gz > boot.img.gz.hex |
| 30 | |
| 31 | Now one can obtain original boot.img from this hex dump like this: |
| 32 | |
| 33 | $ xxd -r -p boot.img.gz.hex boot.img.gz |
| 34 | $ gunzip -9 boot.img.gz |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 35 | |
| 36 | For boot image header version 4, these tests rely on two images that are generated |
| 37 | using the same steps above : |
| 38 | |
| 39 | 1- boot.img : |
| 40 | $ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \ |
| 41 | --cmdline "cmdline test" --dtb ./dtb.img \ |
| 42 | --os_version R --os_patch_level 2019-06-05 \ |
| 43 | --header_version 4 --output ./boot.img |
| 44 | |
| 45 | 2- vendor_boot.img |
| 46 | $ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \ |
| 47 | --cmdline "cmdline test" --dtb ./dtb.img \ |
| 48 | --os_version R --os_patch_level 2019-06-05 \ |
| 49 | --pagesize 4096 --vendor_ramdisk ./ramdisk.img \ |
| 50 | --header_version 4 --vendor_boot ./vboot.img \ |
| 51 | |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 52 | """ |
| 53 | |
| 54 | # boot.img.gz hex dump |
| 55 | img_hex = """1f8b08084844af5d0203626f6f742e696d670073f47309f2f77451e46700 |
| 56 | 820606010106301084501f04181819041838181898803c3346060c909c9b |
| 57 | 92939997aa50925a5cc2300a461c3078b2e1793c4b876fd92db97939fb6c |
| 58 | b7762ffff07d345446c1281805e8a0868d81e117a45e111c0d8dc101b253 |
| 59 | 8bf25273140a122b73f21353b8460364148c8251300a46c1281801a02831 |
| 60 | 3725b3387bb401300a46c1281805a360148c207081f7df5b20550bc41640 |
| 61 | 9c03c41a0c90f17fe85400986d82452b6c3680198a192a0ce17c3610ae34 |
| 62 | d4a9820881a70f3873f35352731892f3730b124b32937252a96bb9119ae5 |
| 63 | 463a5546f82c1f05a360148c8251300a462e000085bf67f200200000""" |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 64 | |
| 65 | # boot img v4 hex dump |
| 66 | boot_img_hex = """1f8b080827b0cd630203626f6f742e696d6700edd8bd0d82601885d1d7c4 |
| 67 | 58d8c808b88195bd098d8d246e40e42b083f1aa0717be99d003d277916b8 |
| 68 | e5bddc8a7b792d8e8788c896ce9b88d32ebe6c971e7ddd3543cae734cd01 |
| 69 | c0ffc84c0000b0766d1a87d4e5afeadd3dab7a6f10000000f84163d5d7cd |
| 70 | d43a000000000000000060c53e7544995700400000""" |
| 71 | |
| 72 | # vendor boot image v4 hex dump |
| 73 | vboot_img_hex = """1f8b0808baaecd63020376626f6f742e696d6700edd8310b824018c6f1b3 |
| 74 | 222a08f41b3436b4280dcdd19c11d16ee9109d18d59042d047ec8b04cd0d |
| 75 | d19d5a4345534bf6ffc173ef29272f38e93b1d0ec67dd79d548462aa1cd2 |
| 76 | d5d20b0000f8438678f90c18d584b8a4bbb3a557991ecb2a0000f80d6b2f |
| 77 | f4179b656be5c532f2fc066f040000000080e23936af2755f62a3d918df1 |
| 78 | db2a7ab67f9ffdeb7df7cda3465ecb79c4ce7e5c577562bb9364b74449a5 |
| 79 | 1e467e20c53c0a57de763193c1779b3b4fcd9d4ee27c6a0e00000000c0ff |
| 80 | 309ffea7010000000040f1dc004129855400400000""" |
| 81 | |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 82 | # Expected response for "abootimg dtb_dump" command |
| 83 | dtb_dump_resp="""## DTB area contents (concat format): |
| 84 | - DTB #0: |
| 85 | (DTB)size = 125 |
| 86 | (DTB)model = x1 |
| 87 | (DTB)compatible = y1,z1 |
| 88 | - DTB #1: |
| 89 | (DTB)size = 125 |
| 90 | (DTB)model = x2 |
| 91 | (DTB)compatible = y2,z2""" |
| 92 | # Address in RAM where to load the boot image ('abootimg' looks in $loadaddr) |
| 93 | loadaddr = 0x1000 |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 94 | # Address in RAM where to load the vendor boot image ('abootimg' looks in $vloadaddr) |
| 95 | vloadaddr= 0x10000 |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 96 | # Expected DTB #1 offset from the boot image start address |
| 97 | dtb1_offset = 0x187d |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 98 | # Expected DTB offset from the vendor boot image start address |
| 99 | dtb2_offset = 0x207d |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 100 | # DTB #1 start address in RAM |
| 101 | dtb1_addr = loadaddr + dtb1_offset |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 102 | # DTB #2 start address in RAM |
| 103 | dtb2_addr = vloadaddr + dtb2_offset |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 104 | |
| 105 | class AbootimgTestDiskImage(object): |
| 106 | """Disk image used by abootimg tests.""" |
| 107 | |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 108 | def __init__(self, u_boot_console, image_name, hex_img): |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 109 | """Initialize a new AbootimgDiskImage object. |
| 110 | |
| 111 | Args: |
| 112 | u_boot_console: A U-Boot console. |
| 113 | |
| 114 | Returns: |
| 115 | Nothing. |
| 116 | """ |
| 117 | |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 118 | gz_hex = u_boot_console.config.persistent_data_dir + '/' + image_name + '.gz.hex' |
| 119 | gz = u_boot_console.config.persistent_data_dir + '/' + image_name + '.gz' |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 120 | |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 121 | filename = image_name |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 122 | persistent = u_boot_console.config.persistent_data_dir + '/' + filename |
| 123 | self.path = u_boot_console.config.result_dir + '/' + filename |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 124 | u_boot_console.log.action('persistent is ' + persistent) |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 125 | with u_boot_utils.persistent_file_helper(u_boot_console.log, persistent): |
| 126 | if os.path.exists(persistent): |
| 127 | u_boot_console.log.action('Disk image file ' + persistent + |
| 128 | ' already exists') |
| 129 | else: |
| 130 | u_boot_console.log.action('Generating ' + persistent) |
| 131 | |
| 132 | f = open(gz_hex, "w") |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 133 | f.write(hex_img) |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 134 | f.close() |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 135 | cmd = ('xxd', '-r', '-p', gz_hex, gz) |
| 136 | u_boot_utils.run_and_log(u_boot_console, cmd) |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 137 | cmd = ('gunzip', '-9', gz) |
| 138 | u_boot_utils.run_and_log(u_boot_console, cmd) |
| 139 | |
| 140 | cmd = ('cp', persistent, self.path) |
| 141 | u_boot_utils.run_and_log(u_boot_console, cmd) |
| 142 | |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 143 | gtdi1 = None |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 144 | @pytest.fixture(scope='function') |
| 145 | def abootimg_disk_image(u_boot_console): |
| 146 | """pytest fixture to provide a AbootimgTestDiskImage object to tests. |
| 147 | This is function-scoped because it uses u_boot_console, which is also |
| 148 | function-scoped. However, we don't need to actually do any function-scope |
| 149 | work, so this simply returns the same object over and over each time.""" |
| 150 | |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 151 | global gtdi1 |
| 152 | if not gtdi1: |
| 153 | gtdi1 = AbootimgTestDiskImage(u_boot_console, 'boot.img', img_hex) |
| 154 | return gtdi1 |
| 155 | |
| 156 | gtdi2 = None |
| 157 | @pytest.fixture(scope='function') |
| 158 | def abootimgv4_disk_image_vboot(u_boot_console): |
| 159 | """pytest fixture to provide a AbootimgTestDiskImage object to tests. |
| 160 | This is function-scoped because it uses u_boot_console, which is also |
| 161 | function-scoped. However, we don't need to actually do any function-scope |
| 162 | work, so this simply returns the same object over and over each time.""" |
| 163 | |
| 164 | global gtdi2 |
| 165 | if not gtdi2: |
| 166 | gtdi2 = AbootimgTestDiskImage(u_boot_console, 'vendor_boot.img', vboot_img_hex) |
| 167 | return gtdi2 |
| 168 | |
| 169 | gtdi3 = None |
| 170 | @pytest.fixture(scope='function') |
| 171 | def abootimgv4_disk_image_boot(u_boot_console): |
| 172 | """pytest fixture to provide a AbootimgTestDiskImage object to tests. |
| 173 | This is function-scoped because it uses u_boot_console, which is also |
| 174 | function-scoped. However, we don't need to actually do any function-scope |
| 175 | work, so this simply returns the same object over and over each time.""" |
| 176 | |
| 177 | global gtdi3 |
| 178 | if not gtdi3: |
| 179 | gtdi3 = AbootimgTestDiskImage(u_boot_console, 'bootv4.img', boot_img_hex) |
| 180 | return gtdi3 |
Sam Protsenko | 61c72ea | 2020-01-24 17:53:45 +0200 | [diff] [blame] | 181 | |
| 182 | @pytest.mark.boardspec('sandbox') |
| 183 | @pytest.mark.buildconfigspec('android_boot_image') |
| 184 | @pytest.mark.buildconfigspec('cmd_abootimg') |
| 185 | @pytest.mark.buildconfigspec('cmd_fdt') |
| 186 | @pytest.mark.requiredtool('xxd') |
| 187 | @pytest.mark.requiredtool('gunzip') |
| 188 | def test_abootimg(abootimg_disk_image, u_boot_console): |
| 189 | """Test the 'abootimg' command.""" |
| 190 | |
| 191 | u_boot_console.log.action('Loading disk image to RAM...') |
| 192 | u_boot_console.run_command('setenv loadaddr 0x%x' % (loadaddr)) |
| 193 | u_boot_console.run_command('host load hostfs - 0x%x %s' % (loadaddr, |
| 194 | abootimg_disk_image.path)) |
| 195 | |
| 196 | u_boot_console.log.action('Testing \'abootimg get ver\'...') |
| 197 | response = u_boot_console.run_command('abootimg get ver') |
| 198 | assert response == "2" |
| 199 | u_boot_console.run_command('abootimg get ver v') |
| 200 | response = u_boot_console.run_command('env print v') |
| 201 | assert response == 'v=2' |
| 202 | |
| 203 | u_boot_console.log.action('Testing \'abootimg get recovery_dtbo\'...') |
| 204 | response = u_boot_console.run_command('abootimg get recovery_dtbo a') |
| 205 | assert response == 'Error: recovery_dtbo_size is 0' |
| 206 | |
| 207 | u_boot_console.log.action('Testing \'abootimg dump dtb\'...') |
| 208 | response = u_boot_console.run_command('abootimg dump dtb').replace('\r', '') |
| 209 | assert response == dtb_dump_resp |
| 210 | |
| 211 | u_boot_console.log.action('Testing \'abootimg get dtb_load_addr\'...') |
| 212 | u_boot_console.run_command('abootimg get dtb_load_addr a') |
| 213 | response = u_boot_console.run_command('env print a') |
| 214 | assert response == 'a=11f00000' |
| 215 | |
| 216 | u_boot_console.log.action('Testing \'abootimg get dtb --index\'...') |
| 217 | u_boot_console.run_command('abootimg get dtb --index=1 dtb1_start') |
| 218 | response = u_boot_console.run_command('env print dtb1_start') |
| 219 | correct_str = "dtb1_start=%x" % (dtb1_addr) |
| 220 | assert response == correct_str |
| 221 | u_boot_console.run_command('fdt addr $dtb1_start') |
| 222 | u_boot_console.run_command('fdt get value v / model') |
| 223 | response = u_boot_console.run_command('env print v') |
| 224 | assert response == 'v=x2' |
Safae Ouajih | b39cfcb | 2023-02-06 00:50:20 +0100 | [diff] [blame] | 225 | |
| 226 | @pytest.mark.boardspec('sandbox') |
| 227 | @pytest.mark.buildconfigspec('android_boot_image') |
| 228 | @pytest.mark.buildconfigspec('cmd_abootimg') |
| 229 | @pytest.mark.buildconfigspec('cmd_fdt') |
| 230 | @pytest.mark.requiredtool('xxd') |
| 231 | @pytest.mark.requiredtool('gunzip') |
| 232 | def test_abootimgv4(abootimgv4_disk_image_vboot, abootimgv4_disk_image_boot, u_boot_console): |
| 233 | """Test the 'abootimg' command with boot image header v4.""" |
| 234 | |
| 235 | cons = u_boot_console |
| 236 | cons.log.action('Loading disk image to RAM...') |
| 237 | cons.run_command('setenv loadaddr 0x%x' % (loadaddr)) |
| 238 | cons.run_command('setenv vloadaddr 0x%x' % (vloadaddr)) |
| 239 | cons.run_command('host load hostfs - 0x%x %s' % (vloadaddr, |
| 240 | abootimgv4_disk_image_vboot.path)) |
| 241 | cons.run_command('host load hostfs - 0x%x %s' % (loadaddr, |
| 242 | abootimgv4_disk_image_boot.path)) |
| 243 | cons.run_command('abootimg addr 0x%x 0x%x' % (loadaddr, vloadaddr)) |
| 244 | cons.log.action('Testing \'abootimg get ver\'...') |
| 245 | response = cons.run_command('abootimg get ver') |
| 246 | assert response == "4" |
| 247 | cons.run_command('abootimg get ver v') |
| 248 | response = cons.run_command('env print v') |
| 249 | assert response == 'v=4' |
| 250 | |
| 251 | cons.log.action('Testing \'abootimg get recovery_dtbo\'...') |
| 252 | response = cons.run_command('abootimg get recovery_dtbo a') |
| 253 | assert response == 'Error: header version must be >= 1 and <= 2 to get dtbo' |
| 254 | |
| 255 | cons.log.action('Testing \'abootimg get dtb_load_addr\'...') |
| 256 | cons.run_command('abootimg get dtb_load_addr a') |
| 257 | response = cons.run_command('env print a') |
| 258 | assert response == 'a=11f00000' |
| 259 | |
| 260 | cons.log.action('Testing \'abootimg get dtb --index\'...') |
| 261 | cons.run_command('abootimg get dtb --index=1 dtb2_start') |
| 262 | response = cons.run_command('env print dtb2_start') |
| 263 | correct_str = "dtb2_start=%x" % (dtb2_addr) |
| 264 | assert response == correct_str |
| 265 | |
| 266 | cons.run_command('fdt addr $dtb2_start') |
| 267 | cons.run_command('fdt get value v / model') |
| 268 | response = cons.run_command('env print v') |
| 269 | assert response == 'v=x2' |