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 = efi_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 312 /* Connect controller to virtual disk */ 313 ret = boottime->connect_controller(disk_handle, NULL, NULL, 1); 314 if (ret != EFI_SUCCESS) { 315 efi_st_error("Failed to connect controller\n"); 316 return EFI_ST_FAILURE; 317 } 318 319 /* Get the handle for the partition */ 320 ret = boottime->locate_handle_buffer( 321 BY_PROTOCOL, &guid_device_path, NULL, 322 &no_handles, &handles); 323 if (ret != EFI_SUCCESS) { 324 efi_st_error("Failed to locate handles\n"); 325 return EFI_ST_FAILURE; 326 } 327 len = dp_size(dp); 328 for (i = 0; i < no_handles; ++i) { 329 ret = boottime->open_protocol(handles[i], &guid_device_path, 330 (void **)&dp_partition, 331 NULL, NULL, 332 EFI_OPEN_PROTOCOL_GET_PROTOCOL); 333 if (ret != EFI_SUCCESS) { 334 efi_st_error("Failed to open device path protocol\n"); 335 return EFI_ST_FAILURE; 336 } 337 if (len >= dp_size(dp_partition)) 338 continue; 339 if (efi_st_memcmp(dp, dp_partition, len)) 340 continue; 341 handle_partition = handles[i]; 342 break; 343 } 344 ret = boottime->free_pool(handles); 345 if (ret != EFI_SUCCESS) { 346 efi_st_error("Failed to free pool memory\n"); 347 return EFI_ST_FAILURE; 348 } 349 if (!handle_partition) { 350 efi_st_error("Partition handle not found\n"); 351 return EFI_ST_FAILURE; 352 } 353 354 /* Open the simple file system protocol */ 355 ret = boottime->open_protocol(handle_partition, 356 &guid_simple_file_system_protocol, 357 (void **)&file_system, NULL, NULL, 358 EFI_OPEN_PROTOCOL_GET_PROTOCOL); 359 if (ret != EFI_SUCCESS) { 360 efi_st_error("Failed to open simple file system protocol\n"); 361 return EFI_ST_FAILURE; 362 } 363 364 /* Open volume */ 365 ret = file_system->open_volume(file_system, &root); 366 if (ret != EFI_SUCCESS) { 367 efi_st_error("Failed to open volume\n"); 368 return EFI_ST_FAILURE; 369 } 370 buf_size = sizeof(system_info); 371 ret = root->getinfo(root, &guid_file_system_info, &buf_size, 372 &system_info); 373 if (ret != EFI_SUCCESS) { 374 efi_st_error("Failed to get file system info\n"); 375 return EFI_ST_FAILURE; 376 } 377 if (system_info.info.block_size != 512) { 378 efi_st_error("Wrong block size %u, expected 512\n", 379 system_info.info.block_size); 380 return EFI_ST_FAILURE; 381 } 382 if (efi_st_strcmp_16_8(system_info.info.volume_label, "U-BOOT TEST")) { 383 efi_st_todo( 384 "Wrong volume label '%ps', expected 'U-BOOT TEST'\n", 385 system_info.info.volume_label); 386 } 387 388 /* Read file */ 389 ret = root->open(root, &file, (s16 *)L"hello.txt", EFI_FILE_MODE_READ, 390 0); 391 if (ret != EFI_SUCCESS) { 392 efi_st_error("Failed to open file\n"); 393 return EFI_ST_FAILURE; 394 } 395 buf_size = sizeof(buf) - 1; 396 ret = file->read(file, &buf_size, buf); 397 if (ret != EFI_SUCCESS) { 398 efi_st_error("Failed to read file\n"); 399 return EFI_ST_FAILURE; 400 } 401 if (buf_size != 13) { 402 efi_st_error("Wrong number of bytes read: %u\n", 403 (unsigned int)buf_size); 404 return EFI_ST_FAILURE; 405 } 406 if (efi_st_memcmp(buf, "Hello world!", 12)) { 407 efi_st_error("Unexpected file content\n"); 408 return EFI_ST_FAILURE; 409 } 410 ret = file->close(file); 411 if (ret != EFI_SUCCESS) { 412 efi_st_error("Failed to close file\n"); 413 return EFI_ST_FAILURE; 414 } 415 416 #ifdef CONFIG_FAT_WRITE 417 /* Write file */ 418 ret = root->open(root, &file, (s16 *)L"u-boot.txt", 419 EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); 420 if (ret != EFI_SUCCESS) { 421 efi_st_error("Failed to open file\n"); 422 return EFI_ST_FAILURE; 423 } 424 buf_size = 7; 425 boottime->set_mem(buf, sizeof(buf), 0); 426 boottime->copy_mem(buf, "U-Boot", buf_size); 427 ret = file->write(file, &buf_size, buf); 428 if (ret != EFI_SUCCESS || buf_size != 7) { 429 efi_st_error("Failed to write file\n"); 430 return EFI_ST_FAILURE; 431 } 432 ret = file->close(file); 433 if (ret != EFI_SUCCESS) { 434 efi_st_error("Failed to close file\n"); 435 return EFI_ST_FAILURE; 436 } 437 438 /* Verify file */ 439 boottime->set_mem(buf, sizeof(buf), 0); 440 ret = root->open(root, &file, (s16 *)L"u-boot.txt", EFI_FILE_MODE_READ, 441 0); 442 if (ret != EFI_SUCCESS) { 443 efi_st_error("Failed to open file\n"); 444 return EFI_ST_FAILURE; 445 } 446 buf_size = sizeof(buf) - 1; 447 ret = file->read(file, &buf_size, buf); 448 if (ret != EFI_SUCCESS) { 449 efi_st_error("Failed to read file\n"); 450 return EFI_ST_FAILURE; 451 } 452 if (buf_size != 7) { 453 efi_st_error("Wrong number of bytes read: %u\n", 454 (unsigned int)buf_size); 455 return EFI_ST_FAILURE; 456 } 457 if (efi_st_memcmp(buf, "U-Boot", 7)) { 458 efi_st_error("Unexpected file content %s\n", buf); 459 return EFI_ST_FAILURE; 460 } 461 ret = file->close(file); 462 if (ret != EFI_SUCCESS) { 463 efi_st_error("Failed to close file\n"); 464 return EFI_ST_FAILURE; 465 } 466 #else 467 efi_st_todo("CONFIG_FAT_WRITE is not set\n"); 468 #endif /* CONFIG_FAT_WRITE */ 469 470 /* Close volume */ 471 ret = root->close(root); 472 if (ret != EFI_SUCCESS) { 473 efi_st_error("Failed to close volume\n"); 474 return EFI_ST_FAILURE; 475 } 476 477 return EFI_ST_SUCCESS; 478 } 479 480 EFI_UNIT_TEST(blkdev) = { 481 .name = "block device", 482 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 483 .setup = setup, 484 .execute = execute, 485 .teardown = teardown, 486 }; 487