[PATCH 0/4] introduce EFI_RAM_DISK_PROTOCOL

This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO
000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO
000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO] - udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

This is a preparation to add the EFI_RAM_DISK_PROTOCOL. This commit adds the RAM disk device path structure and text conversion to Device Path to Text Protocol.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- include/efi_api.h | 19 +++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 14 ++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/include/efi_api.h b/include/efi_api.h index 55a4c989fc..4ee4a1b5e9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -682,6 +682,7 @@ struct efi_device_path_uri { # define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02 # define DEVICE_PATH_SUB_TYPE_VENDOR_PATH 0x03 # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 +# define DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH 0x09
struct efi_device_path_hard_drive_path { struct efi_device_path dp; @@ -705,6 +706,24 @@ struct efi_device_path_file_path { u16 str[]; } __packed;
+/* This GUID defines a RAM Disk supporting a raw disk format in volatile memory */ +#define EFI_VIRTUAL_DISK_GUID \ + EFI_GUID(0x77ab535a, 0x45fc, 0x624b, \ + 0x55, 0x60, 0xf7, 0xb2, 0x81, 0xd1, 0xf9, 0x6e) + +/* This GUID defines a RAM Disk supporting an ISO image in volatile memory */ +#define EFI_VIRTUAL_CD_GUID \ + EFI_GUID(0x3d5abd30, 0x4175, 0x87ce, \ + 0x6d, 0x64, 0xd2, 0xad, 0xe5, 0x23, 0xc4, 0xbb) + +struct efi_device_path_ram_disk_path { + struct efi_device_path dp; + u64 starting_address; + u64 ending_address; + efi_guid_t disk_type_guid; + u16 disk_instance; +} __packed; + #define EFI_BLOCK_IO_PROTOCOL_GUID \ EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 8c76d8be60..4395e79f33 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -324,6 +324,20 @@ static char *dp_media(char *s, struct efi_device_path *dp) free(buffer); break; } + case DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH: { + struct efi_device_path_ram_disk_path *rddp = + (struct efi_device_path_ram_disk_path *)dp; + u64 start; + u64 end; + + /* Copy from packed structure to aligned memory */ + memcpy(&start, &rddp->starting_address, sizeof(start)); + memcpy(&end, &rddp->ending_address, sizeof(end)); + + s += sprintf(s, "RamDisk(0x%llx,%llx,%pUl,0x%x)", start, end, + &rddp->disk_type_guid, rddp->disk_instance); + break; + } default: s = dp_unknown(s, dp); break;

This commit adds the EFI_RAM_DISK_PROTOCOL implementation. User can mount the distro installer by registering the memory mapped ISO image through EFI_RAM_DISK_PROTOCOL.
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- include/efi_api.h | 13 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_ram_disk.c | 334 ++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/uuid.c | 4 + 8 files changed, 373 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c
diff --git a/include/efi_api.h b/include/efi_api.h index 4ee4a1b5e9..3982ab89bc 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -764,6 +764,19 @@ struct efi_block_io { efi_status_t (EFIAPI *flush_blocks)(struct efi_block_io *this); };
+#define EFI_RAM_DISK_PROTOCOL_GUID \ + EFI_GUID(0xab38a0df, 0x6873, 0x44a9, \ + 0x87, 0xe6, 0xd4, 0xeb, 0x56, 0x14, 0x84, 0x49) + +struct efi_ram_disk_protocol { + /* "register" is a reserved keyword in C, use "disk_register" instead */ + efi_status_t(EFIAPI *disk_register)( + u64 ram_disk_base, u64 ram_disk_size, efi_guid_t *ram_disk_type, + struct efi_device_path *parent_device_path, + struct efi_device_path **device_path); + efi_status_t (EFIAPI *unregister)(struct efi_device_path *device_path); +}; + struct simple_text_output_mode { s32 max_mode; s32 mode; diff --git a/include/efi_loader.h b/include/efi_loader.h index 604fd765f7..70c8c83099 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -333,6 +333,8 @@ extern const efi_guid_t smbios_guid; /*GUID of console */ extern const efi_guid_t efi_guid_text_input_protocol; extern const efi_guid_t efi_guid_text_output_protocol; +/* GUID of Ram Disk protocol */ +extern const efi_guid_t efi_guid_ram_disk_protocol;
extern char __efi_runtime_start[], __efi_runtime_stop[]; extern char __efi_runtime_rel_start[], __efi_runtime_rel_stop[]; @@ -1159,4 +1161,6 @@ efi_status_t efi_disk_get_device_name(const efi_handle_t handle, char *buf, int */ void efi_add_known_memory(void);
+efi_status_t efi_ram_disk_register(void); + #endif /* _EFI_LOADER_H */ diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c index 45f9351988..f7597811b7 100644 --- a/lib/efi_driver/efi_uclass.c +++ b/lib/efi_driver/efi_uclass.c @@ -44,8 +44,11 @@ static efi_status_t check_node_type(efi_handle_t handle) /* Get the last node */ const struct efi_device_path *node = efi_dp_last_node(dp); /* We do not support partitions as controller */ - if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE) - ret = EFI_UNSUPPORTED; + if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE) { + /* We support RAM disk as controller */ + if (node->sub_type != DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH) + ret = EFI_UNSUPPORTED; + } } return ret; } diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index c5835e6ef6..1a81b65688 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -433,4 +433,10 @@ config EFI_RISCV_BOOT_PROTOCOL replace the transfer via the device-tree. The latter is not possible on systems using ACPI.
+config EFI_RAM_DISK_PROTOCOL + bool "EFI_RAM_DISK_PROTOCOL support" + depends on PARTITIONS + help + Provide a EFI_RAM_DISK_PROTOCOL implementation to register the + RAM disk and create the block device. endif diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 1a8c8d7cab..4197f594a2 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o obj-$(CONFIG_EFI_SIGNATURE_SUPPORT) += efi_signature.o obj-$(CONFIG_EFI_ECPT) += efi_conformance.o +obj-$(CONFIG_EFI_RAM_DISK_PROTOCOL) += efi_ram_disk.o
EFI_VAR_SEED_FILE := $(subst $",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) diff --git a/lib/efi_loader/efi_ram_disk.c b/lib/efi_loader/efi_ram_disk.c new file mode 100644 index 0000000000..10a6944aea --- /dev/null +++ b/lib/efi_loader/efi_ram_disk.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * RAM Disk Protocol + * + * Copyright (c) 2023, Linaro Limited + */ + +#include <efi_driver.h> +#include <malloc.h> +#include <linux/unaligned/le_byteshift.h> +#include <linux/unaligned/generic.h> + +#define MEM_BLOCK_SIZE_SHIFT 9 /* 512 bytes */ + +const efi_guid_t efi_guid_ram_disk_protocol = EFI_RAM_DISK_PROTOCOL_GUID; +static struct list_head obj_list; + +/** + * struct efi_ram_disk_obj - ram disk protocol object + * + * @ops: EFI disk I/O protocol interface + * @media: block I/O media information + * @dp: device path + * @image: image base address + * @image_size: image size + * @list: list structure + */ +struct efi_ram_disk_obj { + struct efi_block_io ops; + struct efi_block_io_media media; + struct efi_device_path *dp; + u8 *image; + u64 image_size; + struct list_head list; +}; + +/* + * reset - Reset service of the block IO protocol + * + * @this: pointer to the BLOCK_IO_PROTOCOL + * @extended_verification: extended verification + * Return: status code + */ +static efi_status_t EFIAPI reset(struct efi_block_io *this, + char extended_verification) +{ + return EFI_SUCCESS; +} + +/* + * read_blocks - Read service of the block IO protocol + * + * @this: pointer to the BLOCK_IO_PROTOCOL + * @media_id: id of the medium to be read from + * @lba: starting logical block for reading + * @buffer_size: size of the read buffer + * @buffer: pointer to the destination buffer + * Return: status code + */ +static efi_status_t EFIAPI read_blocks(struct efi_block_io *this, u32 media_id, + u64 lba, efi_uintn_t buffer_size, + void *buffer) +{ + u8 *start; + struct efi_ram_disk_obj *ram_disk_obj; + + if (!this || !buffer) + return EFI_INVALID_PARAMETER; + + if (!buffer_size) + return EFI_SUCCESS; + + /* TODO: check for media changes */ + if (media_id != this->media->media_id) + return EFI_MEDIA_CHANGED; + + if (!this->media->media_present) + return EFI_NO_MEDIA; + + EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba, + buffer_size, buffer); + + ram_disk_obj = container_of(this, struct efi_ram_disk_obj, ops); + + if ((lba << MEM_BLOCK_SIZE_SHIFT) + buffer_size > + ram_disk_obj->image_size) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + start = ram_disk_obj->image + (lba << MEM_BLOCK_SIZE_SHIFT); + memmove(buffer, start, buffer_size); + + return EFI_EXIT(EFI_SUCCESS); +} + +/* + * write_blocks - Write service of the block IO protocol + * + * @this: pointer to the BLOCK_IO_PROTOCOL + * @media_id: id of the medium to be written to + * @lba: starting logical block for writing + * @buffer_size: size of the write buffer + * @buffer: pointer to the source buffer + * Return: status code + */ +static efi_status_t EFIAPI write_blocks(struct efi_block_io *this, u32 media_id, + u64 lba, efi_uintn_t buffer_size, + void *buffer) +{ + u8 *start; + struct efi_ram_disk_obj *ram_disk_obj; + + if (!this || !buffer) + return EFI_INVALID_PARAMETER; + + if (this->media->read_only) + return EFI_WRITE_PROTECTED; + + if (!buffer_size) + return EFI_SUCCESS; + + /* TODO: check for media changes */ + if (media_id != this->media->media_id) + return EFI_MEDIA_CHANGED; + + if (!this->media->media_present) + return EFI_NO_MEDIA; + + EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba, + buffer_size, buffer); + + ram_disk_obj = container_of(this, struct efi_ram_disk_obj, ops); + + if ((lba << MEM_BLOCK_SIZE_SHIFT) + buffer_size > + ram_disk_obj->image_size) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + start = ram_disk_obj->image + (lba << MEM_BLOCK_SIZE_SHIFT); + memmove(start, buffer, buffer_size); + + return EFI_EXIT(EFI_SUCCESS); +} + +/* + * flush_blocks - Flush service of the block IO protocol + * + * @this: pointer to the BLOCK_IO_PROTOCOL + * Return: status code + */ +static efi_status_t EFIAPI flush_blocks(struct efi_block_io *this) +{ + return EFI_SUCCESS; +} + +/* + * ram_disk_register - Register service of the RAM disk protocol + * + * @ram_disk_base: The base address of registered RAM disk + * @ram_disk_size: The size of registered RAM disk + * @ram_disk_type: The type of registered RAM disk + * @parent_device_path: Pointer to the parent device path + * @device_path: Pointer to the device path + * Return: status code + */ +static efi_status_t EFIAPI +ram_disk_register(u64 ram_disk_base, u64 ram_disk_size, + efi_guid_t *ram_disk_type, + struct efi_device_path *parent_device_path, + struct efi_device_path **device_path) +{ + efi_status_t ret; + efi_handle_t disk_handle = NULL; + struct efi_device_path *dp; + struct efi_device_path end_node; + struct efi_ram_disk_obj *ram_disk_obj; + struct efi_device_path_ram_disk_path ram_disk_node; + + EFI_ENTRY("%llu %llu %pUs %p, %p", ram_disk_base, ram_disk_size, + ram_disk_type, parent_device_path, device_path); + + if (!ram_disk_size || !ram_disk_type || !device_path) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + *device_path = NULL; + + ram_disk_obj = calloc(1, sizeof(*ram_disk_obj)); + if (!ram_disk_obj) + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + ram_disk_obj->image = (u8 *)ram_disk_base; + ram_disk_obj->image_size = ram_disk_size; + ram_disk_obj->ops.media = &ram_disk_obj->media; + + ram_disk_obj->ops.media->block_size = 1 << MEM_BLOCK_SIZE_SHIFT; + ram_disk_obj->ops.media->last_block = + (ram_disk_size >> MEM_BLOCK_SIZE_SHIFT) - 1; + ram_disk_obj->ops.media->media_present = 1; + + ram_disk_obj->ops.reset = reset; + ram_disk_obj->ops.read_blocks = read_blocks; + ram_disk_obj->ops.write_blocks = write_blocks; + ram_disk_obj->ops.flush_blocks = flush_blocks; + + dp = calloc(1, sizeof(struct efi_device_path_ram_disk_path) + + sizeof(struct efi_device_path)); + if (!dp) { + free(ram_disk_obj); + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + } + + ram_disk_node.dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; + ram_disk_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_RAM_DISK_PATH; + ram_disk_node.dp.length = sizeof(struct efi_device_path_ram_disk_path); + put_unaligned_le64(ram_disk_base, &ram_disk_node.starting_address); + put_unaligned_le64(ram_disk_base + ram_disk_size - 1, &ram_disk_node.ending_address); + guidcpy(&ram_disk_node.disk_type_guid, ram_disk_type); + ram_disk_node.disk_instance = 0; + memcpy(dp, &ram_disk_node, sizeof(struct efi_device_path_ram_disk_path)); + + end_node.type = DEVICE_PATH_TYPE_END; + end_node.sub_type = DEVICE_PATH_SUB_TYPE_END; + end_node.length = sizeof(struct efi_device_path); + memcpy((char *)dp + sizeof(struct efi_device_path_ram_disk_path), + &end_node, sizeof(struct efi_device_path)); + + ram_disk_obj->dp = efi_dp_append(parent_device_path, dp); + free(dp); + if (!ram_disk_obj->dp) { + free(ram_disk_obj); + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + } + + if (efi_dp_find_obj(ram_disk_obj->dp, NULL, NULL)) { + log_err("Already Started\n"); + ret = EFI_ALREADY_STARTED; + goto err; + } + + ret = efi_install_multiple_protocol_interfaces( + &disk_handle, &efi_guid_device_path, ram_disk_obj->dp, + &efi_block_io_guid, &ram_disk_obj->ops, NULL); + if (ret != EFI_SUCCESS) { + log_err("InstallProtocolInterface failed\n"); + goto err; + } + + ret = EFI_CALL(systab.boottime->connect_controller(disk_handle, NULL, + NULL, 1)); + if (ret != EFI_SUCCESS) { + log_err("ConnectController failed\n"); + goto err; + } + + *device_path = ram_disk_obj->dp; + list_add(&ram_disk_obj->list, &obj_list); + + return EFI_EXIT(ret); +err: + efi_free_pool(ram_disk_obj->dp); + free(ram_disk_obj); + + return EFI_EXIT(ret); +} + +/* + * ram_disk_unregister - Unregister service of the RAM disk protocol + * + * @device_path: Pointer to the device path + * Return: status code + */ +static efi_status_t EFIAPI +ram_disk_unregister(struct efi_device_path *device_path) +{ + int ret; + efi_handle_t disk_handle; + struct list_head *pos, *n; + struct efi_ram_disk_obj *entry; + struct efi_ram_disk_obj *ram_disk_obj = NULL; + + EFI_ENTRY("%p", device_path); + + if (!device_path) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + list_for_each_safe(pos, n, &obj_list) { + entry = list_entry(pos, struct efi_ram_disk_obj, list); + if (!efi_dp_match(device_path, entry->dp)) { + ram_disk_obj = entry; + break; + } + } + + if (!ram_disk_obj) + return EFI_EXIT(EFI_NOT_FOUND); + + disk_handle = efi_dp_find_obj(device_path, &efi_block_io_guid, NULL); + if (!disk_handle) + return EFI_EXIT(EFI_NOT_FOUND); + + ret = efi_uninstall_multiple_protocol_interfaces( + disk_handle, &efi_guid_device_path, ram_disk_obj->dp, + &efi_block_io_guid, &ram_disk_obj->ops, NULL); + if (ret != EFI_SUCCESS) + log_err("UninstallProtocolInterface failed\n"); + + list_del(&ram_disk_obj->list); + efi_free_pool(ram_disk_obj->dp); + free(ram_disk_obj); + + return EFI_EXIT(ret); +} + +static const struct efi_ram_disk_protocol efi_ram_disk_protocol = { + .disk_register = ram_disk_register, + .unregister = ram_disk_unregister, +}; + +/** + * efi_ram_disk_register() - register EFI_RAM_DISK_PROTOCOL + * + * Return: status code + */ +efi_status_t efi_ram_disk_register(void) +{ + efi_status_t ret; + + ret = efi_add_protocol(efi_root, &efi_guid_ram_disk_protocol, + (void *)&efi_ram_disk_protocol); + if (ret != EFI_SUCCESS) + log_err("Cannot install EFI_RAM_DISK_PROTOCOL\n"); + + INIT_LIST_HEAD(&obj_list); + + return ret; +} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 877f3878d6..8c430d4a9c 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -344,6 +344,12 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out;
+ if (IS_ENABLED(CONFIG_EFI_RAM_DISK_PROTOCOL)) { + ret = efi_ram_disk_register(); + if (ret != EFI_SUCCESS) + goto out; + } + /* Initialize EFI runtime services */ ret = efi_reset_system_init(); if (ret != EFI_SUCCESS) diff --git a/lib/uuid.c b/lib/uuid.c index 96e1af3c8b..9827588186 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -195,6 +195,10 @@ static const struct { "Firmware Management", EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID }, + { + "Ram Disk", + EFI_RAM_DISK_PROTOCOL_GUID + }, /* Configuration table GUIDs */ { "ACPI table",

This commit implements the test commands for EFI_RAM_DISK_PROTOCOL. With the disk load/unload commands, user can mount the ISO image in the volatile memory through EFI_RAM_DISK_PROTOCOL.
Currently the load command can load only one image at a time even if UEFI specification does not limit the number of images. Anyway one image is enough for testing.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- cmd/efidebug.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 9622430c47..3466ae7e32 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1421,6 +1421,113 @@ static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag, return CMD_RET_SUCCESS; }
+#ifdef CONFIG_EFI_RAM_DISK_PROTOCOL +static struct efi_device_path *ram_disk_dp; +static efi_guid_t virtual_cd_guid = EFI_VIRTUAL_CD_GUID; + +static int do_efi_disk_load(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u64 addr, size; + efi_status_t ret; + struct efi_ram_disk_protocol *ram_disk = NULL; + + if (ram_disk_dp) { + printf("Only one image can be loaded\n"); + return CMD_RET_FAILURE; + } + + argc--; + argv++; + + if (argc != 2) + return CMD_RET_USAGE; + + addr = hextoul(argv[0], NULL); + size = hextoul(argv[1], NULL); + + ret = EFI_CALL(BS->locate_protocol(&efi_guid_ram_disk_protocol, NULL, + (void **)&ram_disk)); + if (ret != EFI_SUCCESS || !ram_disk) { + printf("No EFI_RAM_DISK_PROTOCOL found(ret = %lu)\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = EFI_CALL(ram_disk->disk_register(addr, size, &virtual_cd_guid, NULL, + &ram_disk_dp)); + if (ret != EFI_SUCCESS || !ram_disk_dp) { + printf("RAM DISK register failed(ret = %lu)\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static int do_efi_disk_unload(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + efi_status_t ret; + struct efi_ram_disk_protocol *ram_disk = NULL; + + ret = EFI_CALL(BS->locate_protocol(&efi_guid_ram_disk_protocol, NULL, + (void **)&ram_disk)); + if (ret != EFI_SUCCESS || !ram_disk) { + printf("No EFI_RAM_DISK_PROTOCOL found(ret = %lu)\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = EFI_CALL(ram_disk->unregister(ram_disk_dp)); + if (ret != EFI_SUCCESS) { + printf("RAM DISK unregister failed(ret = %lu)\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ram_disk_dp = NULL; + + return CMD_RET_SUCCESS; +} + +static struct cmd_tbl cmd_efidebug_disk_sub[] = { + U_BOOT_CMD_MKENT(load, CONFIG_SYS_MAXARGS, 1, do_efi_disk_load, "", ""), + U_BOOT_CMD_MKENT(unload, CONFIG_SYS_MAXARGS, 1, do_efi_disk_unload, "", ""), +}; + +/** + * do_efi_disk() - manage UEFI ram disk device + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, + * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "disk" sub-command. + */ +static int do_efi_disk(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct cmd_tbl *cp; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; + argv++; + + cp = find_cmd_tbl(argv[0], cmd_efidebug_disk_sub, + ARRAY_SIZE(cmd_efidebug_disk_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} +#endif + static struct cmd_tbl cmd_efidebug_sub[] = { U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""), #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT @@ -1441,6 +1548,10 @@ static struct cmd_tbl cmd_efidebug_sub[] = { "", ""), U_BOOT_CMD_MKENT(query, CONFIG_SYS_MAXARGS, 1, do_efi_query_info, "", ""), +#ifdef CONFIG_EFI_RAM_DISK_PROTOCOL + U_BOOT_CMD_MKENT(disk, CONFIG_SYS_MAXARGS, 1, do_efi_disk, + "", ""), +#endif };
/** @@ -1526,6 +1637,12 @@ static char efidebug_help_text[] = " - show UEFI memory map\n" "efidebug tables\n" " - show UEFI configuration tables\n" +#ifdef CONFIG_EFI_RAM_DISK_PROTOCOL + "efidebug disk load <address> <size>\n" + " - load ISO image\n" + "efidebug disk unload\n" + " - unload ISO image\n" +#endif #ifdef CONFIG_CMD_BOOTEFI_BOOTMGR "efidebug test bootmgr\n" " - run simple bootmgr for test\n"

This adds the selftest for the EFI_RAM_DISK_PROTOCOL.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ 2 files changed, 512 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index e4d75420bf..899f2278d5 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -70,6 +70,7 @@ endif
ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy) obj-y += efi_selftest_block_device.o +obj-$(CONFIG_EFI_RAM_DISK_PROTOCOL) += efi_selftest_ram_disk.o endif
obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o diff --git a/lib/efi_selftest/efi_selftest_ram_disk.c b/lib/efi_selftest/efi_selftest_ram_disk.c new file mode 100644 index 0000000000..5d6ae1f44f --- /dev/null +++ b/lib/efi_selftest/efi_selftest_ram_disk.c @@ -0,0 +1,511 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_ram_disk + * The disk image defined in efi_selftest_disk_image.h is + * used in this test. + * Most source code originates from efi_selftest_block_device.c. + * + * Copyright (c) 2023, Linaro Limited + */ + +#include <efi_selftest.h> +#include "efi_selftest_disk_image.h" +#include <asm/cache.h> + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +static struct efi_boot_services *boottime; + +static const efi_guid_t block_io_protocol_guid = EFI_BLOCK_IO_PROTOCOL_GUID; +static const efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID; +static const efi_guid_t guid_simple_file_system_protocol = + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID; +static const efi_guid_t guid_ram_disk_protocol = EFI_RAM_DISK_PROTOCOL_GUID; +static efi_guid_t guid_virtual_disk = EFI_VIRTUAL_DISK_GUID; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed disk image */ +struct compressed_disk_image { + size_t length; + struct line lines[]; +}; + +static const struct compressed_disk_image img = EFI_ST_DISK_IMG; + +/* Decompressed disk image */ +static u8 *image; +static u8 *image2; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * Return: status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * Return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + decompress(&image); + decompress(&image2); + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t r; + + if (image) { + r = boottime->free_pool(image); + if (r != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + if (image2) { + r = boottime->free_pool(image2); + if (r != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Get length of device path without end tag. + * + * @dp device path + * Return: length of device path in bytes + */ +static efi_uintn_t dp_size(struct efi_device_path *dp) +{ + struct efi_device_path *pos = dp; + + while (pos->type != DEVICE_PATH_TYPE_END) + pos = (struct efi_device_path *)((char *)pos + pos->length); + return (char *)pos - (char *)dp; +} + +/* + * Execute unit test. + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + struct efi_device_path *ram_disk_dp, *ram_disk_dp2; + struct efi_ram_disk_protocol *ram_disk = NULL; + efi_uintn_t no_handles, i, len; + efi_handle_t *handles; + efi_handle_t handle_partition = NULL; + struct efi_device_path *dp_partition; + struct efi_block_io *block_io_protocol; + struct efi_simple_file_system_protocol *file_system; + struct efi_file_handle *root, *file; + struct { + struct efi_file_system_info info; + u16 label[12]; + } system_info; + efi_uintn_t buf_size; + char buf[16] __aligned(ARCH_DMA_MINALIGN); + u32 part1_size; + u64 pos; + char block_io_aligned[1 << LB_BLOCK_SIZE] __aligned(1 << LB_BLOCK_SIZE); + + /* load first disk image */ + ret = boottime->locate_protocol(&guid_ram_disk_protocol, NULL, (void **)&ram_disk); + if (ret != EFI_SUCCESS || !ram_disk) { + efi_st_error("Failed to locate ram disk protocol\n"); + return EFI_ST_FAILURE; + } + ret = ram_disk->disk_register((u64)image, img.length, &guid_virtual_disk, + NULL, &ram_disk_dp); + if (ret != EFI_SUCCESS || !ram_disk_dp) { + efi_st_error("Failed to register ram disk image\n"); + return EFI_ST_FAILURE; + } + + /* Get the handle for the partition */ + ret = boottime->locate_handle_buffer( + BY_PROTOCOL, &guid_device_path, NULL, + &no_handles, &handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate handles\n"); + return EFI_ST_FAILURE; + } + len = dp_size(ram_disk_dp); + for (i = 0; i < no_handles; ++i) { + ret = boottime->open_protocol(handles[i], &guid_device_path, + (void **)&dp_partition, + NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open device path protocol\n"); + return EFI_ST_FAILURE; + } + if (len >= dp_size(dp_partition)) + continue; + if (memcmp(ram_disk_dp, dp_partition, len)) + continue; + handle_partition = handles[i]; + break; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free pool memory\n"); + return EFI_ST_FAILURE; + } + if (!handle_partition) { + efi_st_error("Partition handle not found\n"); + return EFI_ST_FAILURE; + } + + /* Open the block_io_protocol */ + ret = boottime->open_protocol(handle_partition, + &block_io_protocol_guid, + (void **)&block_io_protocol, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open block IO protocol\n"); + return EFI_ST_FAILURE; + } + /* Get size of first MBR partition */ + memcpy(&part1_size, image + 0x1ca, sizeof(u32)); + if (block_io_protocol->media->last_block != part1_size - 1) { + efi_st_error("Last LBA of partition %x, expected %x\n", + (unsigned int)block_io_protocol->media->last_block, + part1_size - 1); + return EFI_ST_FAILURE; + } + /* Open the simple file system protocol */ + ret = boottime->open_protocol(handle_partition, + &guid_simple_file_system_protocol, + (void **)&file_system, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open simple file system protocol\n"); + return EFI_ST_FAILURE; + } + + /* Open volume */ + ret = file_system->open_volume(file_system, &root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open volume\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(system_info); + ret = root->getinfo(root, &guid_file_system_info, &buf_size, + &system_info); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get file system info\n"); + return EFI_ST_FAILURE; + } + if (system_info.info.block_size != 512) { + efi_st_error("Wrong block size %u, expected 512\n", + system_info.info.block_size); + return EFI_ST_FAILURE; + } + if (efi_st_strcmp_16_8(system_info.info.volume_label, "U-BOOT TEST")) { + efi_st_todo( + "Wrong volume label '%ps', expected 'U-BOOT TEST'\n", + system_info.info.volume_label); + } + + /* Read file */ + ret = root->open(root, &file, u"hello.txt", EFI_FILE_MODE_READ, + 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + ret = file->setpos(file, 1); + if (ret != EFI_SUCCESS) { + efi_st_error("SetPosition failed\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(buf) - 1; + ret = file->read(file, &buf_size, buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to read file\n"); + return EFI_ST_FAILURE; + } + if (buf_size != 12) { + efi_st_error("Wrong number of bytes read: %u\n", + (unsigned int)buf_size); + return EFI_ST_FAILURE; + } + if (memcmp(buf, "ello world!", 11)) { + efi_st_error("Unexpected file content\n"); + return EFI_ST_FAILURE; + } + ret = file->getpos(file, &pos); + if (ret != EFI_SUCCESS) { + efi_st_error("GetPosition failed\n"); + return EFI_ST_FAILURE; + } + if (pos != 13) { + efi_st_error("GetPosition returned %u, expected 13\n", + (unsigned int)pos); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } + + /* + * Test that read_blocks() can read same file data. + * + * In the test data, the partition starts at block 1 and the file + * hello.txt with the content 'Hello world!' is located at 0x5000 + * of the disk. Here we read block 0x27 (offset 0x4e00 of the + * partition) and expect the string 'Hello world!' to be at the + * start of block. + */ + ret = block_io_protocol->read_blocks(block_io_protocol, + block_io_protocol->media->media_id, + (0x5000 >> LB_BLOCK_SIZE) - 1, + block_io_protocol->media->block_size, + block_io_aligned); + if (ret != EFI_SUCCESS) { + efi_st_error("ReadBlocks failed\n"); + return EFI_ST_FAILURE; + } + + if (memcmp(block_io_aligned + 1, buf, 11)) { + efi_st_error("Unexpected block content\n"); + return EFI_ST_FAILURE; + } + +#ifdef CONFIG_FAT_WRITE + /* Write file */ + ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ | + EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + buf_size = 7; + boottime->set_mem(buf, sizeof(buf), 0); + boottime->copy_mem(buf, "U-Boot", buf_size); + ret = file->write(file, &buf_size, buf); + if (ret != EFI_SUCCESS || buf_size != 7) { + efi_st_error("Failed to write file\n"); + return EFI_ST_FAILURE; + } + ret = file->getpos(file, &pos); + if (ret != EFI_SUCCESS) { + efi_st_error("GetPosition failed\n"); + return EFI_ST_FAILURE; + } + if (pos != 7) { + efi_st_error("GetPosition returned %u, expected 7\n", + (unsigned int)pos); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } + + /* Verify file */ + boottime->set_mem(buf, sizeof(buf), 0); + ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ, + 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(buf) - 1; + ret = file->read(file, &buf_size, buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to read file\n"); + return EFI_ST_FAILURE; + } + if (buf_size != 7) { + efi_st_error("Wrong number of bytes read: %u\n", + (unsigned int)buf_size); + return EFI_ST_FAILURE; + } + if (memcmp(buf, "U-Boot", 7)) { + efi_st_error("Unexpected file content %s\n", buf); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } +#else + efi_st_todo("CONFIG_FAT_WRITE is not set\n"); +#endif /* CONFIG_FAT_WRITE */ + + /* Close volume */ + ret = root->close(root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close volume\n"); + return EFI_ST_FAILURE; + } + +#ifdef CONFIG_FAT_WRITE + /* load second disk image, then check the disk image is same as original */ + ret = ram_disk->disk_register((u64)image2, img.length, + &guid_virtual_disk, NULL, &ram_disk_dp2); + if (ret != EFI_SUCCESS || !ram_disk_dp2) { + efi_st_error("Failed to register ram disk image\n"); + return EFI_ST_FAILURE; + } + + /* Get the handle for the partition */ + ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid_device_path, + NULL, &no_handles, &handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate handles\n"); + return EFI_ST_FAILURE; + } + len = dp_size(ram_disk_dp2); + for (i = 0; i < no_handles; ++i) { + ret = boottime->open_protocol(handles[i], &guid_device_path, + (void **)&dp_partition, NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open device path protocol\n"); + return EFI_ST_FAILURE; + } + if (len >= dp_size(dp_partition)) + continue; + if (memcmp(ram_disk_dp2, dp_partition, len)) + continue; + handle_partition = handles[i]; + break; + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free pool memory\n"); + return EFI_ST_FAILURE; + } + if (!handle_partition) { + efi_st_error("Partition handle not found\n"); + return EFI_ST_FAILURE; + } + + /* Open the block_io_protocol */ + ret = boottime->open_protocol(handle_partition, &block_io_protocol_guid, + (void **)&block_io_protocol, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open block IO protocol\n"); + return EFI_ST_FAILURE; + } + + /* Open the simple file system protocol */ + ret = boottime->open_protocol(handle_partition, + &guid_simple_file_system_protocol, + (void **)&file_system, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open simple file system protocol\n"); + return EFI_ST_FAILURE; + } + + /* Open volume */ + ret = file_system->open_volume(file_system, &root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open volume\n"); + return EFI_ST_FAILURE; + } + + boottime->set_mem(buf, sizeof(buf), 0); + ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ, 0); + if (ret == EFI_SUCCESS) { + efi_st_error("wrong image loaded\n"); + return EFI_ST_FAILURE; + } + + /* Close volume */ + ret = root->close(root); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close volume\n"); + return EFI_ST_FAILURE; + } + + /* unload disk images */ + ret = ram_disk->unregister(ram_disk_dp); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unregister ramdisk\n"); + return EFI_ST_FAILURE; + } + ret = ram_disk->unregister(ram_disk_dp2); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unregister ramdisk2\n"); + return EFI_ST_FAILURE; + } +#endif + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(ramdisk) = { + .name = "ramdisk", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +};

On Fri, Jul 07, 2023 at 01:00:40PM +0900, Masahisa Kojima wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
Can a disk created here be used natively on U-Boot with commands like (fs)ls or (fs)load? If so, it would be nice to mention the fact.
-Takahiro Akashi
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO 000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO 000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO]
- udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9
2.34.1

On 7/7/23 06:00, Masahisa Kojima wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
If I understand you correctly, with your design RAM disks will only exist in the EFI sub-system.
We strive to synchronize what is happening on the driver model level and on the UEFI level. I would prefer a design where we have a UCLASS_BLK driver ram disks and the EFI_RAM_DISK_PROTOCOL is a one method of managing ram disk devices.
A big issue we have is RAM management. malloc() can only assign limited amount of memory which is probably too small for the RAM disk you are looking at. We manage page sized memory in the EFI sub-system but this is not integrated with the LMB memory checks.
The necessary sequence of development is probably:
* Rework memory management * Implement ramdisks as UCLASS_BLK driver * Implement the EFI_RAM_DISK_PROTOCOL based on the UCLASS_BLK driver.
Best regards
Heinrich
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO 000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO 000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO]
- udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote:
On 7/7/23 06:00, Masahisa Kojima wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
If I understand you correctly, with your design RAM disks will only exist in the EFI sub-system.
Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot block device (and associated partition devices) thanks to your efi_driver framework.
We strive to synchronize what is happening on the driver model level and on the UEFI level. I would prefer a design where we have a UCLASS_BLK driver ram disks and the EFI_RAM_DISK_PROTOCOL is a one method of managing ram disk devices.
That said, I agree to starting with U-Boot block device implementation, UEFI_DISK comes automatically. It benefits both U-Boot proper and UEFI subsystem equally as well. (That is also what I meant to say in my first response.)
A big issue we have is RAM management. malloc() can only assign limited amount of memory which is probably too small for the RAM disk you are looking at. We manage page sized memory in the EFI sub-system but this is not integrated with the LMB memory checks.
Not sure, is it enough simply to add some restrictions on the start size and the size when a memory region is specified for a raw disk?
-Takahiro Akashi
The necessary sequence of development is probably:
- Rework memory management
- Implement ramdisks as UCLASS_BLK driver
- Implement the EFI_RAM_DISK_PROTOCOL based on the UCLASS_BLK driver.
Best regards
Heinrich
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO 000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO 000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO]
- udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

Hi Akashi-san,
On Fri, 7 Jul 2023 at 16:16, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote:
On 7/7/23 06:00, Masahisa Kojima wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
If I understand you correctly, with your design RAM disks will only exist in the EFI sub-system.
Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot block device (and associated partition devices) thanks to your efi_driver framework.
Read/Write the RAM disk is expected to be called from the EFI context, so native U-Boot can not access the RAM disk. # Honestly speaking, I'm not sure how U-Boot prohibits the access to the EFI RAM disk because the udevices are created for the RAM disk.
Thanks, Masahisa Kojima
We strive to synchronize what is happening on the driver model level and on the UEFI level. I would prefer a design where we have a UCLASS_BLK driver ram disks and the EFI_RAM_DISK_PROTOCOL is a one method of managing ram disk devices.
That said, I agree to starting with U-Boot block device implementation, UEFI_DISK comes automatically. It benefits both U-Boot proper and UEFI subsystem equally as well. (That is also what I meant to say in my first response.)
A big issue we have is RAM management. malloc() can only assign limited amount of memory which is probably too small for the RAM disk you are looking at. We manage page sized memory in the EFI sub-system but this is not integrated with the LMB memory checks.
Not sure, is it enough simply to add some restrictions on the start size and the size when a memory region is specified for a raw disk?
-Takahiro Akashi
The necessary sequence of development is probably:
- Rework memory management
- Implement ramdisks as UCLASS_BLK driver
- Implement the EFI_RAM_DISK_PROTOCOL based on the UCLASS_BLK driver.
Best regards
Heinrich
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO 000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO 000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO]
- udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

