diff mbox series

[v2,4/6] efi_loader: add EFI_RAM_DISK_PROTOCOL implementation

Message ID 20230714054406.761508-5-masahisa.kojima@linaro.org
State New
Headers show
Series introduce EFI_RAM_DISK_PROTOCOL | expand

Commit Message

Masahisa Kojima July 14, 2023, 5:44 a.m. UTC
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>
---
Changes in v2:
- implement EFI_RAM_DISK_PROTOCOL based on the
  ramdisk uclass

 include/efi_api.h             |  13 ++++
 include/efi_loader.h          |   4 +
 lib/efi_loader/Kconfig        |   7 ++
 lib/efi_loader/Makefile       |   1 +
 lib/efi_loader/efi_ram_disk.c | 142 ++++++++++++++++++++++++++++++++++
 lib/efi_loader/efi_setup.c    |   6 ++
 lib/uuid.c                    |   4 +
 7 files changed, 177 insertions(+)
 create mode 100644 lib/efi_loader/efi_ram_disk.c
diff mbox series

Patch

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_loader/Kconfig b/lib/efi_loader/Kconfig
index c5835e6ef6..ff0559e8c4 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -433,4 +433,11 @@  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
+	depends on RAM_DISK
+	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..a261d93963
--- /dev/null
+++ b/lib/efi_loader/efi_ram_disk.c
@@ -0,0 +1,142 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  RAM Disk Protocol
+ *
+ *  Copyright (c) 2023, Linaro Limited
+ */
+
+#include <dm.h>
+#include <efi_loader.h>
+#include <malloc.h>
+#include <ramdisk.h>
+
+const efi_guid_t efi_guid_ram_disk_protocol = EFI_RAM_DISK_PROTOCOL_GUID;
+
+/*
+ * 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;
+	struct udevice *bdev;
+	efi_handle_t disk_handle;
+	struct efi_handler *handler;
+	struct efi_device_path *dp;
+
+	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) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	*device_path = NULL;
+
+	/* TODO: Add parent_device_path */
+	bdev = ramdisk_mount(ram_disk_base, ram_disk_size, ram_disk_type);
+	if (!bdev) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	if (dev_tag_get_ptr(bdev, DM_TAG_EFI, (void **)&disk_handle)) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	ret = efi_search_protocol(disk_handle, &efi_guid_device_path, &handler);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	ret = efi_protocol_open(handler, (void **)&dp, NULL, NULL,
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	log_debug("EFI_RAM_DISK_PROTOCOL register %pD\n", dp);
+
+	*device_path = efi_dp_dup(dp);
+	if (!(*device_path))
+		ret = EFI_OUT_OF_RESOURCES;
+
+out:
+	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_status_t status = EFI_SUCCESS;
+	enum uclass_id id;
+	efi_handle_t disk_handle;
+
+	EFI_ENTRY("%pD", device_path);
+
+	if (!device_path) {
+		status = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	disk_handle = efi_dp_find_obj(device_path, &efi_block_io_guid, NULL);
+	if (!disk_handle) {
+		status = EFI_NOT_FOUND;
+		goto out;
+	}
+
+	id = device_get_uclass_id(disk_handle->dev);
+	if (id != UCLASS_BLK) {
+		status = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	ret = ramdisk_unmount(disk_handle->dev);
+	if (ret) {
+		log_err("EFI_RAM_DISK_PROTOCOL unregister failed(%d)\n", ret);
+		status = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+out:
+	return EFI_EXIT(status);
+}
+
+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");
+
+	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",