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