On Fri, Jul 07, 2023 at 05:19:33PM +0900, Masahisa Kojima wrote:
Hi Akashi-san,
On Fri, 7 Jul 2023 at 16:16, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote:
On 7/7/23 06:00, Masahisa Kojima wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
If I understand you correctly, with your design RAM disks will only exist in the EFI sub-system.
Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot block device (and associated partition devices) thanks to your efi_driver framework.
Read/Write the RAM disk is expected to be called from the EFI context, so
An associated U-Boot block device should work as well on top of your RAW_DISK_PROTOCOL via a generated RAM disk object (efi_disk). That is why SYMPLE_FILE_SYSTEM_PROTOCOL, which solely relies on U-Boot's proper filesystem subsystem, is installed to the RAM disk object.
native U-Boot can not access the RAM disk.
I believe that, in theory, "fatls efidisk 0 1" (or efi_disk as an interface?) should work even under your current implementation.
-Takahiro Akashi
# Honestly speaking, I'm not sure how U-Boot prohibits the access to the EFI RAM disk because the udevices are created for the RAM disk.
Thanks, Masahisa Kojima
We strive to synchronize what is happening on the driver model level and on the UEFI level. I would prefer a design where we have a UCLASS_BLK driver ram disks and the EFI_RAM_DISK_PROTOCOL is a one method of managing ram disk devices.
That said, I agree to starting with U-Boot block device implementation, UEFI_DISK comes automatically. It benefits both U-Boot proper and UEFI subsystem equally as well. (That is also what I meant to say in my first response.)
A big issue we have is RAM management. malloc() can only assign limited amount of memory which is probably too small for the RAM disk you are looking at. We manage page sized memory in the EFI sub-system but this is not integrated with the LMB memory checks.
Not sure, is it enough simply to add some restrictions on the start size and the size when a memory region is specified for a raw disk?
-Takahiro Akashi
The necessary sequence of development is probably:
- Rework memory management
- Implement ramdisks as UCLASS_BLK driver
- Implement the EFI_RAM_DISK_PROTOCOL based on the UCLASS_BLK driver.
Best regards
Heinrich
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO 000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO 000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO]
- udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

