1 // SPDX-License-Identifier: GPL-2.0+
5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
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
13 * A known file is read from the file system and verified.
16 #include <efi_selftest.h>
17 #include "efi_selftest_disk_image.h"
19 /* Block size of compressed disk image */
20 #define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
22 /* Binary logarithm of the block size */
23 #define LB_BLOCK_SIZE 9
25 static struct efi_boot_services
*boottime
;
27 static const efi_guid_t block_io_protocol_guid
= EFI_BLOCK_IO_PROTOCOL_GUID
;
28 static const efi_guid_t guid_device_path
= EFI_DEVICE_PATH_PROTOCOL_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);
36 static struct efi_device_path
*dp
;
38 /* One 8 byte block of the compressed disk image */
44 /* Compressed disk image */
45 struct compressed_disk_image
{
50 static const struct compressed_disk_image img
= EFI_ST_DISK_IMG
;
52 /* Decompressed disk image */
56 * Reset service of the block IO protocol.
58 * @this block IO protocol
61 static efi_status_t EFIAPI
reset(
62 struct efi_block_io
*this,
63 char extended_verification
)
69 * Read service of the block IO protocol.
71 * @this block IO protocol
73 * @lba start of the read in logical blocks
74 * @buffer_size number of bytes to read
75 * @buffer target buffer
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
)
84 if ((lba
<< LB_BLOCK_SIZE
) + buffer_size
> img
.length
)
85 return EFI_INVALID_PARAMETER
;
86 start
= image
+ (lba
<< LB_BLOCK_SIZE
);
88 boottime
->copy_mem(buffer
, start
, buffer_size
);
94 * Write service of the block IO protocol.
96 * @this block IO protocol
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
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
)
109 if ((lba
<< LB_BLOCK_SIZE
) + buffer_size
> img
.length
)
110 return EFI_INVALID_PARAMETER
;
111 start
= image
+ (lba
<< LB_BLOCK_SIZE
);
113 boottime
->copy_mem(start
, buffer
, buffer_size
);
119 * Flush service of the block IO protocol.
121 * @this block IO protocol
122 * @return status code
124 static efi_status_t EFIAPI
flush_blocks(struct efi_block_io
*this)
130 * Decompress the disk image.
132 * @image decompressed disk image
133 * @return status code
135 static efi_status_t
decompress(u8
**image
)
143 ret
= boottime
->allocate_pool(EFI_LOADER_DATA
, img
.length
,
145 if (ret
!= EFI_SUCCESS
) {
146 efi_st_error("Out of memory\n");
149 boottime
->set_mem(buf
, img
.length
, 0);
152 if (!img
.lines
[i
].line
)
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
);
164 static struct efi_block_io_media media
;
166 static struct efi_block_io block_io
= {
169 .read_blocks
= read_blocks
,
170 .write_blocks
= write_blocks
,
171 .flush_blocks
= flush_blocks
,
174 /* Handle for the block IO device */
175 static efi_handle_t disk_handle
;
180 * @handle: handle of the loaded image
181 * @systable: system table
182 * @return: EFI_ST_SUCCESS for success
184 static int setup(const efi_handle_t handle
,
185 const struct efi_system_table
*systable
)
188 struct efi_device_path_vendor vendor_node
;
189 struct efi_device_path end_node
;
191 boottime
= systable
->boottime
;
195 block_io
.media
->block_size
= 1 << LB_BLOCK_SIZE
;
196 block_io
.media
->last_block
= img
.length
>> LB_BLOCK_SIZE
;
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
;
206 ret
= boottime
->allocate_pool(EFI_LOADER_DATA
,
207 sizeof(struct efi_device_path_vendor
) +
208 sizeof(struct efi_device_path
),
210 if (ret
!= EFI_SUCCESS
) {
211 efi_st_error("Out of memory\n");
212 return EFI_ST_FAILURE
;
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
);
218 boottime
->copy_mem(&vendor_node
.guid
, &guid_vendor
,
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
);
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
,
230 EFI_NATIVE_INTERFACE
,
232 if (ret
!= EFI_SUCCESS
) {
233 efi_st_error("InstallProtocolInterface failed\n");
234 return EFI_ST_FAILURE
;
236 return EFI_ST_SUCCESS
;
240 * Tear down unit test.
242 * @return: EFI_ST_SUCCESS for success
244 static int teardown(void)
246 efi_status_t r
= EFI_ST_SUCCESS
;
249 r
= boottime
->uninstall_protocol_interface(disk_handle
,
252 if (r
!= EFI_SUCCESS
) {
253 efi_st_error("Uninstall device path failed\n");
254 return EFI_ST_FAILURE
;
256 r
= boottime
->uninstall_protocol_interface(
257 disk_handle
, &block_io_protocol_guid
,
259 if (r
!= EFI_SUCCESS
) {
261 "Failed to uninstall block I/O protocol\n");
262 return EFI_ST_SUCCESS
;
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
;
277 * Get length of device path without end tag.
280 * @return length of device path in bytes
282 static efi_uintn_t
dp_size(struct efi_device_path
*dp
)
284 struct efi_device_path
*pos
= dp
;
286 while (pos
->type
!= DEVICE_PATH_TYPE_END
)
287 pos
= (struct efi_device_path
*)((char *)pos
+ pos
->length
);
288 return (char *)pos
- (char *)dp
;
294 * @return: EFI_ST_SUCCESS for success
296 static int execute(void)
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
;
306 struct efi_file_system_info info
;
309 efi_uintn_t buf_size
;
310 char buf
[16] __aligned(ARCH_DMA_MINALIGN
);
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
;
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
;
329 for (i
= 0; i
< no_handles
; ++i
) {
330 ret
= boottime
->open_protocol(handles
[i
], &guid_device_path
,
331 (void **)&dp_partition
,
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
;
338 if (len
>= dp_size(dp_partition
))
340 if (efi_st_memcmp(dp
, dp_partition
, len
))
342 handle_partition
= handles
[i
];
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
;
350 if (!handle_partition
) {
351 efi_st_error("Partition handle not found\n");
352 return EFI_ST_FAILURE
;
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
;
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
;
371 buf_size
= sizeof(system_info
);
372 ret
= root
->getinfo(root
, &guid_file_system_info
, &buf_size
,
374 if (ret
!= EFI_SUCCESS
) {
375 efi_st_error("Failed to get file system info\n");
376 return EFI_ST_FAILURE
;
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
;
383 if (efi_st_strcmp_16_8(system_info
.info
.volume_label
, "U-BOOT TEST")) {
385 "Wrong volume label '%ps', expected 'U-BOOT TEST'\n",
386 system_info
.info
.volume_label
);
390 ret
= root
->open(root
, &file
, L
"hello.txt", EFI_FILE_MODE_READ
,
392 if (ret
!= EFI_SUCCESS
) {
393 efi_st_error("Failed to open file\n");
394 return EFI_ST_FAILURE
;
396 ret
= file
->setpos(file
, 1);
397 if (ret
!= EFI_SUCCESS
) {
398 efi_st_error("SetPosition failed\n");
399 return EFI_ST_FAILURE
;
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
;
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
;
412 if (efi_st_memcmp(buf
, "ello world!", 11)) {
413 efi_st_error("Unexpected file content\n");
414 return EFI_ST_FAILURE
;
416 ret
= file
->getpos(file
, &pos
);
417 if (ret
!= EFI_SUCCESS
) {
418 efi_st_error("GetPosition failed\n");
419 return EFI_ST_FAILURE
;
422 efi_st_error("GetPosition returned %u, expected 13\n",
424 return EFI_ST_FAILURE
;
426 ret
= file
->close(file
);
427 if (ret
!= EFI_SUCCESS
) {
428 efi_st_error("Failed to close file\n");
429 return EFI_ST_FAILURE
;
432 #ifdef CONFIG_FAT_WRITE
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
;
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
;
448 ret
= file
->getpos(file
, &pos
);
449 if (ret
!= EFI_SUCCESS
) {
450 efi_st_error("GetPosition failed\n");
451 return EFI_ST_FAILURE
;
454 efi_st_error("GetPosition returned %u, expected 7\n",
456 return EFI_ST_FAILURE
;
458 ret
= file
->close(file
);
459 if (ret
!= EFI_SUCCESS
) {
460 efi_st_error("Failed to close file\n");
461 return EFI_ST_FAILURE
;
465 boottime
->set_mem(buf
, sizeof(buf
), 0);
466 ret
= root
->open(root
, &file
, L
"u-boot.txt", EFI_FILE_MODE_READ
,
468 if (ret
!= EFI_SUCCESS
) {
469 efi_st_error("Failed to open file\n");
470 return EFI_ST_FAILURE
;
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
;
479 efi_st_error("Wrong number of bytes read: %u\n",
480 (unsigned int)buf_size
);
481 return EFI_ST_FAILURE
;
483 if (efi_st_memcmp(buf
, "U-Boot", 7)) {
484 efi_st_error("Unexpected file content %s\n", buf
);
485 return EFI_ST_FAILURE
;
487 ret
= file
->close(file
);
488 if (ret
!= EFI_SUCCESS
) {
489 efi_st_error("Failed to close file\n");
490 return EFI_ST_FAILURE
;
493 efi_st_todo("CONFIG_FAT_WRITE is not set\n");
494 #endif /* CONFIG_FAT_WRITE */
497 ret
= root
->close(root
);
498 if (ret
!= EFI_SUCCESS
) {
499 efi_st_error("Failed to close volume\n");
500 return EFI_ST_FAILURE
;
503 return EFI_ST_SUCCESS
;
506 EFI_UNIT_TEST(blkdev
) = {
507 .name
= "block device",
508 .phase
= EFI_EXECUTE_BEFORE_BOOTTIME_EXIT
,
511 .teardown
= teardown
,