1# SPDX-License-Identifier: GPL-2.0 2# Copyright (c) 2017 Alison Chaiken 3# Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. 4 5# Test GPT manipulation commands. 6 7import os 8import pytest 9import u_boot_utils 10 11""" 12These tests rely on a 4 MB disk image, which is automatically created by 13the test. 14""" 15 16# Mark all tests here as slow 17pytestmark = pytest.mark.slow 18 19def parse_gpt_parts(disk_str): 20 """Parser a partition string into a list of partitions. 21 22 Args: 23 disk_str: The disk description string, as returned by `gpt read` 24 25 Returns: 26 A list of parsed partitions. Each partition is a dictionary with the 27 string value from each specified key in the partition description, or a 28 key with with the value True for a boolean flag 29 """ 30 parts = [] 31 for part_str in disk_str.split(';'): 32 part = {} 33 for option in part_str.split(","): 34 if not option: 35 continue 36 37 if "=" in option: 38 key, value = option.split("=") 39 part[key] = value 40 else: 41 part[option] = True 42 43 if part: 44 parts.append(part) 45 46 return parts 47 48class GptTestDiskImage(object): 49 """Disk Image used by the GPT tests.""" 50 51 def __init__(self, u_boot_console): 52 """Initialize a new GptTestDiskImage object. 53 54 Args: 55 u_boot_console: A U-Boot console. 56 57 Returns: 58 Nothing. 59 """ 60 61 filename = 'test_gpt_disk_image.bin' 62 63 persistent = u_boot_console.config.persistent_data_dir + '/' + filename 64 self.path = u_boot_console.config.result_dir + '/' + filename 65 66 with u_boot_utils.persistent_file_helper(u_boot_console.log, persistent): 67 if os.path.exists(persistent): 68 u_boot_console.log.action('Disk image file ' + persistent + 69 ' already exists') 70 else: 71 u_boot_console.log.action('Generating ' + persistent) 72 fd = os.open(persistent, os.O_RDWR | os.O_CREAT) 73 os.ftruncate(fd, 4194304) 74 os.close(fd) 75 cmd = ('sgdisk', 76 '--disk-guid=375a56f7-d6c9-4e81-b5f0-09d41ca89efe', 77 persistent) 78 u_boot_utils.run_and_log(u_boot_console, cmd) 79 # part1 offset 1MB size 1MB 80 cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', 81 '--partition-guid=1:33194895-67f6-4561-8457-6fdeed4f50a3', 82 '-A 1:set:2', 83 persistent) 84 # part2 offset 2MB size 1.5MB 85 u_boot_utils.run_and_log(u_boot_console, cmd) 86 cmd = ('sgdisk', '--new=2:4096:7167', '--change-name=2:part2', 87 '--partition-guid=2:cc9c6e4a-6551-4cb5-87be-3210f96c86fb', 88 persistent) 89 u_boot_utils.run_and_log(u_boot_console, cmd) 90 cmd = ('sgdisk', '--load-backup=' + persistent) 91 u_boot_utils.run_and_log(u_boot_console, cmd) 92 93 cmd = ('cp', persistent, self.path) 94 u_boot_utils.run_and_log(u_boot_console, cmd) 95 96@pytest.fixture(scope='function') 97def state_disk_image(u_boot_console): 98 """pytest fixture to provide a GptTestDiskImage object to tests. 99 This is function-scoped because it uses u_boot_console, which is also 100 function-scoped. A new disk is returned each time to prevent tests from 101 interfering with each other.""" 102 103 return GptTestDiskImage(u_boot_console) 104 105@pytest.mark.boardspec('sandbox') 106@pytest.mark.buildconfigspec('cmd_gpt') 107@pytest.mark.buildconfigspec('cmd_part') 108@pytest.mark.requiredtool('sgdisk') 109def test_gpt_read(state_disk_image, u_boot_console): 110 """Test the gpt read command.""" 111 112 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 113 output = u_boot_console.run_command('gpt read host 0') 114 assert 'Start 1MiB, size 1MiB' in output 115 assert 'Block size 512, name part1' in output 116 assert 'Start 2MiB, size 1MiB' in output 117 assert 'Block size 512, name part2' in output 118 output = u_boot_console.run_command('part list host 0') 119 assert '0x00000800 0x00000fff "part1"' in output 120 assert '0x00001000 0x00001bff "part2"' in output 121 122@pytest.mark.boardspec('sandbox') 123@pytest.mark.buildconfigspec('cmd_gpt') 124@pytest.mark.buildconfigspec('partition_type_guid') 125@pytest.mark.requiredtool('sgdisk') 126def test_gpt_read_var(state_disk_image, u_boot_console): 127 """Test the gpt read command.""" 128 129 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 130 output = u_boot_console.run_command('gpt read host 0 gpt_parts') 131 assert 'success!' in output 132 133 output = u_boot_console.run_command('echo ${gpt_parts}') 134 parts = parse_gpt_parts(output.rstrip()) 135 136 assert parts == [ 137 { 138 "uuid_disk": "375a56f7-d6c9-4e81-b5f0-09d41ca89efe", 139 }, 140 { 141 "name": "part1", 142 "start": "0x100000", 143 "size": "0x100000", 144 "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", 145 "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", 146 "bootable": True, 147 }, 148 { 149 "name": "part2", 150 "start": "0x200000", 151 "size": "0x180000", 152 "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", 153 "uuid": "cc9c6e4a-6551-4cb5-87be-3210f96c86fb", 154 }, 155 ] 156 157@pytest.mark.boardspec('sandbox') 158@pytest.mark.buildconfigspec('cmd_gpt') 159@pytest.mark.requiredtool('sgdisk') 160def test_gpt_verify(state_disk_image, u_boot_console): 161 """Test the gpt verify command.""" 162 163 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 164 output = u_boot_console.run_command('gpt verify host 0') 165 assert 'Verify GPT: success!' in output 166 167@pytest.mark.boardspec('sandbox') 168@pytest.mark.buildconfigspec('cmd_gpt') 169@pytest.mark.requiredtool('sgdisk') 170def test_gpt_repair(state_disk_image, u_boot_console): 171 """Test the gpt repair command.""" 172 173 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 174 output = u_boot_console.run_command('gpt repair host 0') 175 assert 'Repairing GPT: success!' in output 176 177@pytest.mark.boardspec('sandbox') 178@pytest.mark.buildconfigspec('cmd_gpt') 179@pytest.mark.requiredtool('sgdisk') 180def test_gpt_guid(state_disk_image, u_boot_console): 181 """Test the gpt guid command.""" 182 183 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 184 output = u_boot_console.run_command('gpt guid host 0') 185 assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output 186 187@pytest.mark.boardspec('sandbox') 188@pytest.mark.buildconfigspec('cmd_gpt') 189@pytest.mark.requiredtool('sgdisk') 190def test_gpt_setenv(state_disk_image, u_boot_console): 191 """Test the gpt setenv command.""" 192 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 193 output = u_boot_console.run_command('gpt setenv host 0 part1') 194 assert 'success!' in output 195 output = u_boot_console.run_command('echo ${gpt_partition_addr}') 196 assert output.rstrip() == '800' 197 output = u_boot_console.run_command('echo ${gpt_partition_size}') 198 assert output.rstrip() == '800' 199 output = u_boot_console.run_command('echo ${gpt_partition_name}') 200 assert output.rstrip() == 'part1' 201 output = u_boot_console.run_command('echo ${gpt_partition_entry}') 202 assert output.rstrip() == '1' 203 output = u_boot_console.run_command('echo ${gpt_partition_bootable}') 204 assert output.rstrip() == '1' 205 206 output = u_boot_console.run_command('gpt setenv host 0 part2') 207 assert 'success!' in output 208 output = u_boot_console.run_command('echo ${gpt_partition_addr}') 209 assert output.rstrip() == '1000' 210 output = u_boot_console.run_command('echo ${gpt_partition_size}') 211 assert output.rstrip() == 'c00' 212 output = u_boot_console.run_command('echo ${gpt_partition_name}') 213 assert output.rstrip() == 'part2' 214 output = u_boot_console.run_command('echo ${gpt_partition_entry}') 215 assert output.rstrip() == '2' 216 output = u_boot_console.run_command('echo ${gpt_partition_bootable}') 217 assert output.rstrip() == '0' 218 219@pytest.mark.boardspec('sandbox') 220@pytest.mark.buildconfigspec('cmd_gpt') 221@pytest.mark.requiredtool('sgdisk') 222def test_gpt_save_guid(state_disk_image, u_boot_console): 223 """Test the gpt guid command to save GUID into a string.""" 224 225 if u_boot_console.config.buildconfig.get('config_cmd_gpt', 'n') != 'y': 226 pytest.skip('gpt command not supported') 227 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 228 output = u_boot_console.run_command('gpt guid host 0 newguid') 229 output = u_boot_console.run_command('printenv newguid') 230 assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output 231 232@pytest.mark.boardspec('sandbox') 233@pytest.mark.buildconfigspec('cmd_gpt') 234@pytest.mark.requiredtool('sgdisk') 235def test_gpt_part_type_uuid(state_disk_image, u_boot_console): 236 """Test the gpt partittion type UUID command.""" 237 238 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 239 output = u_boot_console.run_command('part type host 0:1') 240 assert '0fc63daf-8483-4772-8e79-3d69d8477de4' in output 241 242@pytest.mark.boardspec('sandbox') 243@pytest.mark.buildconfigspec('cmd_gpt') 244@pytest.mark.requiredtool('sgdisk') 245def test_gpt_part_type_save_uuid(state_disk_image, u_boot_console): 246 """Test the gpt partittion type to save UUID into a string.""" 247 248 if u_boot_console.config.buildconfig.get('config_cmd_gpt', 'n') != 'y': 249 pytest.skip('gpt command not supported') 250 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 251 output = u_boot_console.run_command('part type host 0:1 newguid') 252 output = u_boot_console.run_command('printenv newguid') 253 assert '0fc63daf-8483-4772-8e79-3d69d8477de4' in output 254 255@pytest.mark.boardspec('sandbox') 256@pytest.mark.buildconfigspec('cmd_gpt') 257@pytest.mark.buildconfigspec('cmd_gpt_rename') 258@pytest.mark.buildconfigspec('cmd_part') 259@pytest.mark.requiredtool('sgdisk') 260def test_gpt_rename_partition(state_disk_image, u_boot_console): 261 """Test the gpt rename command to write partition names.""" 262 263 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 264 u_boot_console.run_command('gpt rename host 0 1 first') 265 output = u_boot_console.run_command('gpt read host 0') 266 assert 'name first' in output 267 u_boot_console.run_command('gpt rename host 0 2 second') 268 output = u_boot_console.run_command('gpt read host 0') 269 assert 'name second' in output 270 output = u_boot_console.run_command('part list host 0') 271 assert '0x00000800 0x00000fff "first"' in output 272 assert '0x00001000 0x00001bff "second"' in output 273 274@pytest.mark.boardspec('sandbox') 275@pytest.mark.buildconfigspec('cmd_gpt') 276@pytest.mark.buildconfigspec('cmd_gpt_rename') 277@pytest.mark.buildconfigspec('cmd_part') 278@pytest.mark.requiredtool('sgdisk') 279def test_gpt_swap_partitions(state_disk_image, u_boot_console): 280 """Test the gpt swap command to exchange two partition names.""" 281 282 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 283 output = u_boot_console.run_command('part list host 0') 284 assert '0x00000800 0x00000fff "part1"' in output 285 assert '0x00001000 0x00001bff "part2"' in output 286 u_boot_console.run_command('gpt swap host 0 part1 part2') 287 output = u_boot_console.run_command('part list host 0') 288 assert '0x00000800 0x00000fff "part2"' in output 289 assert '0x00001000 0x00001bff "part1"' in output 290 291@pytest.mark.buildconfigspec('cmd_gpt') 292@pytest.mark.buildconfigspec('cmd_gpt_rename') 293@pytest.mark.buildconfigspec('cmd_part') 294@pytest.mark.requiredtool('sgdisk') 295def test_gpt_set_bootable(state_disk_image, u_boot_console): 296 """Test the gpt set-bootable command.""" 297 298 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 299 parts = ('part2', 'part1') 300 for bootable in parts: 301 output = u_boot_console.run_command(f'gpt set-bootable host 0 {bootable}') 302 assert 'success!' in output 303 304 for p in parts: 305 output = u_boot_console.run_command(f'gpt setenv host 0 {p}') 306 assert 'success!' in output 307 output = u_boot_console.run_command('echo ${gpt_partition_bootable}') 308 if p == bootable: 309 assert output.rstrip() == '1' 310 else: 311 assert output.rstrip() == '0' 312 313@pytest.mark.boardspec('sandbox') 314@pytest.mark.buildconfigspec('cmd_gpt') 315@pytest.mark.buildconfigspec('cmd_part') 316@pytest.mark.requiredtool('sgdisk') 317def test_gpt_write(state_disk_image, u_boot_console): 318 """Test the gpt write command.""" 319 320 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 321 output = u_boot_console.run_command('gpt write host 0 "name=all,size=0"') 322 assert 'Writing GPT: success!' in output 323 output = u_boot_console.run_command('part list host 0') 324 assert '0x00000022 0x00001fde "all"' in output 325 output = u_boot_console.run_command('gpt write host 0 "uuid_disk=375a56f7-d6c9-4e81-b5f0-09d41ca89efe;name=first,start=1M,size=1M;name=second,start=0x200000,size=0x180000;"') 326 assert 'Writing GPT: success!' in output 327 output = u_boot_console.run_command('part list host 0') 328 assert '0x00000800 0x00000fff "first"' in output 329 assert '0x00001000 0x00001bff "second"' in output 330 output = u_boot_console.run_command('gpt guid host 0') 331 assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output 332 333@pytest.mark.buildconfigspec('cmd_gpt') 334@pytest.mark.buildconfigspec('cmd_gpt_rename') 335@pytest.mark.buildconfigspec('cmd_part') 336@pytest.mark.requiredtool('sgdisk') 337def test_gpt_transpose(state_disk_image, u_boot_console): 338 """Test the gpt transpose command.""" 339 340 u_boot_console.run_command('host bind 0 ' + state_disk_image.path) 341 output = u_boot_console.run_command('part list host 0') 342 assert '1\t0x00000800\t0x00000fff\t"part1"' in output 343 assert '2\t0x00001000\t0x00001bff\t"part2"' in output 344 345 output = u_boot_console.run_command('gpt transpose host 0 1 2') 346 assert 'success!' in output 347 348 output = u_boot_console.run_command('part list host 0') 349 assert '2\t0x00000800\t0x00000fff\t"part1"' in output 350 assert '1\t0x00001000\t0x00001bff\t"part2"' in output 351