On Fri, 7 Jul 2023 at 18:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 05:19:33PM +0900, Masahisa Kojima wrote:
Hi Akashi-san,
On Fri, 7 Jul 2023 at 16:16, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote:
On 7/7/23 06:00, Masahisa Kojima wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
If I understand you correctly, with your design RAM disks will only exist in the EFI sub-system.
Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot block device (and associated partition devices) thanks to your efi_driver framework.
Read/Write the RAM disk is expected to be called from the EFI context, so
An associated U-Boot block device should work as well on top of your RAW_DISK_PROTOCOL via a generated RAM disk object (efi_disk). That is why SYMPLE_FILE_SYSTEM_PROTOCOL, which solely relies on U-Boot's proper filesystem subsystem, is installed to the RAM disk object.
I now realize that my RAM_DISK_PROTOCOL implementation happens to work thanks to the block cache. When I disable CONFIG_BLOCK_CACHE and load some EFI application(it does set 'app_gd') before calling RAM_DISK_PROTOCOL service, RAM_DISK_PROTOCOL does not work. ConnectController fails.
native U-Boot can not access the RAM disk.
I believe that, in theory, "fatls efidisk 0 1" (or efi_disk as an interface?) should work even under your current implementation.
"fatls efiloader 0:2" does not work. I think "efiloader" device is designed to be accessed from EFI application only even if it is listed by "dm tree".
I understand that ramdisk as UCLASS_BLK driver is required as Heinrich said.
Thanks, Masahisa Kojima
-Takahiro Akashi
# Honestly speaking, I'm not sure how U-Boot prohibits the access to the EFI RAM disk because the udevices are created for the RAM disk.
Thanks, Masahisa Kojima
We strive to synchronize what is happening on the driver model level and on the UEFI level. I would prefer a design where we have a UCLASS_BLK driver ram disks and the EFI_RAM_DISK_PROTOCOL is a one method of managing ram disk devices.
That said, I agree to starting with U-Boot block device implementation, UEFI_DISK comes automatically. It benefits both U-Boot proper and UEFI subsystem equally as well. (That is also what I meant to say in my first response.)
A big issue we have is RAM management. malloc() can only assign limited amount of memory which is probably too small for the RAM disk you are looking at. We manage page sized memory in the EFI sub-system but this is not integrated with the LMB memory checks.
Not sure, is it enough simply to add some restrictions on the start size and the size when a memory region is specified for a raw disk?
-Takahiro Akashi
The necessary sequence of development is probably:
- Rework memory management
- Implement ramdisks as UCLASS_BLK driver
- Implement the EFI_RAM_DISK_PROTOCOL based on the UCLASS_BLK driver.
Best regards
Heinrich
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO 000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO 000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO]
- udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

