[U-Boot] [PATCH 1/2] efi_loader: Add bounce buffer support
Alexander Graf
agraf at suse.de
Wed May 11 18:25:48 CEST 2016
Some hardware that is supported by U-Boot can not handle DMA above 32bits.
For these systems, we need to come up with a way to expose the disk interface
in a safe way.
This patch implements EFI specific bounce buffers. For non-EFI cases, this
apparently was no issue so far, since we can just define our environment
variables conveniently.
Signed-off-by: Alexander Graf <agraf at suse.de>
---
include/efi_loader.h | 5 ++++
lib/efi_loader/Kconfig | 9 ++++++
lib/efi_loader/efi_disk.c | 70 +++++++++++++++++++++++++++++++++++++++------
lib/efi_loader/efi_memory.c | 16 +++++++++++
4 files changed, 91 insertions(+), 9 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 8005454..b1ca4ba 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -139,6 +139,11 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
/* Called by board init to initialize the EFI memory map */
int efi_memory_init(void);
+#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
+extern void *efi_bounce_buffer;
+#define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024)
+#endif
+
/* Convert strings from normal C strings to uEFI strings */
static inline void ascii2unicode(u16 *unicode, char *ascii)
{
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 14c99ec..37a0dd6 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -7,3 +7,12 @@ config EFI_LOADER
on top of U-Boot. If this option is enabled, U-Boot will expose EFI
interfaces to a loaded EFI application, enabling it to reuse U-Boot's
device drivers.
+
+config EFI_LOADER_BOUNCE_BUFFER
+ bool "EFI Applications use bounce buffers for DMA operations"
+ depends on EFI_LOADER && ARM64
+ default n
+ help
+ Some hardware does not support DMA to full 64bit addresses. For this
+ hardware we can create a bounce buffer so that payloads don't have to
+ worry about platform details.
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 28e5b7f..ffce286 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -75,9 +75,6 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this,
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 = blk_get_dev(diskobj->ifname, diskobj->dev_index)))
return EFI_EXIT(EFI_DEVICE_ERROR);
@@ -94,10 +91,11 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this,
if (buffer_size & (blksz - 1))
return EFI_EXIT(EFI_DEVICE_ERROR);
- if (direction == EFI_DISK_READ)
+ if (direction == EFI_DISK_READ) {
n = desc->block_read(desc, lba, blocks, buffer);
- else
+ } else {
n = desc->block_write(desc, lba, blocks, buffer);
+ }
/* We don't do interrupts, so check for timers cooperatively */
efi_timer_check();
@@ -115,16 +113,70 @@ 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);
+ void *real_buffer = buffer;
+ efi_status_t r;
+
+#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
+ if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
+ r = efi_disk_read_blocks(this, media_id, lba,
+ EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
+ if (r != EFI_SUCCESS)
+ return r;
+ return efi_disk_read_blocks(this, media_id, lba +
+ EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
+ buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
+ buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
+ }
+
+ real_buffer = efi_bounce_buffer;
+#endif
+
+ EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
+ buffer_size, buffer);
+
+ r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
+ EFI_DISK_READ);
+
+ /* Copy from bounce buffer to real buffer if necessary */
+ if ((r == EFI_SUCCESS) && (real_buffer != buffer))
+ memcpy(buffer, real_buffer, buffer_size);
+
+ return EFI_EXIT(r);
}
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);
+ void *real_buffer = buffer;
+ efi_status_t r;
+
+#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
+ if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
+ r = efi_disk_write_blocks(this, media_id, lba,
+ EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
+ if (r != EFI_SUCCESS)
+ return r;
+ return efi_disk_write_blocks(this, media_id, lba +
+ EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
+ buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
+ buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
+ }
+
+ real_buffer = efi_bounce_buffer;
+#endif
+
+ EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
+ buffer_size, buffer);
+
+ /* Populate bounce buffer if necessary */
+ if (real_buffer != buffer)
+ memcpy(real_buffer, buffer, buffer_size);
+
+ r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
+ EFI_DISK_WRITE);
+
+ return EFI_EXIT(r);
}
static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this)
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 71a3d19..9e669f5 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -27,6 +27,10 @@ struct efi_mem_list {
/* This list contains all memory map items */
LIST_HEAD(efi_mem);
+#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
+void *efi_bounce_buffer;
+#endif
+
/*
* Sorts the memory list from highest address to lowest address
*
@@ -349,5 +353,17 @@ int efi_memory_init(void)
efi_add_memory_map(runtime_start, runtime_pages,
EFI_RUNTIME_SERVICES_CODE, false);
+#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
+ /* Request a 32bit 64MB bounce buffer region */
+ uint64_t efi_bounce_buffer_addr = 0xffffffff;
+
+ if (efi_allocate_pages(1, EFI_LOADER_DATA,
+ (64 * 1024 * 1024) >> EFI_PAGE_SHIFT,
+ &efi_bounce_buffer_addr) != EFI_SUCCESS)
+ return -1;
+
+ efi_bounce_buffer = (void*)(uintptr_t)efi_bounce_buffer_addr;
+#endif
+
return 0;
}
--
1.8.5.6
More information about the U-Boot
mailing list