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 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 u64 buf_size; 306 char buf[16] __aligned(ARCH_DMA_MINALIGN); 307 308 ret = boottime->connect_controller(disk_handle, NULL, NULL, 1); 309 if (ret != EFI_SUCCESS) { 310 efi_st_error("Failed to connect controller\n"); 311 return EFI_ST_FAILURE; 312 } 313 ret = boottime->locate_handle_buffer( 314 BY_PROTOCOL, &guid_device_path, NULL, 315 &no_handles, &handles); 316 if (ret != EFI_SUCCESS) { 317 efi_st_error("Failed to locate handles\n"); 318 return EFI_ST_FAILURE; 319 } 320 len = dp_size(dp); 321 for (i = 0; i < no_handles; ++i) { 322 ret = boottime->open_protocol(handles[i], &guid_device_path, 323 (void **)&dp_partition, 324 NULL, NULL, 325 EFI_OPEN_PROTOCOL_GET_PROTOCOL); 326 if (ret != EFI_SUCCESS) { 327 efi_st_error("Failed to open device path protocol\n"); 328 return EFI_ST_FAILURE; 329 } 330 if (len >= dp_size(dp_partition)) 331 continue; 332 if (efi_st_memcmp(dp, dp_partition, len)) 333 continue; 334 handle_partition = handles[i]; 335 break; 336 } 337 ret = boottime->free_pool(handles); 338 if (ret != EFI_SUCCESS) { 339 efi_st_error("Failed to free pool memory\n"); 340 return EFI_ST_FAILURE; 341 } 342 if (!handle_partition) { 343 efi_st_error("Partition handle not found\n"); 344 return EFI_ST_FAILURE; 345 } 346 ret = boottime->open_protocol(handle_partition, 347 &guid_simple_file_system_protocol, 348 (void **)&file_system, NULL, NULL, 349 EFI_OPEN_PROTOCOL_GET_PROTOCOL); 350 if (ret != EFI_SUCCESS) { 351 efi_st_error("Failed to open simple file system protocol\n"); 352 return EFI_ST_FAILURE; 353 } 354 ret = file_system->open_volume(file_system, &root); 355 if (ret != EFI_SUCCESS) { 356 efi_st_error("Failed to open volume\n"); 357 return EFI_ST_FAILURE; 358 } 359 ret = root->open(root, &file, (s16 *)L"hello.txt", EFI_FILE_MODE_READ, 360 0); 361 if (ret != EFI_SUCCESS) { 362 efi_st_error("Failed to open file\n"); 363 return EFI_ST_FAILURE; 364 } 365 buf_size = sizeof(buf) - 1; 366 ret = file->read(file, &buf_size, buf); 367 if (ret != EFI_SUCCESS) { 368 efi_st_error("Failed to read file\n"); 369 return EFI_ST_FAILURE; 370 } 371 if (efi_st_memcmp(buf, "Hello world!", 12)) { 372 efi_st_error("Unexpected file content\n"); 373 return EFI_ST_FAILURE; 374 } 375 ret = file->close(file); 376 if (ret != EFI_SUCCESS) { 377 efi_st_error("Failed to close file\n"); 378 return EFI_ST_FAILURE; 379 } 380 ret = root->close(root); 381 if (ret != EFI_SUCCESS) { 382 efi_st_error("Failed to close volume\n"); 383 return EFI_ST_FAILURE; 384 } 385 386 return EFI_ST_SUCCESS; 387 } 388 389 EFI_UNIT_TEST(blkdev) = { 390 .name = "block device", 391 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 392 .setup = setup, 393 .execute = execute, 394 .teardown = teardown, 395 }; 396