From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Fri, 12 Jul 2019 09:53:32 +0200 Subject: [PATCH] x86-efi: Use bounce buffers for reading to addresses > 4GB Lots of machines apparently can't DMA correctly above 4GB during UEFI, so use bounce buffers for the initramfs read. Signed-off-by: Peter Jones --- grub-core/loader/i386/efi/linux.c | 52 +++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c index 33e981e76..2f0336809 100644 --- a/grub-core/loader/i386/efi/linux.c +++ b/grub-core/loader/i386/efi/linux.c @@ -35,11 +35,16 @@ static grub_dl_t my_mod; static int loaded; static void *kernel_mem; static grub_uint64_t kernel_size; -static grub_uint8_t *initrd_mem; +static void *initrd_mem; static grub_uint32_t handover_offset; struct linux_kernel_params *params; static char *linux_cmdline; +#define MIN(a, b) \ + ({ typeof (a) _a = (a); \ + typeof (b) _b = (b); \ + _a < _b ? _a : _b; }) + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) static grub_err_t @@ -73,6 +78,44 @@ grub_linuxefi_unload (void) return GRUB_ERR_NONE; } +#define BOUNCE_BUFFER_MAX 0x10000000ull + +static grub_ssize_t +read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) +{ + grub_ssize_t bufpos = 0; + static grub_size_t bbufsz = 0; + static char *bbuf = NULL; + + if (bbufsz == 0) + bbufsz = MIN(BOUNCE_BUFFER_MAX, len); + + while (!bbuf && bbufsz) + { + bbuf = grub_malloc(bbufsz); + if (!bbuf) + bbufsz >>= 1; + } + if (!bbuf) + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer")); + + while (bufpos < (long long)len) + { + grub_ssize_t sz; + + sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos)); + if (sz < 0) + return sz; + if (sz == 0) + break; + + grub_memcpy(bufp + bufpos, bbuf, sz); + bufpos += sz; + } + + return bufpos; +} + static grub_err_t grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) @@ -126,7 +169,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), for (i = 0; i < nfiles; i++) { grub_ssize_t cursize = grub_file_size (files[i]); - if (grub_file_read (files[i], ptr, cursize) != cursize) + if (read (files[i], ptr, cursize) != cursize) { if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), @@ -152,11 +195,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), return grub_errno; } -#define MIN(a, b) \ - ({ typeof (a) _a = (a); \ - typeof (b) _b = (b); \ - _a < _b ? _a : _b; }) - static grub_err_t grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[])