1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * efi_selftest_block 4 * 5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 6 * 7 * This test checks the driver for block IO devices. 8 * A disk image is created in memory. 9 * A handle is created for the new block IO device. 10 * The block I/O protocol is installed on the handle. 11 * ConnectController is used to setup partitions and to install the simple 12 * file protocol. 13 * A known file is read from the file system and verified. 14 */ 15 16 #include <efi_selftest.h> 17 #include "efi_selftest_disk_image.h" 18 19 /* Block size of compressed disk image */ 20 #define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 21 22 /* Binary logarithm of the block size */ 23 #define LB_BLOCK_SIZE 9 24 25 static struct efi_boot_services *boottime; 26 27 static const efi_guid_t block_io_protocol_guid = BLOCK_IO_GUID; 28 static const efi_guid_t guid_device_path = DEVICE_PATH_GUID; 29 static const efi_guid_t guid_simple_file_system_protocol = 30 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; 31 static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID; 32 static efi_guid_t guid_vendor = 33 EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, 34 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xb7, 0xb8); 35 36 static struct efi_device_path *dp; 37 38 /* One 8 byte block of the compressed disk image */ 39 struct line { 40 size_t addr; 41 char *line; 42 }; 43 44 /* Compressed disk image */ 45 struct compressed_disk_image { 46 size_t length; 47 struct line lines[]; 48 }; 49 50 static const struct compressed_disk_image img = EFI_ST_DISK_IMG; 51 52 /* Decompressed disk image */ 53 static u8 *image; 54 55 /* 56 * Reset service of the block IO protocol. 57 * 58 * @this block IO protocol 59 * @return status code 60 */ 61 static efi_status_t EFIAPI reset( 62 struct efi_block_io *this, 63 char extended_verification) 64 { 65 return EFI_SUCCESS; 66 } 67 68 /* 69 * Read service of the block IO protocol. 70 * 71 * @this block IO protocol 72 * @media_id media id 73 * @lba start of the read in logical blocks 74 * @buffer_size number of bytes to read 75 * @buffer target buffer 76 * @return status code 77 */ 78 static efi_status_t EFIAPI read_blocks( 79 struct efi_block_io *this, u32 media_id, u64 lba, 80 efi_uintn_t buffer_size, void *buffer) 81 { 82 u8 *start; 83 84 if ((lba << LB_BLOCK_SIZE) + buffer_size > img.length) 85 return EFI_INVALID_PARAMETER; 86 start = image + (lba << LB_BLOCK_SIZE); 87 88 boottime->copy_mem(buffer, start, buffer_size); 89 90 return EFI_SUCCESS; 91 } 92 93 /* 94 * Write service of the block IO protocol. 95 * 96 * @this block IO protocol 97 * @media_id media id 98 * @lba start of the write in logical blocks 99 * @buffer_size number of bytes to read 100 * @buffer source buffer 101 * @return status code 102 */ 103 static efi_status_t EFIAPI write_blocks( 104 struct efi_block_io *this, u32 media_id, u64 lba, 105 efi_uintn_t buffer_size, void *buffer) 106 { 107 u8 *start; 108 109 if ((lba << LB_BLOCK_SIZE) + buffer_size > img.length) 110 return EFI_INVALID_PARAMETER; 111 start = image + (lba << LB_BLOCK_SIZE); 112 113 boottime->copy_mem(start, buffer, buffer_size); 114 115 return EFI_SUCCESS; 116 } 117 118 /* 119 * Flush service of the block IO protocol. 120 * 121 * @this block IO protocol 122 * @return status code 123 */ 124 static efi_status_t EFIAPI flush_blocks(struct efi_block_io *this) 125 { 126 return EFI_SUCCESS; 127 } 128 129 /* 130 * Decompress the disk image. 131 * 132 * @image decompressed disk image 133 * @return status code 134 */ 135 static efi_status_t decompress(u8 **image) 136 { 137 u8 *buf; 138 size_t i; 139 size_t addr; 140 size_t len; 141 efi_status_t ret; 142 143 ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, 144 (void **)&buf); 145 if (ret != EFI_SUCCESS) { 146 efi_st_error("Out of memory\n"); 147 return ret; 148 } 149 boottime->set_mem(buf, img.length, 0); 150 151 for (i = 0; ; ++i) { 152 if (!img.lines[i].line) 153 break; 154 addr = img.lines[i].addr; 155 len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; 156 if (addr + len > img.length) 157 len = img.length - addr; 158 boottime->copy_mem(buf + addr, img.lines[i].line, len); 159 } 160 *image = buf; 161 return ret; 162 } 163 164 static struct efi_block_io_media media; 165 166 static struct efi_block_io block_io = { 167 .media = &media, 168 .reset = reset, 169 .read_blocks = read_blocks, 170 .write_blocks = write_blocks, 171 .flush_blocks = flush_blocks, 172 }; 173 174 /* Handle for the block IO device */ 175 static efi_handle_t disk_handle; 176 177 /* 178 * Setup unit test. 179 * 180 * @handle: handle of the loaded image 181 * @systable: system table 182 * @return: EFI_ST_SUCCESS for success 183 */ 184 static int setup(const efi_handle_t handle, 185 const struct efi_system_table *systable) 186 { 187 efi_status_t ret; 188 struct efi_device_path_vendor vendor_node; 189 struct efi_device_path end_node; 190 191 boottime = systable->boottime; 192 193 decompress(&image); 194 195 block_io.media->block_size = 1 << LB_BLOCK_SIZE; 196 block_io.media->last_block = img.length >> LB_BLOCK_SIZE; 197 198 ret = boottime->install_protocol_interface( 199 &disk_handle, &block_io_protocol_guid, 200 EFI_NATIVE_INTERFACE, &block_io); 201 if (ret != EFI_SUCCESS) { 202 efi_st_error("Failed to install block I/O protocol\n"); 203 return EFI_ST_FAILURE; 204 } 205 206 ret = boottime->allocate_pool(EFI_LOADER_DATA, 207 sizeof(struct efi_device_path_vendor) + 208 sizeof(struct efi_device_path), 209 (void **)&dp); 210 if (ret != EFI_SUCCESS) { 211 efi_st_error("Out of memory\n"); 212 return EFI_ST_FAILURE; 213 } 214 vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; 215 vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR; 216 vendor_node.dp.length = sizeof(struct efi_device_path_vendor); 217 218 boottime->copy_mem(&vendor_node.guid, &guid_vendor, 219 sizeof(efi_guid_t)); 220 boottime->copy_mem(dp, &vendor_node, 221 sizeof(struct efi_device_path_vendor)); 222 end_node.type = DEVICE_PATH_TYPE_END; 223 end_node.sub_type = DEVICE_PATH_SUB_TYPE_END; 224 end_node.length = sizeof(struct efi_device_path); 225 226 boottime->copy_mem((char *)dp + sizeof(struct efi_device_path_vendor), 227 &end_node, sizeof(struct efi_device_path)); 228 ret = boottime->install_protocol_interface(&disk_handle, 229 &guid_device_path, 230 EFI_NATIVE_INTERFACE, 231 dp); 232 if (ret != EFI_SUCCESS) { 233 efi_st_error("InstallProtocolInterface failed\n"); 234 return EFI_ST_FAILURE; 235 } 236 return EFI_ST_SUCCESS; 237 } 238 239 /* 240 * Tear down unit test. 241 * 242 * @return: EFI_ST_SUCCESS for success 243 */ 244 static int teardown(void) 245 { 246 efi_status_t r = EFI_ST_SUCCESS; 247 248 if (disk_handle) { 249 r = boottime->uninstall_protocol_interface(disk_handle, 250 &guid_device_path, 251 dp); 252 if (r != EFI_SUCCESS) { 253 efi_st_error("Uninstall device path failed\n"); 254 return EFI_ST_FAILURE; 255 } 256 r = boottime->uninstall_protocol_interface( 257 disk_handle, &block_io_protocol_guid, 258 &block_io); 259 if (r != EFI_SUCCESS) { 260 efi_st_todo( 261 "Failed to uninstall block I/O protocol\n"); 262 return EFI_ST_SUCCESS; 263 } 264 } 265 266 if (image) { 267 r = boottime->free_pool(image); 268 if (r != EFI_SUCCESS) { 269 efi_st_error("Failed to free image\n"); 270 return EFI_ST_FAILURE; 271 } 272 } 273 return r; 274 } 275 276 /* 277 * Get length of device path without end tag. 278 * 279 * @dp device path 280 * @return length of device path in bytes 281 */ 282 static efi_uintn_t dp_size(struct efi_device_path *dp) 283 { 284 struct efi_device_path *pos = dp; 285 286 while (pos->type != DEVICE_PATH_TYPE_END) 287 pos = (struct efi_device_path *)((char *)pos + pos->length); 288 return (char *)pos - (char *)dp; 289 } 290 291 /* 292 * Execute unit test. 293 * 294 * @return: EFI_ST_SUCCESS for success 295 */ 296 static int execute(void) 297 { 298 efi_status_t ret; 299 efi_uintn_t no_handles, i, len; 300 efi_handle_t *handles; 301 efi_handle_t handle_partition = NULL; 302 struct efi_device_path *dp_partition; 303 struct efi_simple_file_system_protocol *file_system; 304 struct efi_file_handle *root, *file; 305 struct { 306 struct efi_file_system_info info; 307 u16 label[12]; 308 } system_info; 309 efi_uintn_t buf_size; 310 char buf[16] __aligned(ARCH_DMA_MINALIGN); 311 u64 pos; 312 313 /* Connect controller to virtual disk */ 314 ret = boottime->connect_controller(disk_handle, NULL, NULL, 1); 315 if (ret != EFI_SUCCESS) { 316 efi_st_error("Failed to connect controller\n"); 317 return EFI_ST_FAILURE; 318 } 319 320 /* Get the handle for the partition */ 321 ret = boottime->locate_handle_buffer( 322 BY_PROTOCOL, &guid_device_path, NULL, 323 &no_handles, &handles); 324 if (ret != EFI_SUCCESS) { 325 efi_st_error("Failed to locate handles\n"); 326 return EFI_ST_FAILURE; 327 } 328 len = dp_size(dp); 329 for (i = 0; i < no_handles; ++i) { 330 ret = boottime->open_protocol(handles[i], &guid_device_path, 331 (void **)&dp_partition, 332 NULL, NULL, 333 EFI_OPEN_PROTOCOL_GET_PROTOCOL); 334 if (ret != EFI_SUCCESS) { 335 efi_st_error("Failed to open device path protocol\n"); 336 return EFI_ST_FAILURE; 337 } 338 if (len >= dp_size(dp_partition)) 339 continue; 340 if (efi_st_memcmp(dp, dp_partition, len)) 341 continue; 342 handle_partition = handles[i]; 343 break; 344 } 345 ret = boottime->free_pool(handles); 346 if (ret != EFI_SUCCESS) { 347 efi_st_error("Failed to free pool memory\n"); 348 return EFI_ST_FAILURE; 349 } 350 if (!handle_partition) { 351 efi_st_error("Partition handle not found\n"); 352 return EFI_ST_FAILURE; 353 } 354 355 /* Open the simple file system protocol */ 356 ret = boottime->open_protocol(handle_partition, 357 &guid_simple_file_system_protocol, 358 (void **)&file_system, NULL, NULL, 359 EFI_OPEN_PROTOCOL_GET_PROTOCOL); 360 if (ret != EFI_SUCCESS) { 361 efi_st_error("Failed to open simple file system protocol\n"); 362 return EFI_ST_FAILURE; 363 } 364 365 /* Open volume */ 366 ret = file_system->open_volume(file_system, &root); 367 if (ret != EFI_SUCCESS) { 368 efi_st_error("Failed to open volume\n"); 369 return EFI_ST_FAILURE; 370 } 371 buf_size = sizeof(system_info); 372 ret = root->getinfo(root, &guid_file_system_info, &buf_size, 373 &system_info); 374 if (ret != EFI_SUCCESS) { 375 efi_st_error("Failed to get file system info\n"); 376 return EFI_ST_FAILURE; 377 } 378 if (system_info.info.block_size != 512) { 379 efi_st_error("Wrong block size %u, expected 512\n", 380 system_info.info.block_size); 381 return EFI_ST_FAILURE; 382 } 383 if (efi_st_strcmp_16_8(system_info.info.volume_label, "U-BOOT TEST")) { 384 efi_st_todo( 385 "Wrong volume label '%ps', expected 'U-BOOT TEST'\n", 386 system_info.info.volume_label); 387 } 388 389 /* Read file */ 390 ret = root->open(root, &file, L"hello.txt", EFI_FILE_MODE_READ, 391 0); 392 if (ret != EFI_SUCCESS) { 393 efi_st_error("Failed to open file\n"); 394 return EFI_ST_FAILURE; 395 } 396 ret = file->setpos(file, 1); 397 if (ret != EFI_SUCCESS) { 398 efi_st_error("SetPosition failed\n"); 399 return EFI_ST_FAILURE; 400 } 401 buf_size = sizeof(buf) - 1; 402 ret = file->read(file, &buf_size, buf); 403 if (ret != EFI_SUCCESS) { 404 efi_st_error("Failed to read file\n"); 405 return EFI_ST_FAILURE; 406 } 407 if (buf_size != 12) { 408 efi_st_error("Wrong number of bytes read: %u\n", 409 (unsigned int)buf_size); 410 return EFI_ST_FAILURE; 411 } 412 if (efi_st_memcmp(buf, "ello world!", 11)) { 413 efi_st_error("Unexpected file content\n"); 414 return EFI_ST_FAILURE; 415 } 416 ret = file->getpos(file, &pos); 417 if (ret != EFI_SUCCESS) { 418 efi_st_error("GetPosition failed\n"); 419 return EFI_ST_FAILURE; 420 } 421 if (pos != 13) { 422 efi_st_error("GetPosition returned %u, expected 13\n", 423 (unsigned int)pos); 424 return EFI_ST_FAILURE; 425 } 426 ret = file->close(file); 427 if (ret != EFI_SUCCESS) { 428 efi_st_error("Failed to close file\n"); 429 return EFI_ST_FAILURE; 430 } 431 432 #ifdef CONFIG_FAT_WRITE 433 /* Write file */ 434 ret = root->open(root, &file, L"u-boot.txt", EFI_FILE_MODE_READ | 435 EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); 436 if (ret != EFI_SUCCESS) { 437 efi_st_error("Failed to open file\n"); 438 return EFI_ST_FAILURE; 439 } 440 buf_size = 7; 441 boottime->set_mem(buf, sizeof(buf), 0); 442 boottime->copy_mem(buf, "U-Boot", buf_size); 443 ret = file->write(file, &buf_size, buf); 444 if (ret != EFI_SUCCESS || buf_size != 7) { 445 efi_st_error("Failed to write file\n"); 446 return EFI_ST_FAILURE; 447 } 448 ret = file->getpos(file, &pos); 449 if (ret != EFI_SUCCESS) { 450 efi_st_error("GetPosition failed\n"); 451 return EFI_ST_FAILURE; 452 } 453 if (pos != 7) { 454 efi_st_error("GetPosition returned %u, expected 7\n", 455 (unsigned int)pos); 456 return EFI_ST_FAILURE; 457 } 458 ret = file->close(file); 459 if (ret != EFI_SUCCESS) { 460 efi_st_error("Failed to close file\n"); 461 return EFI_ST_FAILURE; 462 } 463 464 /* Verify file */ 465 boottime->set_mem(buf, sizeof(buf), 0); 466 ret = root->open(root, &file, L"u-boot.txt", EFI_FILE_MODE_READ, 467 0); 468 if (ret != EFI_SUCCESS) { 469 efi_st_error("Failed to open file\n"); 470 return EFI_ST_FAILURE; 471 } 472 buf_size = sizeof(buf) - 1; 473 ret = file->read(file, &buf_size, buf); 474 if (ret != EFI_SUCCESS) { 475 efi_st_error("Failed to read file\n"); 476 return EFI_ST_FAILURE; 477 } 478 if (buf_size != 7) { 479 efi_st_error("Wrong number of bytes read: %u\n", 480 (unsigned int)buf_size); 481 return EFI_ST_FAILURE; 482 } 483 if (efi_st_memcmp(buf, "U-Boot", 7)) { 484 efi_st_error("Unexpected file content %s\n", buf); 485 return EFI_ST_FAILURE; 486 } 487 ret = file->close(file); 488 if (ret != EFI_SUCCESS) { 489 efi_st_error("Failed to close file\n"); 490 return EFI_ST_FAILURE; 491 } 492 #else 493 efi_st_todo("CONFIG_FAT_WRITE is not set\n"); 494 #endif /* CONFIG_FAT_WRITE */ 495 496 /* Close volume */ 497 ret = root->close(root); 498 if (ret != EFI_SUCCESS) { 499 efi_st_error("Failed to close volume\n"); 500 return EFI_ST_FAILURE; 501 } 502 503 return EFI_ST_SUCCESS; 504 } 505 506 EFI_UNIT_TEST(blkdev) = { 507 .name = "block device", 508 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 509 .setup = setup, 510 .execute = execute, 511 .teardown = teardown, 512 }; 513