From 7721da4c1ebf96ff815987011c1a0edef596b50a Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:27 -0700 Subject: efi: Move common EFI stub code from x86 arch code to common location No code changes made, just moving functions and #define from x86 arch directory to common location. Code is shared using #include, similar to how decompression code is shared among architectures. Signed-off-by: Roy Franz Acked-by: Mark Salter Reviewed-by: Grant Likely Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 463 +++++++++++++++++++++++++++++++++ 1 file changed, 463 insertions(+) create mode 100644 drivers/firmware/efi/efi-stub-helper.c (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c new file mode 100644 index 0000000..8a83387 --- /dev/null +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -0,0 +1,463 @@ +/* + * Helper functions used by the EFI stub on multiple + * architectures. This should be #included by the EFI stub + * implementation files. + * + * Copyright 2011 Intel Corporation; author Matt Fleming + * + * This file is part of the Linux kernel, and is made available + * under the terms of the GNU General Public License version 2. + * + */ +#define EFI_READ_CHUNK_SIZE (1024 * 1024) + +struct initrd { + efi_file_handle_t *handle; + u64 size; +}; + + + + +static void efi_char16_printk(efi_char16_t *str) +{ + struct efi_simple_text_output_protocol *out; + + out = (struct efi_simple_text_output_protocol *)sys_table->con_out; + efi_call_phys2(out->output_string, out, str); +} + +static void efi_printk(char *str) +{ + char *s8; + + for (s8 = str; *s8; s8++) { + efi_char16_t ch[2] = { 0 }; + + ch[0] = *s8; + if (*s8 == '\n') { + efi_char16_t nl[2] = { '\r', 0 }; + efi_char16_printk(nl); + } + + efi_char16_printk(ch); + } +} + + +static efi_status_t __get_map(efi_memory_desc_t **map, unsigned long *map_size, + unsigned long *desc_size) +{ + efi_memory_desc_t *m = NULL; + efi_status_t status; + unsigned long key; + u32 desc_version; + + *map_size = sizeof(*m) * 32; +again: + /* + * Add an additional efi_memory_desc_t because we're doing an + * allocation which may be in a new descriptor region. + */ + *map_size += sizeof(*m); + status = efi_call_phys3(sys_table->boottime->allocate_pool, + EFI_LOADER_DATA, *map_size, (void **)&m); + if (status != EFI_SUCCESS) + goto fail; + + status = efi_call_phys5(sys_table->boottime->get_memory_map, map_size, + m, &key, desc_size, &desc_version); + if (status == EFI_BUFFER_TOO_SMALL) { + efi_call_phys1(sys_table->boottime->free_pool, m); + goto again; + } + + if (status != EFI_SUCCESS) + efi_call_phys1(sys_table->boottime->free_pool, m); + +fail: + *map = m; + return status; +} + +/* + * Allocate at the highest possible address that is not above 'max'. + */ +static efi_status_t high_alloc(unsigned long size, unsigned long align, + unsigned long *addr, unsigned long max) +{ + unsigned long map_size, desc_size; + efi_memory_desc_t *map; + efi_status_t status; + unsigned long nr_pages; + u64 max_addr = 0; + int i; + + status = __get_map(&map, &map_size, &desc_size); + if (status != EFI_SUCCESS) + goto fail; + + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; +again: + for (i = 0; i < map_size / desc_size; i++) { + efi_memory_desc_t *desc; + unsigned long m = (unsigned long)map; + u64 start, end; + + desc = (efi_memory_desc_t *)(m + (i * desc_size)); + if (desc->type != EFI_CONVENTIONAL_MEMORY) + continue; + + if (desc->num_pages < nr_pages) + continue; + + start = desc->phys_addr; + end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); + + if ((start + size) > end || (start + size) > max) + continue; + + if (end - size > max) + end = max; + + if (round_down(end - size, align) < start) + continue; + + start = round_down(end - size, align); + + /* + * Don't allocate at 0x0. It will confuse code that + * checks pointers against NULL. + */ + if (start == 0x0) + continue; + + if (start > max_addr) + max_addr = start; + } + + if (!max_addr) + status = EFI_NOT_FOUND; + else { + status = efi_call_phys4(sys_table->boottime->allocate_pages, + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, + nr_pages, &max_addr); + if (status != EFI_SUCCESS) { + max = max_addr; + max_addr = 0; + goto again; + } + + *addr = max_addr; + } + +free_pool: + efi_call_phys1(sys_table->boottime->free_pool, map); + +fail: + return status; +} + +/* + * Allocate at the lowest possible address. + */ +static efi_status_t low_alloc(unsigned long size, unsigned long align, + unsigned long *addr) +{ + unsigned long map_size, desc_size; + efi_memory_desc_t *map; + efi_status_t status; + unsigned long nr_pages; + int i; + + status = __get_map(&map, &map_size, &desc_size); + if (status != EFI_SUCCESS) + goto fail; + + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + for (i = 0; i < map_size / desc_size; i++) { + efi_memory_desc_t *desc; + unsigned long m = (unsigned long)map; + u64 start, end; + + desc = (efi_memory_desc_t *)(m + (i * desc_size)); + + if (desc->type != EFI_CONVENTIONAL_MEMORY) + continue; + + if (desc->num_pages < nr_pages) + continue; + + start = desc->phys_addr; + end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); + + /* + * Don't allocate at 0x0. It will confuse code that + * checks pointers against NULL. Skip the first 8 + * bytes so we start at a nice even number. + */ + if (start == 0x0) + start += 8; + + start = round_up(start, align); + if ((start + size) > end) + continue; + + status = efi_call_phys4(sys_table->boottime->allocate_pages, + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, + nr_pages, &start); + if (status == EFI_SUCCESS) { + *addr = start; + break; + } + } + + if (i == map_size / desc_size) + status = EFI_NOT_FOUND; + +free_pool: + efi_call_phys1(sys_table->boottime->free_pool, map); +fail: + return status; +} + +static void low_free(unsigned long size, unsigned long addr) +{ + unsigned long nr_pages; + + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages); +} + + +/* + * Check the cmdline for a LILO-style initrd= arguments. + * + * We only support loading an initrd from the same filesystem as the + * kernel image. + */ +static efi_status_t handle_ramdisks(efi_loaded_image_t *image, + struct setup_header *hdr) +{ + struct initrd *initrds; + unsigned long initrd_addr; + efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID; + u64 initrd_total; + efi_file_io_interface_t *io; + efi_file_handle_t *fh; + efi_status_t status; + int nr_initrds; + char *str; + int i, j, k; + + initrd_addr = 0; + initrd_total = 0; + + str = (char *)(unsigned long)hdr->cmd_line_ptr; + + j = 0; /* See close_handles */ + + if (!str || !*str) + return EFI_SUCCESS; + + for (nr_initrds = 0; *str; nr_initrds++) { + str = strstr(str, "initrd="); + if (!str) + break; + + str += 7; + + /* Skip any leading slashes */ + while (*str == '/' || *str == '\\') + str++; + + while (*str && *str != ' ' && *str != '\n') + str++; + } + + if (!nr_initrds) + return EFI_SUCCESS; + + status = efi_call_phys3(sys_table->boottime->allocate_pool, + EFI_LOADER_DATA, + nr_initrds * sizeof(*initrds), + &initrds); + if (status != EFI_SUCCESS) { + efi_printk("Failed to alloc mem for initrds\n"); + goto fail; + } + + str = (char *)(unsigned long)hdr->cmd_line_ptr; + for (i = 0; i < nr_initrds; i++) { + struct initrd *initrd; + efi_file_handle_t *h; + efi_file_info_t *info; + efi_char16_t filename_16[256]; + unsigned long info_sz; + efi_guid_t info_guid = EFI_FILE_INFO_ID; + efi_char16_t *p; + u64 file_sz; + + str = strstr(str, "initrd="); + if (!str) + break; + + str += 7; + + initrd = &initrds[i]; + p = filename_16; + + /* Skip any leading slashes */ + while (*str == '/' || *str == '\\') + str++; + + while (*str && *str != ' ' && *str != '\n') { + if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) + break; + + if (*str == '/') { + *p++ = '\\'; + *str++; + } else { + *p++ = *str++; + } + } + + *p = '\0'; + + /* Only open the volume once. */ + if (!i) { + efi_boot_services_t *boottime; + + boottime = sys_table->boottime; + + status = efi_call_phys3(boottime->handle_protocol, + image->device_handle, &fs_proto, &io); + if (status != EFI_SUCCESS) { + efi_printk("Failed to handle fs_proto\n"); + goto free_initrds; + } + + status = efi_call_phys2(io->open_volume, io, &fh); + if (status != EFI_SUCCESS) { + efi_printk("Failed to open volume\n"); + goto free_initrds; + } + } + + status = efi_call_phys5(fh->open, fh, &h, filename_16, + EFI_FILE_MODE_READ, (u64)0); + if (status != EFI_SUCCESS) { + efi_printk("Failed to open initrd file: "); + efi_char16_printk(filename_16); + efi_printk("\n"); + goto close_handles; + } + + initrd->handle = h; + + info_sz = 0; + status = efi_call_phys4(h->get_info, h, &info_guid, + &info_sz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) { + efi_printk("Failed to get initrd info size\n"); + goto close_handles; + } + +grow: + status = efi_call_phys3(sys_table->boottime->allocate_pool, + EFI_LOADER_DATA, info_sz, &info); + if (status != EFI_SUCCESS) { + efi_printk("Failed to alloc mem for initrd info\n"); + goto close_handles; + } + + status = efi_call_phys4(h->get_info, h, &info_guid, + &info_sz, info); + if (status == EFI_BUFFER_TOO_SMALL) { + efi_call_phys1(sys_table->boottime->free_pool, info); + goto grow; + } + + file_sz = info->file_size; + efi_call_phys1(sys_table->boottime->free_pool, info); + + if (status != EFI_SUCCESS) { + efi_printk("Failed to get initrd info\n"); + goto close_handles; + } + + initrd->size = file_sz; + initrd_total += file_sz; + } + + if (initrd_total) { + unsigned long addr; + + /* + * Multiple initrd's need to be at consecutive + * addresses in memory, so allocate enough memory for + * all the initrd's. + */ + status = high_alloc(initrd_total, 0x1000, + &initrd_addr, hdr->initrd_addr_max); + if (status != EFI_SUCCESS) { + efi_printk("Failed to alloc highmem for initrds\n"); + goto close_handles; + } + + /* We've run out of free low memory. */ + if (initrd_addr > hdr->initrd_addr_max) { + efi_printk("We've run out of free low memory\n"); + status = EFI_INVALID_PARAMETER; + goto free_initrd_total; + } + + addr = initrd_addr; + for (j = 0; j < nr_initrds; j++) { + u64 size; + + size = initrds[j].size; + while (size) { + u64 chunksize; + if (size > EFI_READ_CHUNK_SIZE) + chunksize = EFI_READ_CHUNK_SIZE; + else + chunksize = size; + status = efi_call_phys3(fh->read, + initrds[j].handle, + &chunksize, addr); + if (status != EFI_SUCCESS) { + efi_printk("Failed to read initrd\n"); + goto free_initrd_total; + } + addr += chunksize; + size -= chunksize; + } + + efi_call_phys1(fh->close, initrds[j].handle); + } + + } + + efi_call_phys1(sys_table->boottime->free_pool, initrds); + + hdr->ramdisk_image = initrd_addr; + hdr->ramdisk_size = initrd_total; + + return status; + +free_initrd_total: + low_free(initrd_total, initrd_addr); + +close_handles: + for (k = j; k < i; k++) + efi_call_phys1(fh->close, initrds[k].handle); +free_initrds: + efi_call_phys1(sys_table->boottime->free_pool, initrds); +fail: + hdr->ramdisk_image = 0; + hdr->ramdisk_size = 0; + + return status; +} -- cgit v1.1 From 876dc36aceb1682cb01426f507f369aec4f68c76 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:28 -0700 Subject: efi: Add system table pointer argument to shared functions. Add system table pointer argument to shared EFI stub related functions so they no longer use a global system table pointer as they did when part of eboot.c. For the ARM EFI stub this allows us to avoid global variables completely and thereby not have to deal with GOT fixups. Not having the EFI stub fixup its GOT, which is shared with the decompressor, simplifies the relocating of the zImage to a bootable address. Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 96 ++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 44 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 8a83387..05c539e 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -19,15 +19,16 @@ struct initrd { -static void efi_char16_printk(efi_char16_t *str) +static void efi_char16_printk(efi_system_table_t *sys_table_arg, + efi_char16_t *str) { struct efi_simple_text_output_protocol *out; - out = (struct efi_simple_text_output_protocol *)sys_table->con_out; + out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out; efi_call_phys2(out->output_string, out, str); } -static void efi_printk(char *str) +static void efi_printk(efi_system_table_t *sys_table_arg, char *str) { char *s8; @@ -37,15 +38,17 @@ static void efi_printk(char *str) ch[0] = *s8; if (*s8 == '\n') { efi_char16_t nl[2] = { '\r', 0 }; - efi_char16_printk(nl); + efi_char16_printk(sys_table_arg, nl); } - efi_char16_printk(ch); + efi_char16_printk(sys_table_arg, ch); } } -static efi_status_t __get_map(efi_memory_desc_t **map, unsigned long *map_size, +static efi_status_t __get_map(efi_system_table_t *sys_table_arg, + efi_memory_desc_t **map, + unsigned long *map_size, unsigned long *desc_size) { efi_memory_desc_t *m = NULL; @@ -60,20 +63,20 @@ again: * allocation which may be in a new descriptor region. */ *map_size += sizeof(*m); - status = efi_call_phys3(sys_table->boottime->allocate_pool, + status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, EFI_LOADER_DATA, *map_size, (void **)&m); if (status != EFI_SUCCESS) goto fail; - status = efi_call_phys5(sys_table->boottime->get_memory_map, map_size, - m, &key, desc_size, &desc_version); + status = efi_call_phys5(sys_table_arg->boottime->get_memory_map, + map_size, m, &key, desc_size, &desc_version); if (status == EFI_BUFFER_TOO_SMALL) { - efi_call_phys1(sys_table->boottime->free_pool, m); + efi_call_phys1(sys_table_arg->boottime->free_pool, m); goto again; } if (status != EFI_SUCCESS) - efi_call_phys1(sys_table->boottime->free_pool, m); + efi_call_phys1(sys_table_arg->boottime->free_pool, m); fail: *map = m; @@ -83,8 +86,9 @@ fail: /* * Allocate at the highest possible address that is not above 'max'. */ -static efi_status_t high_alloc(unsigned long size, unsigned long align, - unsigned long *addr, unsigned long max) +static efi_status_t high_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, + unsigned long *addr, unsigned long max) { unsigned long map_size, desc_size; efi_memory_desc_t *map; @@ -93,7 +97,7 @@ static efi_status_t high_alloc(unsigned long size, unsigned long align, u64 max_addr = 0; int i; - status = __get_map(&map, &map_size, &desc_size); + status = __get_map(sys_table_arg, &map, &map_size, &desc_size); if (status != EFI_SUCCESS) goto fail; @@ -139,7 +143,7 @@ again: if (!max_addr) status = EFI_NOT_FOUND; else { - status = efi_call_phys4(sys_table->boottime->allocate_pages, + status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, nr_pages, &max_addr); if (status != EFI_SUCCESS) { @@ -152,7 +156,7 @@ again: } free_pool: - efi_call_phys1(sys_table->boottime->free_pool, map); + efi_call_phys1(sys_table_arg->boottime->free_pool, map); fail: return status; @@ -161,7 +165,8 @@ fail: /* * Allocate at the lowest possible address. */ -static efi_status_t low_alloc(unsigned long size, unsigned long align, +static efi_status_t low_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, unsigned long *addr) { unsigned long map_size, desc_size; @@ -170,7 +175,7 @@ static efi_status_t low_alloc(unsigned long size, unsigned long align, unsigned long nr_pages; int i; - status = __get_map(&map, &map_size, &desc_size); + status = __get_map(sys_table_arg, &map, &map_size, &desc_size); if (status != EFI_SUCCESS) goto fail; @@ -203,7 +208,7 @@ static efi_status_t low_alloc(unsigned long size, unsigned long align, if ((start + size) > end) continue; - status = efi_call_phys4(sys_table->boottime->allocate_pages, + status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, nr_pages, &start); if (status == EFI_SUCCESS) { @@ -216,17 +221,18 @@ static efi_status_t low_alloc(unsigned long size, unsigned long align, status = EFI_NOT_FOUND; free_pool: - efi_call_phys1(sys_table->boottime->free_pool, map); + efi_call_phys1(sys_table_arg->boottime->free_pool, map); fail: return status; } -static void low_free(unsigned long size, unsigned long addr) +static void low_free(efi_system_table_t *sys_table_arg, unsigned long size, + unsigned long addr) { unsigned long nr_pages; nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; - efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages); + efi_call_phys2(sys_table_arg->boottime->free_pages, addr, nr_pages); } @@ -236,7 +242,8 @@ static void low_free(unsigned long size, unsigned long addr) * We only support loading an initrd from the same filesystem as the * kernel image. */ -static efi_status_t handle_ramdisks(efi_loaded_image_t *image, +static efi_status_t handle_ramdisks(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, struct setup_header *hdr) { struct initrd *initrds; @@ -278,12 +285,12 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image, if (!nr_initrds) return EFI_SUCCESS; - status = efi_call_phys3(sys_table->boottime->allocate_pool, + status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, EFI_LOADER_DATA, nr_initrds * sizeof(*initrds), &initrds); if (status != EFI_SUCCESS) { - efi_printk("Failed to alloc mem for initrds\n"); + efi_printk(sys_table_arg, "Failed to alloc mem for initrds\n"); goto fail; } @@ -329,18 +336,18 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image, if (!i) { efi_boot_services_t *boottime; - boottime = sys_table->boottime; + boottime = sys_table_arg->boottime; status = efi_call_phys3(boottime->handle_protocol, image->device_handle, &fs_proto, &io); if (status != EFI_SUCCESS) { - efi_printk("Failed to handle fs_proto\n"); + efi_printk(sys_table_arg, "Failed to handle fs_proto\n"); goto free_initrds; } status = efi_call_phys2(io->open_volume, io, &fh); if (status != EFI_SUCCESS) { - efi_printk("Failed to open volume\n"); + efi_printk(sys_table_arg, "Failed to open volume\n"); goto free_initrds; } } @@ -348,9 +355,9 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image, status = efi_call_phys5(fh->open, fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0); if (status != EFI_SUCCESS) { - efi_printk("Failed to open initrd file: "); - efi_char16_printk(filename_16); - efi_printk("\n"); + efi_printk(sys_table_arg, "Failed to open initrd file: "); + efi_char16_printk(sys_table_arg, filename_16); + efi_printk(sys_table_arg, "\n"); goto close_handles; } @@ -360,30 +367,31 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image, status = efi_call_phys4(h->get_info, h, &info_guid, &info_sz, NULL); if (status != EFI_BUFFER_TOO_SMALL) { - efi_printk("Failed to get initrd info size\n"); + efi_printk(sys_table_arg, "Failed to get initrd info size\n"); goto close_handles; } grow: - status = efi_call_phys3(sys_table->boottime->allocate_pool, + status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, EFI_LOADER_DATA, info_sz, &info); if (status != EFI_SUCCESS) { - efi_printk("Failed to alloc mem for initrd info\n"); + efi_printk(sys_table_arg, "Failed to alloc mem for initrd info\n"); goto close_handles; } status = efi_call_phys4(h->get_info, h, &info_guid, &info_sz, info); if (status == EFI_BUFFER_TOO_SMALL) { - efi_call_phys1(sys_table->boottime->free_pool, info); + efi_call_phys1(sys_table_arg->boottime->free_pool, + info); goto grow; } file_sz = info->file_size; - efi_call_phys1(sys_table->boottime->free_pool, info); + efi_call_phys1(sys_table_arg->boottime->free_pool, info); if (status != EFI_SUCCESS) { - efi_printk("Failed to get initrd info\n"); + efi_printk(sys_table_arg, "Failed to get initrd info\n"); goto close_handles; } @@ -399,16 +407,16 @@ grow: * addresses in memory, so allocate enough memory for * all the initrd's. */ - status = high_alloc(initrd_total, 0x1000, + status = high_alloc(sys_table_arg, initrd_total, 0x1000, &initrd_addr, hdr->initrd_addr_max); if (status != EFI_SUCCESS) { - efi_printk("Failed to alloc highmem for initrds\n"); + efi_printk(sys_table_arg, "Failed to alloc highmem for initrds\n"); goto close_handles; } /* We've run out of free low memory. */ if (initrd_addr > hdr->initrd_addr_max) { - efi_printk("We've run out of free low memory\n"); + efi_printk(sys_table_arg, "We've run out of free low memory\n"); status = EFI_INVALID_PARAMETER; goto free_initrd_total; } @@ -428,7 +436,7 @@ grow: initrds[j].handle, &chunksize, addr); if (status != EFI_SUCCESS) { - efi_printk("Failed to read initrd\n"); + efi_printk(sys_table_arg, "Failed to read initrd\n"); goto free_initrd_total; } addr += chunksize; @@ -440,7 +448,7 @@ grow: } - efi_call_phys1(sys_table->boottime->free_pool, initrds); + efi_call_phys1(sys_table_arg->boottime->free_pool, initrds); hdr->ramdisk_image = initrd_addr; hdr->ramdisk_size = initrd_total; @@ -448,13 +456,13 @@ grow: return status; free_initrd_total: - low_free(initrd_total, initrd_addr); + low_free(sys_table_arg, initrd_total, initrd_addr); close_handles: for (k = j; k < i; k++) efi_call_phys1(fh->close, initrds[k].handle); free_initrds: - efi_call_phys1(sys_table->boottime->free_pool, initrds); + efi_call_phys1(sys_table_arg->boottime->free_pool, initrds); fail: hdr->ramdisk_image = 0; hdr->ramdisk_size = 0; -- cgit v1.1 From 40e4530a00b7d52332fe9a1361388fda8e5260da Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:29 -0700 Subject: efi: Rename memory allocation/free functions Rename them to be more similar, as low_free() could be used to free memory allocated by both high_alloc() and low_alloc(). high_alloc() -> efi_high_alloc() low_alloc() -> efi_low_alloc() low_free() -> efi_free() Signed-off-by: Roy Franz Acked-by: Mark Salter Reviewed-by: Grant Likely Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 05c539e..2f528fb 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -86,7 +86,7 @@ fail: /* * Allocate at the highest possible address that is not above 'max'. */ -static efi_status_t high_alloc(efi_system_table_t *sys_table_arg, +static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, unsigned long size, unsigned long align, unsigned long *addr, unsigned long max) { @@ -165,8 +165,8 @@ fail: /* * Allocate at the lowest possible address. */ -static efi_status_t low_alloc(efi_system_table_t *sys_table_arg, - unsigned long size, unsigned long align, +static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, unsigned long *addr) { unsigned long map_size, desc_size; @@ -226,7 +226,7 @@ fail: return status; } -static void low_free(efi_system_table_t *sys_table_arg, unsigned long size, +static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, unsigned long addr) { unsigned long nr_pages; @@ -407,8 +407,8 @@ grow: * addresses in memory, so allocate enough memory for * all the initrd's. */ - status = high_alloc(sys_table_arg, initrd_total, 0x1000, - &initrd_addr, hdr->initrd_addr_max); + status = efi_high_alloc(sys_table_arg, initrd_total, 0x1000, + &initrd_addr, hdr->initrd_addr_max); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to alloc highmem for initrds\n"); goto close_handles; @@ -456,7 +456,7 @@ grow: return status; free_initrd_total: - low_free(sys_table_arg, initrd_total, initrd_addr); + efi_free(sys_table_arg, initrd_total, initrd_addr); close_handles: for (k = j; k < i; k++) -- cgit v1.1 From 38dd9c02c3f2ed461165db22b93fae7f3ddde9ac Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:30 -0700 Subject: efi: Enforce minimum alignment of 1 page on allocations. The efi_high_alloc() and efi_low_alloc() functions use the EFI_ALLOCATE_ADDRESS option to the EFI function allocate_pages(), which requires a minimum of page alignment, and rejects all other requests. The existing code could fail to allocate depending on allocation size, as although repeated allocation attempts were made, none were guaranteed to be page aligned. Signed-off-by: Roy Franz Acked-by: Mark Salter Reviewed-by: Grant Likely Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 2f528fb..a256758 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -101,6 +101,14 @@ static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, if (status != EFI_SUCCESS) goto fail; + /* + * Enforce minimum alignment that EFI requires when requesting + * a specific address. We are doing page-based allocations, + * so we must be aligned to a page. + */ + if (align < EFI_PAGE_SIZE) + align = EFI_PAGE_SIZE; + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; again: for (i = 0; i < map_size / desc_size; i++) { @@ -179,6 +187,14 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, if (status != EFI_SUCCESS) goto fail; + /* + * Enforce minimum alignment that EFI requires when requesting + * a specific address. We are doing page-based allocations, + * so we must be aligned to a page. + */ + if (align < EFI_PAGE_SIZE) + align = EFI_PAGE_SIZE; + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; for (i = 0; i < map_size / desc_size; i++) { efi_memory_desc_t *desc; -- cgit v1.1 From c6866d7238d4f26055de8db9c1d5a700e554b2d4 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:31 -0700 Subject: efi: Move relocate_kernel() to shared file. The relocate_kernel() function will be generalized and used by all architectures, as they all have similar requirements. Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index a256758..333ed9c 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -485,3 +485,38 @@ fail: return status; } + +static efi_status_t relocate_kernel(struct setup_header *hdr) +{ + unsigned long start, nr_pages; + efi_status_t status; + + /* + * The EFI firmware loader could have placed the kernel image + * anywhere in memory, but the kernel has various restrictions + * on the max physical address it can run at. Attempt to move + * the kernel to boot_params.pref_address, or as low as + * possible. + */ + start = hdr->pref_address; + nr_pages = round_up(hdr->init_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + + status = efi_call_phys4(sys_table->boottime->allocate_pages, + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, + nr_pages, &start); + if (status != EFI_SUCCESS) { + status = efi_low_alloc(sys_table, hdr->init_size, + hdr->kernel_alignment, &start); + if (status != EFI_SUCCESS) + efi_printk(sys_table, "Failed to alloc mem for kernel\n"); + } + + if (status == EFI_SUCCESS) + memcpy((void *)start, (void *)(unsigned long)hdr->code32_start, + hdr->init_size); + + hdr->pref_address = hdr->code32_start; + hdr->code32_start = (__u32)start; + + return status; +} -- cgit v1.1 From 4a9f3a7c336a6b0ffeef2523bef93e67b0921163 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:32 -0700 Subject: efi: Generalize relocate_kernel() for use by other architectures. Rename relocate_kernel() to efi_relocate_kernel(), and take parameters rather than x86 specific structure. Add max_addr argument as for ARM we have some address constraints that we need to enforce when relocating the kernel. Add alloc_size parameter for use by ARM64 which uses an uncompressed kernel, and needs to allocate space for BSS. Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 76 ++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 21 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 333ed9c..361e24d 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -485,38 +485,72 @@ fail: return status; } - -static efi_status_t relocate_kernel(struct setup_header *hdr) +/* + * Relocate a kernel image, either compressed or uncompressed. + * In the ARM64 case, all kernel images are currently + * uncompressed, and as such when we relocate it we need to + * allocate additional space for the BSS segment. Any low + * memory that this function should avoid needs to be + * unavailable in the EFI memory map, as if the preferred + * address is not available the lowest available address will + * be used. + */ +static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, + unsigned long *image_addr, + unsigned long image_size, + unsigned long alloc_size, + unsigned long preferred_addr, + unsigned long alignment) { - unsigned long start, nr_pages; + unsigned long cur_image_addr; + unsigned long new_addr = 0; efi_status_t status; + unsigned long nr_pages; + efi_physical_addr_t efi_addr = preferred_addr; + + if (!image_addr || !image_size || !alloc_size) + return EFI_INVALID_PARAMETER; + if (alloc_size < image_size) + return EFI_INVALID_PARAMETER; + + cur_image_addr = *image_addr; /* * The EFI firmware loader could have placed the kernel image - * anywhere in memory, but the kernel has various restrictions - * on the max physical address it can run at. Attempt to move - * the kernel to boot_params.pref_address, or as low as - * possible. + * anywhere in memory, but the kernel has restrictions on the + * max physical address it can run at. Some architectures + * also have a prefered address, so first try to relocate + * to the preferred address. If that fails, allocate as low + * as possible while respecting the required alignment. */ - start = hdr->pref_address; - nr_pages = round_up(hdr->init_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; - - status = efi_call_phys4(sys_table->boottime->allocate_pages, + nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, - nr_pages, &start); + nr_pages, &efi_addr); + new_addr = efi_addr; + /* + * If preferred address allocation failed allocate as low as + * possible. + */ if (status != EFI_SUCCESS) { - status = efi_low_alloc(sys_table, hdr->init_size, - hdr->kernel_alignment, &start); - if (status != EFI_SUCCESS) - efi_printk(sys_table, "Failed to alloc mem for kernel\n"); + status = efi_low_alloc(sys_table_arg, alloc_size, alignment, + &new_addr); + } + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); + return status; } - if (status == EFI_SUCCESS) - memcpy((void *)start, (void *)(unsigned long)hdr->code32_start, - hdr->init_size); + /* + * We know source/dest won't overlap since both memory ranges + * have been allocated by UEFI, so we can safely use memcpy. + */ + memcpy((void *)new_addr, (void *)cur_image_addr, image_size); + /* Zero any extra space we may have allocated for BSS. */ + memset((void *)(new_addr + image_size), alloc_size - image_size, 0); - hdr->pref_address = hdr->code32_start; - hdr->code32_start = (__u32)start; + /* Return the new address of the relocated image. */ + *image_addr = new_addr; return status; } -- cgit v1.1 From 5fef3870c572a30f9def07c4ded69dc37a9cf5d9 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:33 -0700 Subject: efi: Move unicode to ASCII conversion to shared function. Move the open-coded conversion to a shared function for use by all architectures. Change the allocation to prefer a high address for ARM, as this is required to avoid conflicts with reserved regions in low memory. We don't know the specifics of these regions until after we process the command line and device tree. Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 361e24d..96665b7 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -554,3 +554,64 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, return status; } + +/* + * Convert the unicode UEFI command line to ASCII to pass to kernel. + * Size of memory allocated return in *cmd_line_len. + * Returns NULL on error. + */ +static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, + int *cmd_line_len) +{ + u16 *s2; + u8 *s1 = NULL; + unsigned long cmdline_addr = 0; + int load_options_size = image->load_options_size / 2; /* ASCII */ + void *options = image->load_options; + int options_size = 0; + efi_status_t status; + int i; + u16 zero = 0; + + if (options) { + s2 = options; + while (*s2 && *s2 != '\n' && options_size < load_options_size) { + s2++; + options_size++; + } + } + + if (options_size == 0) { + /* No command line options, so return empty string*/ + options_size = 1; + options = &zero; + } + + options_size++; /* NUL termination */ +#ifdef CONFIG_ARM + /* + * For ARM, allocate at a high address to avoid reserved + * regions at low addresses that we don't know the specfics of + * at the time we are processing the command line. + */ + status = efi_high_alloc(sys_table_arg, options_size, 0, + &cmdline_addr, 0xfffff000); +#else + status = efi_low_alloc(sys_table_arg, options_size, 0, + &cmdline_addr); +#endif + if (status != EFI_SUCCESS) + return NULL; + + s1 = (u8 *)cmdline_addr; + s2 = (u16 *)options; + + for (i = 0; i < options_size - 1; i++) + *s1++ = *s2++; + + *s1 = '\0'; + + *cmd_line_len = options_size; + return (char *)cmdline_addr; +} -- cgit v1.1 From 86cc653b1955c0a47681d16457f9ee9009f2561a Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:35 -0700 Subject: efi: Rename __get_map() to efi_get_memory_map() Rename function in preparation for making it more flexible and sharing it. Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 96665b7..561b9cf 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -46,10 +46,10 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str) } -static efi_status_t __get_map(efi_system_table_t *sys_table_arg, - efi_memory_desc_t **map, - unsigned long *map_size, - unsigned long *desc_size) +static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, + efi_memory_desc_t **map, + unsigned long *map_size, + unsigned long *desc_size) { efi_memory_desc_t *m = NULL; efi_status_t status; @@ -97,7 +97,7 @@ static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, u64 max_addr = 0; int i; - status = __get_map(sys_table_arg, &map, &map_size, &desc_size); + status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size); if (status != EFI_SUCCESS) goto fail; @@ -183,7 +183,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, unsigned long nr_pages; int i; - status = __get_map(sys_table_arg, &map, &map_size, &desc_size); + status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size); if (status != EFI_SUCCESS) goto fail; -- cgit v1.1 From 1c089c65f54b70261fdcb4c238986a979c11fad7 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:36 -0700 Subject: efi: generalize efi_get_memory_map() Add arguments for returning the descriptor version and also the memory map key. The key is required for calling exit_boot_services(). Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 561b9cf..b314bf7 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -49,7 +49,9 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str) static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, efi_memory_desc_t **map, unsigned long *map_size, - unsigned long *desc_size) + unsigned long *desc_size, + u32 *desc_ver, + unsigned long *key_ptr) { efi_memory_desc_t *m = NULL; efi_status_t status; @@ -77,6 +79,10 @@ again: if (status != EFI_SUCCESS) efi_call_phys1(sys_table_arg->boottime->free_pool, m); + if (key_ptr && status == EFI_SUCCESS) + *key_ptr = key; + if (desc_ver && status == EFI_SUCCESS) + *desc_ver = desc_version; fail: *map = m; @@ -97,7 +103,8 @@ static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, u64 max_addr = 0; int i; - status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size); + status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size, + NULL, NULL); if (status != EFI_SUCCESS) goto fail; @@ -183,7 +190,8 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, unsigned long nr_pages; int i; - status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size); + status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size, + NULL, NULL); if (status != EFI_SUCCESS) goto fail; -- cgit v1.1 From 0e1cadb05bba2293b4575c8cab275313d181d94f Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:38 -0700 Subject: efi: Allow efi_free() to be called with size of 0 Make efi_free() safely callable with size of 0, similar to free() being callable with NULL pointers, and do nothing in that case. Remove size checks that this makes redundant. This also avoids some size checks in the ARM EFI stub code that will be added as well. Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index b314bf7..fda510f 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -255,6 +255,9 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, { unsigned long nr_pages; + if (!size) + return; + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; efi_call_phys2(sys_table_arg->boottime->free_pages, addr, nr_pages); } -- cgit v1.1 From 46f4582e7cbc5f30127183812d4da875782518f5 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:39 -0700 Subject: efi: Generalize handle_ramdisks() and rename to handle_cmdline_files(). The handle_cmdline_files now takes the option to handle as a string, and returns the loaded data through parameters, rather than taking an x86 specific setup_header structure. For ARM, this will be used to load a device tree blob in addition to initrd images. Signed-off-by: Roy Franz Acked-by: Mark Salter Reviewed-by: Grant Likely Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 51 ++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 21 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index fda510f..8c78394 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -269,9 +269,12 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, * We only support loading an initrd from the same filesystem as the * kernel image. */ -static efi_status_t handle_ramdisks(efi_system_table_t *sys_table_arg, - efi_loaded_image_t *image, - struct setup_header *hdr) +static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, + char *cmd_line, char *option_string, + unsigned long max_addr, + unsigned long *load_addr, + unsigned long *load_size) { struct initrd *initrds; unsigned long initrd_addr; @@ -287,19 +290,25 @@ static efi_status_t handle_ramdisks(efi_system_table_t *sys_table_arg, initrd_addr = 0; initrd_total = 0; - str = (char *)(unsigned long)hdr->cmd_line_ptr; + str = cmd_line; j = 0; /* See close_handles */ + if (!load_addr || !load_size) + return EFI_INVALID_PARAMETER; + + *load_addr = 0; + *load_size = 0; + if (!str || !*str) return EFI_SUCCESS; for (nr_initrds = 0; *str; nr_initrds++) { - str = strstr(str, "initrd="); + str = strstr(str, option_string); if (!str) break; - str += 7; + str += strlen(option_string); /* Skip any leading slashes */ while (*str == '/' || *str == '\\') @@ -317,11 +326,11 @@ static efi_status_t handle_ramdisks(efi_system_table_t *sys_table_arg, nr_initrds * sizeof(*initrds), &initrds); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to alloc mem for initrds\n"); + efi_printk(sys_table_arg, "Failed to alloc mem for file load\n"); goto fail; } - str = (char *)(unsigned long)hdr->cmd_line_ptr; + str = cmd_line; for (i = 0; i < nr_initrds; i++) { struct initrd *initrd; efi_file_handle_t *h; @@ -332,11 +341,11 @@ static efi_status_t handle_ramdisks(efi_system_table_t *sys_table_arg, efi_char16_t *p; u64 file_sz; - str = strstr(str, "initrd="); + str = strstr(str, option_string); if (!str) break; - str += 7; + str += strlen(option_string); initrd = &initrds[i]; p = filename_16; @@ -382,7 +391,7 @@ static efi_status_t handle_ramdisks(efi_system_table_t *sys_table_arg, status = efi_call_phys5(fh->open, fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to open initrd file: "); + efi_printk(sys_table_arg, "Failed to open file: "); efi_char16_printk(sys_table_arg, filename_16); efi_printk(sys_table_arg, "\n"); goto close_handles; @@ -394,7 +403,7 @@ static efi_status_t handle_ramdisks(efi_system_table_t *sys_table_arg, status = efi_call_phys4(h->get_info, h, &info_guid, &info_sz, NULL); if (status != EFI_BUFFER_TOO_SMALL) { - efi_printk(sys_table_arg, "Failed to get initrd info size\n"); + efi_printk(sys_table_arg, "Failed to get file info size\n"); goto close_handles; } @@ -402,7 +411,7 @@ grow: status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, EFI_LOADER_DATA, info_sz, &info); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to alloc mem for initrd info\n"); + efi_printk(sys_table_arg, "Failed to alloc mem for file info\n"); goto close_handles; } @@ -418,7 +427,7 @@ grow: efi_call_phys1(sys_table_arg->boottime->free_pool, info); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to get initrd info\n"); + efi_printk(sys_table_arg, "Failed to get file info\n"); goto close_handles; } @@ -435,14 +444,14 @@ grow: * all the initrd's. */ status = efi_high_alloc(sys_table_arg, initrd_total, 0x1000, - &initrd_addr, hdr->initrd_addr_max); + &initrd_addr, max_addr); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to alloc highmem for initrds\n"); goto close_handles; } /* We've run out of free low memory. */ - if (initrd_addr > hdr->initrd_addr_max) { + if (initrd_addr > max_addr) { efi_printk(sys_table_arg, "We've run out of free low memory\n"); status = EFI_INVALID_PARAMETER; goto free_initrd_total; @@ -463,7 +472,7 @@ grow: initrds[j].handle, &chunksize, addr); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to read initrd\n"); + efi_printk(sys_table_arg, "Failed to read file\n"); goto free_initrd_total; } addr += chunksize; @@ -477,8 +486,8 @@ grow: efi_call_phys1(sys_table_arg->boottime->free_pool, initrds); - hdr->ramdisk_image = initrd_addr; - hdr->ramdisk_size = initrd_total; + *load_addr = initrd_addr; + *load_size = initrd_total; return status; @@ -491,8 +500,8 @@ close_handles: free_initrds: efi_call_phys1(sys_table_arg->boottime->free_pool, initrds); fail: - hdr->ramdisk_image = 0; - hdr->ramdisk_size = 0; + *load_addr = 0; + *load_size = 0; return status; } -- cgit v1.1 From 36f8961c963683ac12282e422dfc3db806ee0c7e Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:40 -0700 Subject: efi: Renames in handle_cmdline_files() to complete generalization. Rename variables to be not initrd specific, as now the function loads arbitrary files. This change is exclusively renames and comment changes to reflect the generalization. Signed-off-by: Roy Franz Acked-by: Mark Salter Reviewed-by: Grant Likely Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 92 +++++++++++++++++----------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 8c78394..5cea5d5 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -11,7 +11,7 @@ */ #define EFI_READ_CHUNK_SIZE (1024 * 1024) -struct initrd { +struct file_info { efi_file_handle_t *handle; u64 size; }; @@ -264,10 +264,10 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, /* - * Check the cmdline for a LILO-style initrd= arguments. + * Check the cmdline for a LILO-style file= arguments. * - * We only support loading an initrd from the same filesystem as the - * kernel image. + * We only support loading a file from the same filesystem as + * the kernel image. */ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, efi_loaded_image_t *image, @@ -276,19 +276,19 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, unsigned long *load_addr, unsigned long *load_size) { - struct initrd *initrds; - unsigned long initrd_addr; + struct file_info *files; + unsigned long file_addr; efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID; - u64 initrd_total; + u64 file_size_total; efi_file_io_interface_t *io; efi_file_handle_t *fh; efi_status_t status; - int nr_initrds; + int nr_files; char *str; int i, j, k; - initrd_addr = 0; - initrd_total = 0; + file_addr = 0; + file_size_total = 0; str = cmd_line; @@ -303,7 +303,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, if (!str || !*str) return EFI_SUCCESS; - for (nr_initrds = 0; *str; nr_initrds++) { + for (nr_files = 0; *str; nr_files++) { str = strstr(str, option_string); if (!str) break; @@ -318,21 +318,21 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, str++; } - if (!nr_initrds) + if (!nr_files) return EFI_SUCCESS; status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, EFI_LOADER_DATA, - nr_initrds * sizeof(*initrds), - &initrds); + nr_files * sizeof(*files), + &files); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to alloc mem for file load\n"); + efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); goto fail; } str = cmd_line; - for (i = 0; i < nr_initrds; i++) { - struct initrd *initrd; + for (i = 0; i < nr_files; i++) { + struct file_info *file; efi_file_handle_t *h; efi_file_info_t *info; efi_char16_t filename_16[256]; @@ -347,7 +347,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, str += strlen(option_string); - initrd = &initrds[i]; + file = &files[i]; p = filename_16; /* Skip any leading slashes */ @@ -378,13 +378,13 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, image->device_handle, &fs_proto, &io); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to handle fs_proto\n"); - goto free_initrds; + goto free_files; } status = efi_call_phys2(io->open_volume, io, &fh); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to open volume\n"); - goto free_initrds; + goto free_files; } } @@ -397,7 +397,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, goto close_handles; } - initrd->handle = h; + file->handle = h; info_sz = 0; status = efi_call_phys4(h->get_info, h, &info_guid, @@ -431,37 +431,37 @@ grow: goto close_handles; } - initrd->size = file_sz; - initrd_total += file_sz; + file->size = file_sz; + file_size_total += file_sz; } - if (initrd_total) { + if (file_size_total) { unsigned long addr; /* - * Multiple initrd's need to be at consecutive - * addresses in memory, so allocate enough memory for - * all the initrd's. + * Multiple files need to be at consecutive addresses in memory, + * so allocate enough memory for all the files. This is used + * for loading multiple files. */ - status = efi_high_alloc(sys_table_arg, initrd_total, 0x1000, - &initrd_addr, max_addr); + status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, + &file_addr, max_addr); if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to alloc highmem for initrds\n"); + efi_printk(sys_table_arg, "Failed to alloc highmem for files\n"); goto close_handles; } /* We've run out of free low memory. */ - if (initrd_addr > max_addr) { + if (file_addr > max_addr) { efi_printk(sys_table_arg, "We've run out of free low memory\n"); status = EFI_INVALID_PARAMETER; - goto free_initrd_total; + goto free_file_total; } - addr = initrd_addr; - for (j = 0; j < nr_initrds; j++) { + addr = file_addr; + for (j = 0; j < nr_files; j++) { u64 size; - size = initrds[j].size; + size = files[j].size; while (size) { u64 chunksize; if (size > EFI_READ_CHUNK_SIZE) @@ -469,36 +469,36 @@ grow: else chunksize = size; status = efi_call_phys3(fh->read, - initrds[j].handle, + files[j].handle, &chunksize, addr); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to read file\n"); - goto free_initrd_total; + goto free_file_total; } addr += chunksize; size -= chunksize; } - efi_call_phys1(fh->close, initrds[j].handle); + efi_call_phys1(fh->close, files[j].handle); } } - efi_call_phys1(sys_table_arg->boottime->free_pool, initrds); + efi_call_phys1(sys_table_arg->boottime->free_pool, files); - *load_addr = initrd_addr; - *load_size = initrd_total; + *load_addr = file_addr; + *load_size = file_size_total; return status; -free_initrd_total: - efi_free(sys_table_arg, initrd_total, initrd_addr); +free_file_total: + efi_free(sys_table_arg, file_size_total, file_addr); close_handles: for (k = j; k < i; k++) - efi_call_phys1(fh->close, initrds[k].handle); -free_initrds: - efi_call_phys1(sys_table_arg->boottime->free_pool, initrds); + efi_call_phys1(fh->close, files[k].handle); +free_files: + efi_call_phys1(sys_table_arg->boottime->free_pool, files); fail: *load_addr = 0; *load_size = 0; -- cgit v1.1 From 6a5fe770d32811ffacefaa2a430cc067ecc7336c Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:41 -0700 Subject: efi: Fix types in EFI calls to match EFI function definitions. EFI calls can made directly on ARM, so the function pointers are directly invoked. This allows types to be checked at compile time, so here we ensure that the parameters match the function signature. The wrappers used by x86 prevent any type checking. Correct the type of chunksize to be based on native width as specified by the EFI_FILE_PROTOCOL read() function. Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 5cea5d5..4252d01 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -324,7 +324,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, EFI_LOADER_DATA, nr_files * sizeof(*files), - &files); + (void **)&files); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); goto fail; @@ -375,7 +375,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, boottime = sys_table_arg->boottime; status = efi_call_phys3(boottime->handle_protocol, - image->device_handle, &fs_proto, &io); + image->device_handle, &fs_proto, + (void **)&io); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to handle fs_proto\n"); goto free_files; @@ -409,7 +410,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, grow: status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, - EFI_LOADER_DATA, info_sz, &info); + EFI_LOADER_DATA, info_sz, + (void **)&info); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to alloc mem for file info\n"); goto close_handles; @@ -459,18 +461,19 @@ grow: addr = file_addr; for (j = 0; j < nr_files; j++) { - u64 size; + unsigned long size; size = files[j].size; while (size) { - u64 chunksize; + unsigned long chunksize; if (size > EFI_READ_CHUNK_SIZE) chunksize = EFI_READ_CHUNK_SIZE; else chunksize = size; status = efi_call_phys3(fh->read, files[j].handle, - &chunksize, addr); + &chunksize, + (void *)addr); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to read file\n"); goto free_file_total; -- cgit v1.1 From 4e283088bd9af0ff119d6e15bca81a83d6e8e30c Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Sun, 22 Sep 2013 15:45:42 -0700 Subject: efi: resolve warnings found on ARM compile warnings from gcc: warning: label 'free_pool' defined but not used [-Wunused-label] warning: value computed is not used [-Wunused-value] Signed-off-by: Roy Franz Signed-off-by: Matt Fleming --- drivers/firmware/efi/efi-stub-helper.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c index 4252d01..cc0581d 100644 --- a/drivers/firmware/efi/efi-stub-helper.c +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -170,7 +170,6 @@ again: *addr = max_addr; } -free_pool: efi_call_phys1(sys_table_arg->boottime->free_pool, map); fail: @@ -244,7 +243,6 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, if (i == map_size / desc_size) status = EFI_NOT_FOUND; -free_pool: efi_call_phys1(sys_table_arg->boottime->free_pool, map); fail: return status; @@ -360,7 +358,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, if (*str == '/') { *p++ = '\\'; - *str++; + str++; } else { *p++ = *str++; } -- cgit v1.1