public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Alexander Graf <agraf@suse.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v5 18/30] efi_loader: Add disk interfaces
Date: Fri,  4 Mar 2016 01:10:02 +0100	[thread overview]
Message-ID: <1457050214-117592-19-git-send-email-agraf@suse.de> (raw)
In-Reply-To: <1457050214-117592-1-git-send-email-agraf@suse.de>

A EFI applications usually want to access storage devices to load data from.

This patch adds support for EFI disk interfaces. It loops through all block
storage interfaces known to U-Boot and creates an EFI object for each existing
one. EFI applications can then through these objects call U-Boot's read and
write functions.

Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Simon Glass <sjg@chromium.org>

---

v1 -> v2:

  - Move to block_drvr array
  - Move to GPLv2+
  - Fix header order
  - Document efi block object struct
  - Use calloc rather than malloc & memset

v2 -> v3:

  - Adapt to newer u-boot block API
  - Add EFIAPI to function prototypes
  - Document header
  - Check for DEV_TYPE_UNKNOWN
  - Document 16byte limit for dp string
---
 include/efi_loader.h      |   2 +
 lib/efi_loader/efi_disk.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 220 insertions(+)
 create mode 100644 lib/efi_loader/efi_disk.c

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 3a71a77..32e0632 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -86,6 +86,8 @@ struct efi_object {
 /* This list contains all UEFI objects we know of */
 extern struct list_head efi_obj_list;
 
+/* Called by bootefi to make all disk storage accessible as EFI objects */
+int efi_disk_register(void);
 /*
  * Stub implementation for a protocol opener that just returns the handle as
  * interface
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
new file mode 100644
index 0000000..f93fcb2
--- /dev/null
+++ b/lib/efi_loader/efi_disk.c
@@ -0,0 +1,218 @@
+/*
+ *  EFI application disk support
+ *
+ *  Copyright (c) 2016 Alexander Graf
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <inttypes.h>
+#include <part.h>
+#include <malloc.h>
+
+static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID;
+
+struct efi_disk_obj {
+	/* Generic EFI object parent class data */
+	struct efi_object parent;
+	/* EFI Interface callback struct for block I/O */
+	struct efi_block_io ops;
+	/* U-Boot ifname for block device */
+	const char *ifname;
+	/* U-Boot dev_index for block device */
+	int dev_index;
+	/* EFI Interface Media descriptor struct, referenced by ops */
+	struct efi_block_io_media media;
+	/* EFI device path to this block device */
+	struct efi_device_path_file_path *dp;
+};
+
+static void ascii2unicode(u16 *unicode, char *ascii)
+{
+	while (*ascii)
+		*(unicode++) = *(ascii++);
+}
+
+static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
+			void **protocol_interface, void *agent_handle,
+			void *controller_handle, uint32_t attributes)
+{
+	struct efi_disk_obj *diskobj = handle;
+
+	*protocol_interface = &diskobj->ops;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol,
+			void **protocol_interface, void *agent_handle,
+			void *controller_handle, uint32_t attributes)
+{
+	struct efi_disk_obj *diskobj = handle;
+
+	*protocol_interface = diskobj->dp;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
+			char extended_verification)
+{
+	EFI_ENTRY("%p, %x", this, extended_verification);
+	return EFI_EXIT(EFI_DEVICE_ERROR);
+}
+
+enum efi_disk_direction {
+	EFI_DISK_READ,
+	EFI_DISK_WRITE,
+};
+
+static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this,
+			u32 media_id, u64 lba, unsigned long buffer_size,
+			void *buffer, enum efi_disk_direction direction)
+{
+	struct efi_disk_obj *diskobj;
+	struct block_dev_desc *desc;
+	int blksz;
+	int blocks;
+	unsigned long n;
+
+	EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
+		  buffer_size, buffer);
+
+	diskobj = container_of(this, struct efi_disk_obj, ops);
+	if (!(desc = get_dev(diskobj->ifname, diskobj->dev_index)))
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+	blksz = desc->blksz;
+	blocks = buffer_size / blksz;
+
+#ifdef DEBUG_EFI
+	printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__,
+	       __LINE__, blocks, lba, blksz, direction);
+#endif
+
+	/* We only support full block access */
+	if (buffer_size & (blksz - 1))
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+
+	if (direction == EFI_DISK_READ)
+		n = desc->block_read(desc, lba, blocks, buffer);
+	else
+		n = desc->block_write(desc, lba, blocks, buffer);
+
+	/* We don't do interrupts, so check for timers cooperatively */
+	efi_timer_check();
+
+#ifdef DEBUG_EFI
+	printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
+#endif
+	if (n != blocks)
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
+			u32 media_id, u64 lba, unsigned long buffer_size,
+			void *buffer)
+{
+	return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
+				  EFI_DISK_READ);
+}
+
+static efi_status_t efi_disk_write_blocks(struct efi_block_io *this,
+			u32 media_id, u64 lba, unsigned long buffer_size,
+			void *buffer)
+{
+	return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
+				  EFI_DISK_WRITE);
+}
+
+static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this)
+{
+	/* We always write synchronously */
+	EFI_ENTRY("%p", this);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static const struct efi_block_io block_io_disk_template = {
+	.reset = &efi_disk_reset,
+	.read_blocks = &efi_disk_read_blocks,
+	.write_blocks = &efi_disk_write_blocks,
+	.flush_blocks = &efi_disk_flush_blocks,
+};
+
+/*
+ * U-Boot doesn't have a list of all online disk devices. So when running our
+ * EFI payload, we scan through all of the potentially available ones and
+ * store them in our object pool.
+ *
+ * This gets called from do_bootefi_exec().
+ */
+int efi_disk_register(void)
+{
+	const struct block_drvr *cur_drvr;
+	int i;
+	int disks = 0;
+
+	/* Search for all available disk devices */
+	for (cur_drvr = block_drvr; cur_drvr->name; cur_drvr++) {
+		printf("Scanning disks on %s...\n", cur_drvr->name);
+		for (i = 0; i < 4; i++) {
+			block_dev_desc_t *desc;
+			struct efi_disk_obj *diskobj;
+			struct efi_device_path_file_path *dp;
+			int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2);
+			char devname[16] = { 0 }; /* dp->str is u16[16] long */
+
+			desc = get_dev(cur_drvr->name, i);
+			if (!desc)
+				continue;
+			if (desc->type == DEV_TYPE_UNKNOWN)
+				continue;
+
+			diskobj = calloc(1, objlen);
+
+			/* Fill in object data */
+			diskobj->parent.protocols[0].guid = &efi_block_io_guid;
+			diskobj->parent.protocols[0].open = efi_disk_open_block;
+			diskobj->parent.protocols[1].guid = &efi_guid_device_path;
+			diskobj->parent.protocols[1].open = efi_disk_open_dp;
+			diskobj->parent.handle = diskobj;
+			diskobj->ops = block_io_disk_template;
+			diskobj->ifname = cur_drvr->name;
+			diskobj->dev_index = i;
+
+			/* Fill in EFI IO Media info (for read/write callbacks) */
+			diskobj->media.removable_media = desc->removable;
+			diskobj->media.media_present = 1;
+			diskobj->media.block_size = desc->blksz;
+			diskobj->media.io_align = desc->blksz;
+			diskobj->media.last_block = desc->lba;
+			diskobj->ops.media = &diskobj->media;
+
+			/* Fill in device path */
+			dp = (void*)&diskobj[1];
+			diskobj->dp = dp;
+			dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
+			dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
+			dp[0].dp.length = sizeof(*dp);
+			snprintf(devname, sizeof(devname), "%s%d",
+				 cur_drvr->name, i);
+			ascii2unicode(dp[0].str, devname);
+
+			dp[1].dp.type = DEVICE_PATH_TYPE_END;
+			dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END;
+			dp[1].dp.length = sizeof(*dp);
+
+			/* Hook up to the device list */
+			list_add_tail(&diskobj->parent.link, &efi_obj_list);
+			disks++;
+		}
+	}
+	printf("Found %d disks\n", disks);
+
+	return 0;
+}
-- 
1.8.5.6

  parent reply	other threads:[~2016-03-04  0:10 UTC|newest]

