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