On Mon, Jul 10, 2023 at 11:13:12AM +0900, Masahisa Kojima wrote:
On Fri, 7 Jul 2023 at 18:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 05:19:33PM +0900, Masahisa Kojima wrote:
Hi Akashi-san,
On Fri, 7 Jul 2023 at 16:16, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote:
On 7/7/23 06:00, Masahisa Kojima wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
If I understand you correctly, with your design RAM disks will only exist in the EFI sub-system.
Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot block device (and associated partition devices) thanks to your efi_driver framework.
Read/Write the RAM disk is expected to be called from the EFI context, so
An associated U-Boot block device should work as well on top of your RAW_DISK_PROTOCOL via a generated RAM disk object (efi_disk). That is why SYMPLE_FILE_SYSTEM_PROTOCOL, which solely relies on U-Boot's proper filesystem subsystem, is installed to the RAM disk object.
I now realize that my RAM_DISK_PROTOCOL implementation happens to work thanks to the block cache. When I disable CONFIG_BLOCK_CACHE and load some EFI application(it does set 'app_gd') before calling RAM_DISK_PROTOCOL service, RAM_DISK_PROTOCOL does not work. ConnectController fails.
native U-Boot can not access the RAM disk.
I believe that, in theory, "fatls efidisk 0 1" (or efi_disk as an interface?) should work even under your current implementation.
"fatls efiloader 0:2" does not work. I think "efiloader" device is designed to be accessed from EFI application only even if it is listed by "dm tree".
I don't believe so. (the interface name may be "efi_blk" or "efiblk", though.)
If the command fails, it's a bug. Must be fixed.
I understand that ramdisk as UCLASS_BLK driver is required as Heinrich said.
That said, I agree to starting with UCLASS_BLK from the viewpoint of U-Boot driver model/UEFI integration.
-Takahiro Akashi
Thanks, Masahisa Kojima
-Takahiro Akashi
# Honestly speaking, I'm not sure how U-Boot prohibits the access to the EFI RAM disk because the udevices are created for the RAM disk.
Thanks, Masahisa Kojima
We strive to synchronize what is happening on the driver model level and on the UEFI level. I would prefer a design where we have a UCLASS_BLK driver ram disks and the EFI_RAM_DISK_PROTOCOL is a one method of managing ram disk devices.
That said, I agree to starting with U-Boot block device implementation, UEFI_DISK comes automatically. It benefits both U-Boot proper and UEFI subsystem equally as well. (That is also what I meant to say in my first response.)
A big issue we have is RAM management. malloc() can only assign limited amount of memory which is probably too small for the RAM disk you are looking at. We manage page sized memory in the EFI sub-system but this is not integrated with the LMB memory checks.
Not sure, is it enough simply to add some restrictions on the start size and the size when a memory region is specified for a raw disk?
-Takahiro Akashi
The necessary sequence of development is probably:
- Rework memory management
- Implement ramdisks as UCLASS_BLK driver
- Implement the EFI_RAM_DISK_PROTOCOL based on the UCLASS_BLK driver.
Best regards
Heinrich
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO 000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO 000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO]
- udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

On Mon, 10 Jul 2023 at 11:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Mon, Jul 10, 2023 at 11:13:12AM +0900, Masahisa Kojima wrote:
On Fri, 7 Jul 2023 at 18:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 05:19:33PM +0900, Masahisa Kojima wrote:
Hi Akashi-san,
On Fri, 7 Jul 2023 at 16:16, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote:
On 7/7/23 06:00, Masahisa Kojima wrote: > This series introduces the EFI_RAM_DISK_PROTOCOL implementation. > The major purpose of this series is a preparation for EFI HTTP(S) boot. > > Now U-Boot can download the distro installer ISO image > via wget or tftpboot commands, but U-Boot can not mount > the downloaded ISO image. > By calling EFI_RAM_DISK_PROTOCOL->register API, user can > mount the ISO image and boot the distro installer.
If I understand you correctly, with your design RAM disks will only exist in the EFI sub-system.
Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot block device (and associated partition devices) thanks to your efi_driver framework.
Read/Write the RAM disk is expected to be called from the EFI context, so
An associated U-Boot block device should work as well on top of your RAW_DISK_PROTOCOL via a generated RAM disk object (efi_disk). That is why SYMPLE_FILE_SYSTEM_PROTOCOL, which solely relies on U-Boot's proper filesystem subsystem, is installed to the RAM disk object.
I now realize that my RAM_DISK_PROTOCOL implementation happens to work thanks to the block cache. When I disable CONFIG_BLOCK_CACHE and load some EFI application(it does set 'app_gd') before calling RAM_DISK_PROTOCOL service, RAM_DISK_PROTOCOL does not work. ConnectController fails.
native U-Boot can not access the RAM disk.
I believe that, in theory, "fatls efidisk 0 1" (or efi_disk as an interface?) should work even under your current implementation.
"fatls efiloader 0:2" does not work. I think "efiloader" device is designed to be accessed from EFI application only even if it is listed by "dm tree".
I don't believe so. (the interface name may be "efi_blk" or "efiblk", though.)
If the command fails, it's a bug. Must be fixed.
"fatls efiloader 0:2" failed here: https://source.denx.de/u-boot/u-boot/-/blob/master/drivers/block/blk-uclass....
This is because the parent is 'dm_root' for the device created by lib/efi_driver/efi_block_device.c, so uclass_id is different.
Thanks, Masahisa Kojima
I understand that ramdisk as UCLASS_BLK driver is required as Heinrich said.
That said, I agree to starting with UCLASS_BLK from the viewpoint of U-Boot driver model/UEFI integration.
-Takahiro Akashi
Thanks, Masahisa Kojima
-Takahiro Akashi
# Honestly speaking, I'm not sure how U-Boot prohibits the access to the EFI RAM disk because the udevices are created for the RAM disk.
Thanks, Masahisa Kojima
We strive to synchronize what is happening on the driver model level and on the UEFI level. I would prefer a design where we have a UCLASS_BLK driver ram disks and the EFI_RAM_DISK_PROTOCOL is a one method of managing ram disk devices.
That said, I agree to starting with U-Boot block device implementation, UEFI_DISK comes automatically. It benefits both U-Boot proper and UEFI subsystem equally as well. (That is also what I meant to say in my first response.)
A big issue we have is RAM management. malloc() can only assign limited amount of memory which is probably too small for the RAM disk you are looking at. We manage page sized memory in the EFI sub-system but this is not integrated with the LMB memory checks.
Not sure, is it enough simply to add some restrictions on the start size and the size when a memory region is specified for a raw disk?
-Takahiro Akashi
The necessary sequence of development is probably:
- Rework memory management
- Implement ramdisks as UCLASS_BLK driver
- Implement the EFI_RAM_DISK_PROTOCOL based on the UCLASS_BLK driver.
Best regards
Heinrich
> > Note that the installation process may not proceed > after the distro installer calls ExitBootServices() > since there is no hand-off process for the block device of > memory mapped ISO image. > > The EFI_RAM_DISK_PROTOCOL was tested with the > debian network installer[1] on qemu_arm64 platform. > The example procedure is as follows. > => tftpboot 41000000 mini.iso > => efidebug disk load 41000000 $filesize > > After these commands, ISO image is mounted like: > > => efidebug dh > > 000000007eec5910 (efiblk#0) > /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) > Block IO > > 000000007eec6140 (efiblk#0:1) > /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) > Block IO > > 000000007eec62b0 (efiblk#0:2) > /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) > Block IO > System Partition > Simple File System > > => dm tree > > blk 0 [ + ] efi_blk `-- efiblk#0 > partition 0 [ + ] blk_partition |-- efiblk#0:1 > partition 1 [ + ] blk_partition `-- efiblk#0:2 > > Debian can be successfully installed with this RAM disk on QEMU. > > [TODO] > - udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() > are not removed when the efi_handle is removed. > So after unload the RAM disk, udevices still exist. > I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). > In addition, I also plan to add unbind() callback in struct efi_driver_ops. > > > [1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im... > > Masahisa Kojima (4): > efi_loader: add RAM disk device path > efi_loader: add EFI_RAM_DISK_PROTOCOL implementation > cmd: efidebug: add RAM disk mount command > efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest > > cmd/efidebug.c | 117 ++++++ > include/efi_api.h | 32 ++ > include/efi_loader.h | 4 + > lib/efi_driver/efi_uclass.c | 7 +- > lib/efi_loader/Kconfig | 6 + > lib/efi_loader/Makefile | 1 + > lib/efi_loader/efi_device_path_to_text.c | 14 + > lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ > lib/efi_loader/efi_setup.c | 6 + > lib/efi_selftest/Makefile | 1 + > lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ > lib/uuid.c | 4 + > 12 files changed, 1035 insertions(+), 2 deletions(-) > create mode 100644 lib/efi_loader/efi_ram_disk.c > create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c > > > base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9

Hi,
On Tue, 11 Jul 2023 at 00:23, Masahisa Kojima masahisa.kojima@linaro.org wrote:
On Mon, 10 Jul 2023 at 11:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Mon, Jul 10, 2023 at 11:13:12AM +0900, Masahisa Kojima wrote:
On Fri, 7 Jul 2023 at 18:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 05:19:33PM +0900, Masahisa Kojima wrote:
Hi Akashi-san,
On Fri, 7 Jul 2023 at 16:16, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote: > On 7/7/23 06:00, Masahisa Kojima wrote: > > This series introduces the EFI_RAM_DISK_PROTOCOL implementation. > > The major purpose of this series is a preparation for EFI HTTP(S) boot. > > > > Now U-Boot can download the distro installer ISO image > > via wget or tftpboot commands, but U-Boot can not mount > > the downloaded ISO image. > > By calling EFI_RAM_DISK_PROTOCOL->register API, user can > > mount the ISO image and boot the distro installer. > > If I understand you correctly, with your design RAM disks will only > exist in the EFI sub-system.
Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot block device (and associated partition devices) thanks to your efi_driver framework.
Read/Write the RAM disk is expected to be called from the EFI context, so
An associated U-Boot block device should work as well on top of your RAW_DISK_PROTOCOL via a generated RAM disk object (efi_disk). That is why SYMPLE_FILE_SYSTEM_PROTOCOL, which solely relies on U-Boot's proper filesystem subsystem, is installed to the RAM disk object.
I now realize that my RAM_DISK_PROTOCOL implementation happens to work thanks to the block cache. When I disable CONFIG_BLOCK_CACHE and load some EFI application(it does set 'app_gd') before calling RAM_DISK_PROTOCOL service, RAM_DISK_PROTOCOL does not work. ConnectController fails.
native U-Boot can not access the RAM disk.
I believe that, in theory, "fatls efidisk 0 1" (or efi_disk as an interface?) should work even under your current implementation.
"fatls efiloader 0:2" does not work. I think "efiloader" device is designed to be accessed from EFI application only even if it is listed by "dm tree".
I don't believe so. (the interface name may be "efi_blk" or "efiblk", though.)
If the command fails, it's a bug. Must be fixed.
"fatls efiloader 0:2" failed here: https://source.denx.de/u-boot/u-boot/-/blob/master/drivers/block/blk-uclass....
This is because the parent is 'dm_root' for the device created by lib/efi_driver/efi_block_device.c, so uclass_id is different.
The parent device of a UCLASS_BLK device MUST be a media uclass. It cannot be root. I believe EFI has some suitable classes.
At some point we will remove the uclass_id from struct blk_desc and just use the parent's uclass ID.
Regards, Simon

On 7/11/23 21:13, Simon Glass wrote:
Hi,
On Tue, 11 Jul 2023 at 00:23, Masahisa Kojima masahisa.kojima@linaro.org wrote:
On Mon, 10 Jul 2023 at 11:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Mon, Jul 10, 2023 at 11:13:12AM +0900, Masahisa Kojima wrote:
On Fri, 7 Jul 2023 at 18:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 05:19:33PM +0900, Masahisa Kojima wrote:
Hi Akashi-san,
On Fri, 7 Jul 2023 at 16:16, AKASHI Takahiro takahiro.akashi@linaro.org wrote: > > On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote: >> On 7/7/23 06:00, Masahisa Kojima wrote: >>> This series introduces the EFI_RAM_DISK_PROTOCOL implementation. >>> The major purpose of this series is a preparation for EFI HTTP(S) boot. >>> >>> Now U-Boot can download the distro installer ISO image >>> via wget or tftpboot commands, but U-Boot can not mount >>> the downloaded ISO image. >>> By calling EFI_RAM_DISK_PROTOCOL->register API, user can >>> mount the ISO image and boot the distro installer. >> >> If I understand you correctly, with your design RAM disks will only >> exist in the EFI sub-system. > > Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot > block device (and associated partition devices) thanks to your > efi_driver framework.
Read/Write the RAM disk is expected to be called from the EFI context, so
An associated U-Boot block device should work as well on top of your RAW_DISK_PROTOCOL via a generated RAM disk object (efi_disk). That is why SYMPLE_FILE_SYSTEM_PROTOCOL, which solely relies on U-Boot's proper filesystem subsystem, is installed to the RAM disk object.
I now realize that my RAM_DISK_PROTOCOL implementation happens to work thanks to the block cache. When I disable CONFIG_BLOCK_CACHE and load some EFI application(it does set 'app_gd') before calling RAM_DISK_PROTOCOL service, RAM_DISK_PROTOCOL does not work. ConnectController fails.
native U-Boot can not access the RAM disk.
I believe that, in theory, "fatls efidisk 0 1" (or efi_disk as an interface?) should work even under your current implementation.
"fatls efiloader 0:2" does not work. I think "efiloader" device is designed to be accessed from EFI application only even if it is listed by "dm tree".
I don't believe so. (the interface name may be "efi_blk" or "efiblk", though.)
If the command fails, it's a bug. Must be fixed.
"fatls efiloader 0:2" failed here: https://source.denx.de/u-boot/u-boot/-/blob/master/drivers/block/blk-uclass....
This is because the parent is 'dm_root' for the device created by lib/efi_driver/efi_block_device.c, so uclass_id is different.
The parent device of a UCLASS_BLK device MUST be a media uclass. It cannot be root. I believe EFI has some suitable classes.
At some point we will remove the uclass_id from struct blk_desc and just use the parent's uclass ID.
Hello Simon,
we want to more tightly integrate EFI and DM.
If an EFI program like iPXE creates a handle for an iSCSI drive with the block IO protocol the parent of that handle will be a network device and nothing having to do with a block device.
Introducing dummy devices like you did for the sandbox host block devices will only make integration of EFI and DM more complicated.
As I indicated years before you have to use blk_desc->uclass_id instead of the parent uclass_id to identify block devices in blk_get_devnum_by_uclass_idname() [1][2].
Removing class_id from struct blk_desc is a step against better future integration of EFI and DM.
Best regards
Heinrich
[1] https://lore.kernel.org/all/20221003093550.106304-1-heinrich.schuchardt@cano... [2] https://lore.kernel.org/all/20220802094933.69170-1-heinrich.schuchardt@canon...

Hi Heinrich,
On Wed, 12 Jul 2023 at 00:41, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 7/11/23 21:13, Simon Glass wrote:
Hi,
On Tue, 11 Jul 2023 at 00:23, Masahisa Kojima masahisa.kojima@linaro.org wrote:
On Mon, 10 Jul 2023 at 11:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Mon, Jul 10, 2023 at 11:13:12AM +0900, Masahisa Kojima wrote:
On Fri, 7 Jul 2023 at 18:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jul 07, 2023 at 05:19:33PM +0900, Masahisa Kojima wrote: > Hi Akashi-san, > > On Fri, 7 Jul 2023 at 16:16, AKASHI Takahiro takahiro.akashi@linaro.org wrote: >> >> On Fri, Jul 07, 2023 at 08:29:12AM +0200, Heinrich Schuchardt wrote: >>> On 7/7/23 06:00, Masahisa Kojima wrote: >>>> This series introduces the EFI_RAM_DISK_PROTOCOL implementation. >>>> The major purpose of this series is a preparation for EFI HTTP(S) boot. >>>> >>>> Now U-Boot can download the distro installer ISO image >>>> via wget or tftpboot commands, but U-Boot can not mount >>>> the downloaded ISO image. >>>> By calling EFI_RAM_DISK_PROTOCOL->register API, user can >>>> mount the ISO image and boot the distro installer. >>> >>> If I understand you correctly, with your design RAM disks will only >>> exist in the EFI sub-system. >> >> Probably, not. As Kojima-san's "dm tree" shows, there is a U-Boot >> block device (and associated partition devices) thanks to your >> efi_driver framework. > > Read/Write the RAM disk is expected to be called from the EFI context, so
An associated U-Boot block device should work as well on top of your RAW_DISK_PROTOCOL via a generated RAM disk object (efi_disk). That is why SYMPLE_FILE_SYSTEM_PROTOCOL, which solely relies on U-Boot's proper filesystem subsystem, is installed to the RAM disk object.
I now realize that my RAM_DISK_PROTOCOL implementation happens to work thanks to the block cache. When I disable CONFIG_BLOCK_CACHE and load some EFI application(it does set 'app_gd') before calling RAM_DISK_PROTOCOL service, RAM_DISK_PROTOCOL does not work. ConnectController fails.
> native U-Boot can not access the RAM disk.
I believe that, in theory, "fatls efidisk 0 1" (or efi_disk as an interface?) should work even under your current implementation.
"fatls efiloader 0:2" does not work. I think "efiloader" device is designed to be accessed from EFI application only even if it is listed by "dm tree".
I don't believe so. (the interface name may be "efi_blk" or "efiblk", though.)
If the command fails, it's a bug. Must be fixed.
"fatls efiloader 0:2" failed here: https://source.denx.de/u-boot/u-boot/-/blob/master/drivers/block/blk-uclass....
This is because the parent is 'dm_root' for the device created by lib/efi_driver/efi_block_device.c, so uclass_id is different.
The parent device of a UCLASS_BLK device MUST be a media uclass. It cannot be root. I believe EFI has some suitable classes.
At some point we will remove the uclass_id from struct blk_desc and just use the parent's uclass ID.
Hello Simon,
we want to more tightly integrate EFI and DM.
Who is working on this? I have not seen a series for a while.
If an EFI program like iPXE creates a handle for an iSCSI drive with the block IO protocol the parent of that handle will be a network device and nothing having to do with a block device.
Introducing dummy devices like you did for the sandbox host block devices will only make integration of EFI and DM more complicated.
As I indicated years before you have to use blk_desc->uclass_id instead of the parent uclass_id to identify block devices in blk_get_devnum_by_uclass_idname() [1][2].
Removing class_id from struct blk_desc is a step against better future integration of EFI and DM.
I thought we discussed this before, but this his my understanding: devices cannot exist in EFI that are not known by U-Boot. So if there is a an iSCSI drive it should exist in U-Boot too, under DM.
Anyway, I hope this important work can restart soon.
Regards, Simon
Best regards
Heinrich
[1] https://lore.kernel.org/all/20221003093550.106304-1-heinrich.schuchardt@cano... [2] https://lore.kernel.org/all/20220802094933.69170-1-heinrich.schuchardt@canon...

Hi Heinrich,
On Fri, 7 Jul 2023 at 15:34, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 7/7/23 06:00, Masahisa Kojima wrote:
This series introduces the EFI_RAM_DISK_PROTOCOL implementation. The major purpose of this series is a preparation for EFI HTTP(S) boot.
Now U-Boot can download the distro installer ISO image via wget or tftpboot commands, but U-Boot can not mount the downloaded ISO image. By calling EFI_RAM_DISK_PROTOCOL->register API, user can mount the ISO image and boot the distro installer.
If I understand you correctly, with your design RAM disks will only exist in the EFI sub-system.
Yes, RAM disk can be accessed through the EFI sub-system.
We strive to synchronize what is happening on the driver model level and on the UEFI level. I would prefer a design where we have a UCLASS_BLK driver ram disks and the EFI_RAM_DISK_PROTOCOL is a one method of managing ram disk devices.
The current EFI_RAM_DIISK_PROTOCOL implementation is the same as what EDK2 reference implementation does, and I'm not yet fully convinced how much the native U-Boot gets the benefit of RAM disk support.
A big issue we have is RAM management. malloc() can only assign limited amount of memory which is probably too small for the RAM disk you are looking at. We manage page sized memory in the EFI sub-system but this is not integrated with the LMB memory checks.
OK, when we think about EFI HTTP boot and hand-off the RAM disk to the kernel, we need to consider the memory allocation for the big ISO image. But as far as EFI_RAM_DISK_PROTOCOL is concerned, can we leave the memory management issue?
Thanks, Masahisa Kojima
The necessary sequence of development is probably:
- Rework memory management
- Implement ramdisks as UCLASS_BLK driver
- Implement the EFI_RAM_DISK_PROTOCOL based on the UCLASS_BLK driver.
Best regards
Heinrich
Note that the installation process may not proceed after the distro installer calls ExitBootServices() since there is no hand-off process for the block device of memory mapped ISO image.
The EFI_RAM_DISK_PROTOCOL was tested with the debian network installer[1] on qemu_arm64 platform. The example procedure is as follows. => tftpboot 41000000 mini.iso => efidebug disk load 41000000 $filesize
After these commands, ISO image is mounted like:
=> efidebug dh
000000007eec5910 (efiblk#0) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0) Block IO 000000007eec6140 (efiblk#0:1) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(1,0x01,0,0x0,0x33800) Block IO 000000007eec62b0 (efiblk#0:2) /RamDisk(0x41000000,4974afff,3d5abd30-4175-87ce-6d64-d2ade523c4bb,0x0)/HD(2,0x01,0,0x33800,0x10000) Block IO System Partition Simple File System
=> dm tree
blk 0 [ + ] efi_blk `-- efiblk#0 partition 0 [ + ] blk_partition |-- efiblk#0:1 partition 1 [ + ] blk_partition `-- efiblk#0:2
Debian can be successfully installed with this RAM disk on QEMU.
[TODO]
- udevices created in ./lib/efi_driver/efi_block_device.c::efi_bl_bind() are not removed when the efi_handle is removed. So after unload the RAM disk, udevices still exist. I plan to add a udevice removal process in ./lib/efi_driver/efi_uclass.c::efi_uc_stop(). In addition, I also plan to add unbind() callback in struct efi_driver_ops.
[1] https://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/im...
Masahisa Kojima (4): efi_loader: add RAM disk device path efi_loader: add EFI_RAM_DISK_PROTOCOL implementation cmd: efidebug: add RAM disk mount command efi_selftest: add EFI_RAM_DISK_PROTOCOL selftest
cmd/efidebug.c | 117 ++++++ include/efi_api.h | 32 ++ include/efi_loader.h | 4 + lib/efi_driver/efi_uclass.c | 7 +- lib/efi_loader/Kconfig | 6 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_device_path_to_text.c | 14 + lib/efi_loader/efi_ram_disk.c | 334 +++++++++++++++ lib/efi_loader/efi_setup.c | 6 + lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ram_disk.c | 511 +++++++++++++++++++++++ lib/uuid.c | 4 + 12 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_ram_disk.c create mode 100644 lib/efi_selftest/efi_selftest_ram_disk.c
base-commit: e2e2aea5733f0d23cd9593bbefe5c803c552dcb9
participants (4)
-
AKASHI Takahiro
-
Heinrich Schuchardt
-
Masahisa Kojima
-
Simon Glass