Thread overview: 67+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-04  0:09 [U-Boot] [PATCH v5 00/30] EFI payload / application support Alexander Graf
2016-03-04  0:09 ` [U-Boot] [PATCH v5 01/30] thunderx: Calculate TCR dynamically Alexander Graf
2016-03-17  1:59   ` [U-Boot] [U-Boot,v5,01/30] " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 02/30] arm64: Disable TTBR1 maps in EL1 Alexander Graf
2016-03-17  1:59   ` [U-Boot] [U-Boot,v5,02/30] " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 03/30] arm64: Make full va map code more dynamic Alexander Graf
2016-03-17  1:59   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 04/30] thunderx: Move mmu table into board file Alexander Graf
2016-03-17  2:00   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 05/30] zymqmp: Replace home grown mmu code with generic table approach Alexander Graf
2016-03-17  2:00   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 06/30] tegra: " Alexander Graf
2016-03-17  2:00   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 07/30] vexpress64: Add MMU tables Alexander Graf
2016-03-17  2:00   ` [U-Boot] [U-Boot,v5,07/30] " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 08/30] dwmmc: Increase retry timeout Alexander Graf
2016-03-17  2:00   ` [U-Boot] [U-Boot,v5,08/30] " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 09/30] hikey: Add MMU tables Alexander Graf
2016-03-17  2:00   ` [U-Boot] [U-Boot,v5,09/30] " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 10/30] arm64: Remove non-full-va map code Alexander Graf
2016-03-17  2:00   ` [U-Boot] [U-Boot,v5,10/30] " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 11/30] arm64: Only allow dcache disabled in SPL builds Alexander Graf
2016-03-17  2:01   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 12/30] disk/part.c: Expose list of available block drivers Alexander Graf
2016-03-17  2:01   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 13/30] include/efi_api.h: Add more detailed API definitions Alexander Graf
2016-03-17  2:01   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 14/30] efi_loader: Add PE image loader Alexander Graf
2016-03-17  2:01   ` [U-Boot] [U-Boot,v5,14/30] " Tom Rini
2016-03-04  0:09 ` [U-Boot] [PATCH v5 15/30] efi_loader: Add boot time services Alexander Graf
2016-03-17  2:01   ` [U-Boot] [U-Boot,v5,15/30] " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 16/30] efi_loader: Add console interface Alexander Graf
2016-03-17  2:01   ` [U-Boot] [U-Boot,v5,16/30] " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 17/30] efi_loader: Add runtime services Alexander Graf
2016-03-17  2:01   ` [U-Boot] [U-Boot,v5,17/30] " Tom Rini
2016-03-04  0:10 ` Alexander Graf [this message]
2016-03-17  2:01   ` [U-Boot] [U-Boot,v5,18/30] efi_loader: Add disk interfaces Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 19/30] efi_loader: Add "bootefi" command Alexander Graf
2016-03-09 23:27   ` [U-Boot] [PATCH v6 " Alexander Graf
2016-03-17  2:01     ` [U-Boot] [U-Boot,v6,19/30] " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 20/30] efi_loader: Implement memory allocation and map Alexander Graf
2016-03-17  2:02   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 21/30] arm64: Allow exceptions to return Alexander Graf
2016-03-17  2:02   ` [U-Boot] [U-Boot,v5,21/30] " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 22/30] arm64: Allow EFI payload code to take exceptions Alexander Graf
2016-03-17  2:02   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 23/30] efi_loader: hook up in build environment Alexander Graf
2016-03-17  2:02   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 24/30] efi_loader: Add distro boot script for removable media Alexander Graf
2016-03-09 23:05   ` Alexander Graf
2016-03-09 23:16     ` Tom Rini
2016-03-09 23:26       ` [U-Boot] [PATCH v6 " Alexander Graf
2016-03-17  2:02         ` [U-Boot] [U-Boot, v6, " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 25/30] efi_loader: Add README section in README.efi Alexander Graf
2016-03-17  2:02   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 26/30] efi_loader: Add MAINTAINERS entry Alexander Graf
2016-03-17  2:02   ` [U-Boot] [U-Boot,v5,26/30] " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 27/30] arm64: Replace fdt_name env variables with fdtfile Alexander Graf
2016-03-17  2:02   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 28/30] arm: Allow EFI payload code to take exceptions Alexander Graf
2016-03-17  2:03   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 29/30] efi_loader: Call fdt preparation functions Alexander Graf
2016-03-17  2:03   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  0:10 ` [U-Boot] [PATCH v5 30/30] efi_loader: Pass proper device path in on boot Alexander Graf
2016-03-17  2:03   ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04  9:19 ` [U-Boot] [PATCH] efi_loader: Reserve 2 additional pages for fdt Alexander Graf
2016-03-04  9:41   ` Leif Lindholm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1457050214-117592-19-git-send-email-agraf@suse.de \
    --to=agraf@suse.de \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox