This patch series adds EFI stub support for the ARM architecture.
Some code that was previously only used by x86/x86_64 is now shared
and has been made more general. The stub for ARM is implemented in
a similar manner to x86 in that it is a shim layer between EFI and
the normal zImage/bzImage boot process, and that an image with the
stub configured is bootable as both a zImage and EFI application.
This patch now (new for v3) series depends on the
"arm: Add [U]EFI runtime services support" patches by [email protected].
The Kconfig option now depends on the "CONFIG_EFI" option that his series
adds, and this option will ensure a little endian configuration. Also, the
EFI support is used to handle the EFI memory map the stub passes to the kernel.
There are some minor changes to be coordinated with the EFI runtime services
patch series, so I have put this back to RFC status. These changes should be
minor and relate to final device tree bindings.
Changes since v2:
* EFI bugfix "correct call to free_pages" that patch series
depends on now in mainline
* remove "-fno-stack-protector" from decompressor Makefile. The current code doesn't
trigger the stack protection, so the decompressor now compiles with it still
on. Note that there has never been any stack protection in the decompressor
since the stack usage doesn't trigger the heuristic in GCC, so right now
the "-fno-stack-protector" is a noop.
* Changed EFI command line handling to not have a fixed limit.
* Change FDT memory allocation to retry with a larger allocation if
first educated guess is inadequate.
* Correctly set 'SizeOfCode' in PE/COFF header.
* Reviewed ".setup" section that is in x86 PE/COFF header. This is used for x86
to account for code that is not in the .text section. We don't need this
for ARM, as all of our code is in the .text section, or in the PE/COFF header
itself.
* Moved EFI_STUB_ERROR #define to header file to share between stub C and ASM.
* Variety of cleanups and fixes in head.S.
* Changed update_fdt_and_exit_boot() to just update the device tree, and
renamed appropriately. Memory allocations moved out of this function as
well, which enables the retries if the initial FDT size is too small.
Note that in order to do the retried allocations, the original FDT and
command line memory regions are left allocated. This is OK since the kernel
has the memory map and will free these allocations along with the initrd
and new fdt allocations.
* Added prefix to all prints, reduced number of prints, and reviewed all
messages.
* Change mixed usage of dtb/fdt to all be fdt or "device tree" in efi-stub.c
* remove unnecessary zimage_size variable from relocate_kernel()
* correct return types on EFI functions - should be efi_status_t, not int.
Changes since V1:
* Updated head.S based on feedback from Dave Martin. ARM/THUMB
switches now much cleaner.
* Broke up changes to x86 and common code into more patches.
10 more patches in this series.
Roy Franz (16):
Move common EFI stub code from x86 arch code to common location
Add system pointer argument to shared EFI stub related functions
so they no longer use global system table pointer as they did
when part of eboot.c. This code is now shared, so using a
global variable as part of the interface is not that nice.
Also, by avoiding any global variables in the ARM EFI stub,
this allows the code to be position independent without
requiring GOT fixups.
Rename memory allocation/free functions
Add minimum address parameter to efi_low_alloc()
rename __get_map() to efi_get_memory_map(), add parameter to
optionally return mmap key. The mmap key is required to exit
EFI boot services, and allows efi_get_memory_map() to be used
for getting final memory map.
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.
Allow efi_free() to be called with size of 0, and do nothing in that
case.
Generalize handle_ramdisks() and rename to handle_cmdline_files().
Renames in handle_cmdline_files() to complete generalization.
Move EFI_READ_CHUNK_SIZE define to shared location.
Add proper definitions for some EFI function pointers.
Fix types in EFI calls to match EFI function definitions.
resolve warnings found on ARM compile
Add strstr to compressed string.c for ARM.
Add EFI stub for ARM
Add config EFI_STUB for ARM to Kconfig
arch/arm/Kconfig | 11 +
arch/arm/boot/compressed/Makefile | 15 +-
arch/arm/boot/compressed/efi-header.S | 111 +++++++
arch/arm/boot/compressed/efi-stub.c | 448 ++++++++++++++++++++++++++++
arch/arm/boot/compressed/efi-stub.h | 5 +
arch/arm/boot/compressed/head.S | 90 +++++-
arch/arm/boot/compressed/string.c | 21 ++
arch/x86/boot/compressed/eboot.c | 490 ++-----------------------------
arch/x86/boot/compressed/eboot.h | 9 -
drivers/firmware/efi/efi-stub-helper.c | 505 ++++++++++++++++++++++++++++++++
include/linux/efi.h | 51 +++-
11 files changed, 1263 insertions(+), 493 deletions(-)
create mode 100644 arch/arm/boot/compressed/efi-header.S
create mode 100644 arch/arm/boot/compressed/efi-stub.c
create mode 100644 arch/arm/boot/compressed/efi-stub.h
create mode 100644 drivers/firmware/efi/efi-stub-helper.c
--
1.7.10.4
No code changes made, just moving functions 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 <[email protected]>
---
arch/x86/boot/compressed/eboot.c | 442 +-----------------------------
arch/x86/boot/compressed/eboot.h | 6 -
drivers/firmware/efi/efi-stub-helper.c | 463 ++++++++++++++++++++++++++++++++
include/linux/efi.h | 8 +
4 files changed, 472 insertions(+), 447 deletions(-)
create mode 100644 drivers/firmware/efi/efi-stub-helper.c
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index b7388a4..ab0eefc 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -19,214 +19,10 @@
static efi_system_table_t *sys_table;
-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);
+#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
- 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);
-}
static void find_bits(unsigned long mask, u8 *pos, u8 *size)
{
@@ -624,242 +420,6 @@ void setup_graphics(struct boot_params *boot_params)
}
}
-struct initrd {
- efi_file_handle_t *handle;
- u64 size;
-};
-
-/*
- * 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;
-}
/*
* Because the x86 boot code expects to be passed a boot_params we
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
index e5b0a8f..faa0bdf 100644
--- a/arch/x86/boot/compressed/eboot.h
+++ b/arch/x86/boot/compressed/eboot.h
@@ -62,10 +62,4 @@ struct efi_uga_draw_protocol {
void *blt;
};
-struct efi_simple_text_output_protocol {
- void *reset;
- void *output_string;
- void *test_string;
-};
-
#endif /* BOOT_COMPRESSED_EBOOT_H */
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
new file mode 100644
index 0000000..47891bd
--- /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.
+ *
+ */
+
+
+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;
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 5f8f176..51f5641 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -784,6 +784,14 @@ struct efivar_entry {
struct kobject kobj;
};
+
+struct efi_simple_text_output_protocol {
+ void *reset;
+ void *output_string;
+ void *test_string;
+};
+
+
extern struct list_head efivar_sysfs_list;
static inline void
--
1.7.10.4
Signed-off-by: Roy Franz <[email protected]>
---
arch/x86/boot/compressed/eboot.c | 38 +++++++------
drivers/firmware/efi/efi-stub-helper.c | 96 +++++++++++++++++---------------
2 files changed, 72 insertions(+), 62 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index ab0eefc..65b6a34 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -453,13 +453,13 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
status = efi_call_phys3(sys_table->boottime->handle_protocol,
handle, &proto, (void *)&image);
if (status != EFI_SUCCESS) {
- efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
+ efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
return NULL;
}
- status = low_alloc(0x4000, 1, (unsigned long *)&boot_params);
+ status = low_alloc(sys_table, 0x4000, 1, (unsigned long *)&boot_params);
if (status != EFI_SUCCESS) {
- efi_printk("Failed to alloc lowmem for boot params\n");
+ efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
return NULL;
}
@@ -503,9 +503,10 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
options_size++; /* NUL termination */
- status = low_alloc(options_size, 1, &cmdline);
+ status = low_alloc(sys_table, options_size, 1,
+ &cmdline);
if (status != EFI_SUCCESS) {
- efi_printk("Failed to alloc mem for cmdline\n");
+ efi_printk(sys_table, "Failed to alloc mem for cmdline\n");
goto fail;
}
@@ -529,16 +530,16 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
memset(sdt, 0, sizeof(*sdt));
- status = handle_ramdisks(image, hdr);
+ status = handle_ramdisks(sys_table, image, hdr);
if (status != EFI_SUCCESS)
goto fail2;
return boot_params;
fail2:
if (options_size)
- low_free(options_size, hdr->cmd_line_ptr);
+ low_free(sys_table, options_size, hdr->cmd_line_ptr);
fail:
- low_free(0x4000, (unsigned long)boot_params);
+ low_free(sys_table, 0x4000, (unsigned long)boot_params);
return NULL;
}
@@ -561,7 +562,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
again:
size += sizeof(*mem_map) * 2;
_size = size;
- status = low_alloc(size, 1, (unsigned long *)&mem_map);
+ status = low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
if (status != EFI_SUCCESS)
return status;
@@ -569,7 +570,7 @@ get_map:
status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
mem_map, &key, &desc_size, &desc_version);
if (status == EFI_BUFFER_TOO_SMALL) {
- low_free(_size, (unsigned long)mem_map);
+ low_free(sys_table, _size, (unsigned long)mem_map);
goto again;
}
@@ -671,7 +672,7 @@ get_map:
return EFI_SUCCESS;
free_mem_map:
- low_free(_size, (unsigned long)mem_map);
+ low_free(sys_table, _size, (unsigned long)mem_map);
return status;
}
@@ -694,10 +695,10 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &start);
if (status != EFI_SUCCESS) {
- status = low_alloc(hdr->init_size, hdr->kernel_alignment,
- &start);
+ status = low_alloc(sys_table, hdr->init_size,
+ hdr->kernel_alignment, &start);
if (status != EFI_SUCCESS)
- efi_printk("Failed to alloc mem for kernel\n");
+ efi_printk(sys_table, "Failed to alloc mem for kernel\n");
}
if (status == EFI_SUCCESS)
@@ -737,14 +738,15 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
EFI_LOADER_DATA, sizeof(*gdt),
(void **)&gdt);
if (status != EFI_SUCCESS) {
- efi_printk("Failed to alloc mem for gdt structure\n");
+ efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
goto fail;
}
gdt->size = 0x800;
- status = low_alloc(gdt->size, 8, (unsigned long *)&gdt->address);
+ status = low_alloc(sys_table, gdt->size, 8,
+ (unsigned long *)&gdt->address);
if (status != EFI_SUCCESS) {
- efi_printk("Failed to alloc mem for gdt\n");
+ efi_printk(sys_table, "Failed to alloc mem for gdt\n");
goto fail;
}
@@ -752,7 +754,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
EFI_LOADER_DATA, sizeof(*idt),
(void **)&idt);
if (status != EFI_SUCCESS) {
- efi_printk("Failed to alloc mem for idt structure\n");
+ efi_printk(sys_table, "Failed to alloc mem for idt structure\n");
goto fail;
}
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 47891bd..bd6c1a2 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;
--
1.7.10.4
This allows allocations to be made low in memory while
avoiding allocations at the base of memory.
Signed-off-by: Roy Franz <[email protected]>
---
arch/x86/boot/compressed/eboot.c | 11 ++++++-----
drivers/firmware/efi/efi-stub-helper.c | 7 +++++--
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 2a4430a..f44ef2f 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -458,7 +458,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
}
status = efi_low_alloc(sys_table, 0x4000, 1,
- (unsigned long *)&boot_params);
+ (unsigned long *)&boot_params, 0);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
return NULL;
@@ -505,7 +505,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
options_size++; /* NUL termination */
status = efi_low_alloc(sys_table, options_size, 1,
- &cmdline);
+ &cmdline, 0);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for cmdline\n");
goto fail;
@@ -563,7 +563,8 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
again:
size += sizeof(*mem_map) * 2;
_size = size;
- status = efi_low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
+ status = efi_low_alloc(sys_table, size, 1,
+ (unsigned long *)&mem_map, 0);
if (status != EFI_SUCCESS)
return status;
@@ -697,7 +698,7 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)
nr_pages, &start);
if (status != EFI_SUCCESS) {
status = efi_low_alloc(sys_table, hdr->init_size,
- hdr->kernel_alignment, &start);
+ hdr->kernel_alignment, &start, 0);
if (status != EFI_SUCCESS)
efi_printk(sys_table, "Failed to alloc mem for kernel\n");
}
@@ -745,7 +746,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
gdt->size = 0x800;
status = efi_low_alloc(sys_table, gdt->size, 8,
- (unsigned long *)&gdt->address);
+ (unsigned long *)&gdt->address, 0);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for gdt\n");
goto fail;
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 0218d535..40cd16e 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -163,11 +163,11 @@ fail:
}
/*
- * Allocate at the lowest possible address.
+ * Allocate at the lowest possible address, that is not below min.
*/
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 *addr, unsigned long min)
{
unsigned long map_size, desc_size;
efi_memory_desc_t *map;
@@ -204,6 +204,9 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
if (start == 0x0)
start += 8;
+ if (start < min)
+ start = min;
+
start = round_up(start, align);
if ((start + size) > end)
continue;
--
1.7.10.4
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.
Signed-off-by: Roy Franz <[email protected]>
---
drivers/firmware/efi/efi-stub-helper.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index b707a9f..4bb542f 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -321,7 +321,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;
@@ -372,7 +372,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;
@@ -406,7 +407,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;
@@ -456,18 +458,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;
--
1.7.10.4
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 <[email protected]>
---
arch/x86/boot/compressed/eboot.c | 9 +++++-
drivers/firmware/efi/efi-stub-helper.c | 50 ++++++++++++++++++--------------
2 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index bcfdcc2..7011e33 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -443,6 +443,8 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
u16 *s2;
u8 *s1;
int i;
+ u64 ramdisk_addr;
+ u64 ramdisk_size;
sys_table = _table;
@@ -531,9 +533,14 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
memset(sdt, 0, sizeof(*sdt));
- status = handle_ramdisks(sys_table, image, hdr);
+ status = handle_cmdline_files(sys_table, image,
+ (char *)(unsigned long)hdr->cmd_line_ptr,
+ "initrd=", hdr->initrd_addr_max,
+ &ramdisk_addr, &ramdisk_size);
if (status != EFI_SUCCESS)
goto fail2;
+ hdr->ramdisk_image = ramdisk_addr;
+ hdr->ramdisk_size = ramdisk_size;
return boot_params;
fail2:
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index c45e287..b5ef766 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -267,9 +267,11 @@ 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,
+ u64 max_addr,
+ u64 *load_addr, u64 *load_size)
{
struct initrd *initrds;
unsigned long initrd_addr;
@@ -285,19 +287,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 == '\\')
@@ -315,11 +323,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;
@@ -330,11 +338,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;
@@ -380,7 +388,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 file: ");
efi_char16_printk(sys_table_arg, filename_16);
efi_printk(sys_table_arg, "\n");
goto close_handles;
@@ -392,7 +400,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;
}
@@ -400,7 +408,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;
}
@@ -416,7 +424,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;
}
@@ -433,14 +441,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;
@@ -461,7 +469,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;
@@ -475,8 +483,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;
@@ -489,8 +497,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;
}
--
1.7.10.4
Signed-off-by: Roy Franz <[email protected]>
---
arch/arm/Kconfig | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 43594d5..8607d03 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1805,6 +1805,17 @@ config UACCESS_WITH_MEMCPY
However, if the CPU data cache is using a write-allocate mode,
this option is unlikely to provide any performance gain.
+config EFI_STUB
+ bool "EFI stub support"
+ depends on EFI
+ ---help---
+ This kernel feature allows a zImage to be loaded directly
+ by EFI firmware without the use of a bootloader. A PE/COFF
+ header is added to the zImage in a way that makes the binary
+ both a Linux zImage and an PE/COFF executable that can be
+ executed directly by EFI firmware.
+ See Documentation/efi-stub.txt for more information.
+
config SECCOMP
bool
prompt "Enable seccomp to safely compute untrusted bytecode"
--
1.7.10.4
This patch adds EFI stub support for the ARM Linux kernel. The EFI stub
operations similarly to the x86 stub: it is a shim between the EFI firmware
and the normal zImage entry point, and sets up the environment that the
zImage is expecting. This includes loading the initrd (optionaly) and
device tree from the system partition based on the kernel command line.
The stub updates the device tree as necessary, including adding reserved
memory regions and adding entries for EFI runtime services. The PE/COFF
"MZ" header at offset 0 results in the first instruction being an add
that corrupts r5, which is not used by the zImage interface.
Signed-off-by: Roy Franz <[email protected]>
---
arch/arm/boot/compressed/Makefile | 15 +-
arch/arm/boot/compressed/efi-header.S | 111 ++++++++
arch/arm/boot/compressed/efi-stub.c | 448 +++++++++++++++++++++++++++++++++
arch/arm/boot/compressed/efi-stub.h | 5 +
arch/arm/boot/compressed/head.S | 90 ++++++-
5 files changed, 661 insertions(+), 8 deletions(-)
create mode 100644 arch/arm/boot/compressed/efi-header.S
create mode 100644 arch/arm/boot/compressed/efi-stub.c
create mode 100644 arch/arm/boot/compressed/efi-stub.h
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 7ac1610..5fad8bd 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -103,11 +103,22 @@ libfdt_objs := $(addsuffix .o, $(basename $(libfdt)))
$(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/%
$(call cmd,shipped)
-$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \
+$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o efi-stub.o): \
$(addprefix $(obj)/,$(libfdt_hdrs))
ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
-OBJS += $(libfdt_objs) atags_to_fdt.o
+OBJS += atags_to_fdt.o
+USE_LIBFDT = y
+endif
+
+ifeq ($(CONFIG_EFI_STUB),y)
+CFLAGS_efi-stub.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
+OBJS += efi-stub.o
+USE_LIBFDT = y
+endif
+
+ifeq ($(USE_LIBFDT),y)
+OBJS += $(libfdt_objs)
endif
targets := vmlinux vmlinux.lds \
diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S
new file mode 100644
index 0000000..6965e0f
--- /dev/null
+++ b/arch/arm/boot/compressed/efi-header.S
@@ -0,0 +1,111 @@
+@ Copyright (C) 2013 Linaro Ltd; <[email protected]>
+@
+@ This file contains the PE/COFF header that is part of the
+@ EFI stub.
+@
+
+ .org 0x3c
+ @
+ @ The PE header can be anywhere in the file, but for
+ @ simplicity we keep it together with the MSDOS header
+ @ The offset to the PE/COFF header needs to be at offset
+ @ 0x3C in the MSDOS header.
+ @ The only 2 fields of the MSDOS header that are used are this
+ @ PE/COFF offset, and the "MZ" bytes at offset 0x0.
+ @
+ .long pe_header @ Offset to the PE header.
+
+ .align 3
+pe_header:
+ .ascii "PE"
+ .short 0
+
+coff_header:
+ .short 0x01c2 @ ARM or Thumb
+ .short 2 @ nr_sections
+ .long 0 @ TimeDateStamp
+ .long 0 @ PointerToSymbolTable
+ .long 1 @ NumberOfSymbols
+ .short section_table - optional_header @ SizeOfOptionalHeader
+ .short 0x306 @ Characteristics.
+ @ IMAGE_FILE_32BIT_MACHINE |
+ @ IMAGE_FILE_DEBUG_STRIPPED |
+ @ IMAGE_FILE_EXECUTABLE_IMAGE |
+ @ IMAGE_FILE_LINE_NUMS_STRIPPED
+
+optional_header:
+ .short 0x10b @ PE32 format
+ .byte 0x02 @ MajorLinkerVersion
+ .byte 0x14 @ MinorLinkerVersion
+
+ .long _edata - efi_stub_entry @ SizeOfCode
+
+ .long 0 @ SizeOfInitializedData
+ .long 0 @ SizeOfUninitializedData
+
+ .long efi_stub_entry @ AddressOfEntryPoint
+ .long efi_stub_entry @ BaseOfCode
+ .long 0 @ data
+
+extra_header_fields:
+ .long 0 @ ImageBase
+ .long 0x20 @ SectionAlignment
+ .long 0x20 @ FileAlignment
+ .short 0 @ MajorOperatingSystemVersion
+ .short 0 @ MinorOperatingSystemVersion
+ .short 0 @ MajorImageVersion
+ .short 0 @ MinorImageVersion
+ .short 0 @ MajorSubsystemVersion
+ .short 0 @ MinorSubsystemVersion
+ .long 0 @ Win32VersionValue
+
+ .long _edata @ SizeOfImage
+
+ @ Everything before the entry point is considered part of the header
+ .long efi_stub_entry @ SizeOfHeaders
+ .long 0 @ CheckSum
+ .short 0xa @ Subsystem (EFI application)
+ .short 0 @ DllCharacteristics
+ .long 0 @ SizeOfStackReserve
+ .long 0 @ SizeOfStackCommit
+ .long 0 @ SizeOfHeapReserve
+ .long 0 @ SizeOfHeapCommit
+ .long 0 @ LoaderFlags
+ .long 0x0 @ NumberOfRvaAndSizes
+
+ # Section table
+section_table:
+
+ #
+ # The EFI application loader requires a relocation section
+ # because EFI applications must be relocatable. This is a
+ # dummy section as far as we are concerned.
+ #
+ .ascii ".reloc"
+ .byte 0
+ .byte 0 @ end of 0 padding of section name
+ .long 0
+ .long 0
+ .long 0 @ SizeOfRawData
+ .long 0 @ PointerToRawData
+ .long 0 @ PointerToRelocations
+ .long 0 @ PointerToLineNumbers
+ .short 0 @ NumberOfRelocations
+ .short 0 @ NumberOfLineNumbers
+ .long 0x42100040 @ Characteristics (section flags)
+
+
+ .ascii ".text"
+ .byte 0
+ .byte 0
+ .byte 0 @ end of 0 padding of section name
+ .long _edata - efi_stub_entry @ VirtualSize
+ .long efi_stub_entry @ VirtualAddress
+ .long _edata - efi_stub_entry @ SizeOfRawData
+ .long efi_stub_entry @ PointerToRawData
+
+ .long 0 @ PointerToRelocations (0 for executables)
+ .long 0 @ PointerToLineNumbers (0 for executables)
+ .short 0 @ NumberOfRelocations (0 for executables)
+ .short 0 @ NumberOfLineNumbers (0 for executables)
+ .long 0xe0500020 @ Characteristics (section flags)
diff --git a/arch/arm/boot/compressed/efi-stub.c b/arch/arm/boot/compressed/efi-stub.c
new file mode 100644
index 0000000..4fce68b
--- /dev/null
+++ b/arch/arm/boot/compressed/efi-stub.c
@@ -0,0 +1,448 @@
+/*
+ * linux/arch/arm/boot/compressed/efi-stub.c
+ *
+ * Copyright (C) 2013 Linaro Ltd; <[email protected]>
+ *
+ * This file implements the EFI boot stub for the ARM kernel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/efi.h>
+#include <libfdt.h>
+#include "efi-stub.h"
+
+/* EFI function call wrappers. These are not required for
+ * ARM, but wrappers are required for X86 to convert between
+ * ABIs. These wrappers are provided to allow code sharing
+ * between X86 and ARM. Since these wrappers directly invoke the
+ * EFI function pointer, the function pointer type must be properly
+ * defined, which is not the case for X86 One advantage of this is
+ * it allows for type checking of arguments, which is not
+ * possible with the X86 wrappers.
+ */
+#define efi_call_phys0(f) f()
+#define efi_call_phys1(f, a1) f(a1)
+#define efi_call_phys2(f, a1, a2) f(a1, a2)
+#define efi_call_phys3(f, a1, a2, a3) f(a1, a2, a3)
+#define efi_call_phys4(f, a1, a2, a3, a4) f(a1, a2, a3, a4)
+#define efi_call_phys5(f, a1, a2, a3, a4, a5) f(a1, a2, a3, a4, a5)
+
+/* The maximum uncompressed kernel size is 32 MBytes, so we will reserve
+ * that for the decompressed kernel. We have no easy way to tell what
+ * the actuall size of code + data the uncompressed kernel will use.
+ */
+#define MAX_UNCOMP_KERNEL_SIZE 0x02000000
+
+/* The kernel zImage should be located between 32 Mbytes
+ * and 128 MBytes from the base of DRAM. The min
+ * address leaves space for a maximal size uncompressed image,
+ * and the max address is due to how the zImage decompressor
+ * picks a destination address.
+ */
+#define ZIMAGE_OFFSET_LIMIT 0x08000000
+#define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE
+
+#define PRINTK_PREFIX "EFIstub: "
+
+struct fdt_region {
+ u64 base;
+ u64 size;
+};
+
+
+/* Include shared EFI stub code */
+#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
+
+static int relocate_kernel(efi_system_table_t *sys_table,
+ unsigned long *zimage_addr,
+ unsigned long zimage_size,
+ unsigned long min_addr, unsigned long max_addr)
+{
+ /* Get current address of kernel. */
+ unsigned long cur_zimage_addr = *zimage_addr;
+ unsigned long new_addr = 0;
+
+ efi_status_t status;
+
+ if (!zimage_addr || !zimage_size)
+ return EFI_INVALID_PARAMETER;
+
+ if (cur_zimage_addr > min_addr
+ && (cur_zimage_addr + zimage_size) < max_addr) {
+ /* We don't need to do anything, as kernel is at an
+ * acceptable address already.
+ */
+ return EFI_SUCCESS;
+ }
+ /*
+ * The EFI firmware loader could have placed the kernel image
+ * anywhere in memory, but the kernel has restrictions on the
+ * min and max physical address it can run at.
+ */
+ status = efi_low_alloc(sys_table, zimage_size, 0,
+ &new_addr, min_addr);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to allocate usable memory for kernel.\n");
+ return status;
+ }
+
+ if (new_addr > (max_addr - zimage_size)) {
+ efi_free(sys_table, zimage_size, new_addr);
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to allocate usable memory for kernel.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* 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 *)(unsigned long)cur_zimage_addr,
+ zimage_size);
+
+ /* Return the load address */
+ *zimage_addr = new_addr;
+
+ 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 *convert_cmdline_to_ascii(efi_system_table_t *sys_table,
+ efi_loaded_image_t *image,
+ unsigned long *cmd_line_len,
+ u32 max_addr)
+{
+ u16 *s2;
+ u8 *s1 = NULL;
+ unsigned long cmdline_addr = 0;
+ int load_options_size = image->load_options_size / 2; /* ASCII */
+ void *options = (u16 *)image->load_options;
+ int options_size = 0;
+ int 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 */
+
+ status = efi_high_alloc(sys_table, options_size, 0,
+ &cmdline_addr, max_addr);
+ if (status != EFI_SUCCESS)
+ return NULL;
+
+ s1 = (u8 *)(unsigned long)cmdline_addr;
+ s2 = (u16 *)options;
+
+ for (i = 0; i < options_size - 1; i++)
+ *s1++ = *s2++;
+
+ *s1 = '\0';
+
+ *cmd_line_len = options_size;
+ return (char *)(unsigned long)cmdline_addr;
+}
+
+
+static u32 update_fdt(efi_system_table_t *sys_table, void *orig_fdt, void *fdt,
+ int new_fdt_size, char *cmdline_ptr, u64 initrd_addr,
+ u64 initrd_size, efi_memory_desc_t *memory_map,
+ int map_size, int desc_size)
+{
+ int node;
+ int status;
+ unsigned long fdt_val;
+
+ status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
+ if (status != 0)
+ goto fdt_set_fail;
+
+ node = fdt_subnode_offset(fdt, 0, "chosen");
+ if (node < 0) {
+ node = fdt_add_subnode(fdt, 0, "chosen");
+ if (node < 0) {
+ status = node; /* node is error code when negative */
+ goto fdt_set_fail;
+ }
+ }
+
+ if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) {
+ status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
+ strlen(cmdline_ptr) + 1);
+ if (status)
+ goto fdt_set_fail;
+ }
+
+ /* Set intird address/end in device tree, if present */
+ if (initrd_size != 0) {
+ u64 initrd_image_end;
+ u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
+ status = fdt_setprop(fdt, node, "linux,initrd-start",
+ &initrd_image_start, sizeof(u64));
+ if (status)
+ goto fdt_set_fail;
+ initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
+ status = fdt_setprop(fdt, node, "linux,initrd-end",
+ &initrd_image_end, sizeof(u64));
+ if (status)
+ goto fdt_set_fail;
+ }
+
+ /* Add FDT entries for EFI runtime services in chosen node. */
+ node = fdt_subnode_offset(fdt, 0, "chosen");
+ fdt_val = cpu_to_fdt32((unsigned long)sys_table);
+ status = fdt_setprop(fdt, node, "efi-system-table",
+ &fdt_val, sizeof(fdt_val));
+ if (status)
+ goto fdt_set_fail;
+
+ fdt_val = cpu_to_fdt32(desc_size);
+ status = fdt_setprop(fdt, node, "efi-mmap-desc-size",
+ &fdt_val, sizeof(fdt_val));
+ if (status)
+ goto fdt_set_fail;
+
+ fdt_val = cpu_to_fdt32(map_size);
+ status = fdt_setprop(fdt, node, "efi-runtime-mmap-size",
+ &fdt_val, sizeof(fdt_val));
+ if (status)
+ goto fdt_set_fail;
+
+ fdt_val = cpu_to_fdt32((unsigned long)memory_map);
+ status = fdt_setprop(fdt, node, "efi-runtime-mmap",
+ &fdt_val, sizeof(fdt_val));
+ if (status)
+ goto fdt_set_fail;
+
+ return EFI_SUCCESS;
+
+fdt_set_fail:
+ if (status == -FDT_ERR_NOSPACE)
+ return EFI_BUFFER_TOO_SMALL;
+
+ return EFI_LOAD_ERROR;
+}
+
+
+
+int efi_entry(void *handle, efi_system_table_t *sys_table,
+ unsigned long *zimage_addr)
+{
+ efi_loaded_image_t *image;
+ int status;
+ unsigned long nr_pages;
+ const struct fdt_region *region;
+
+ void *fdt;
+ int err;
+ int node;
+ unsigned long zimage_size = 0;
+ unsigned long dram_base;
+ /* addr/point and size pairs for memory management*/
+ u64 initrd_addr;
+ u64 initrd_size = 0;
+ u64 fdt_addr;
+ u64 fdt_size = 0;
+ u64 kernel_reserve_addr;
+ u64 kernel_reserve_size = 0;
+ char *cmdline_ptr;
+ unsigned long cmdline_size = 0;
+
+ unsigned long map_size, desc_size;
+ unsigned long mmap_key;
+ efi_memory_desc_t *memory_map;
+
+ unsigned long new_fdt_size;
+ unsigned long new_fdt_addr;
+
+ efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
+
+ /* Check if we were booted by the EFI firmware */
+ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+ goto fail;
+
+ efi_printk(sys_table, PRINTK_PREFIX"Booting Linux using EFI stub.\n");
+
+
+ /* get the command line from EFI, using the LOADED_IMAGE protocol */
+ status = efi_call_phys3(sys_table->boottime->handle_protocol,
+ handle, &proto, (void *)&image);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
+ goto fail;
+ }
+
+ /* We are going to copy this into device tree, so we don't care where in
+ * memory it is.
+ */
+ cmdline_ptr = convert_cmdline_to_ascii(sys_table, image,
+ &cmdline_size, 0xFFFFFFFF);
+ if (!cmdline_ptr) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: converting command line to ascii failed.\n");
+ goto fail;
+ }
+
+ /* We first load the device tree, as we need to get the base address of
+ * DRAM from the device tree. The zImage, device tree, and initrd
+ * have address restrictions that are relative to the base of DRAM.
+ */
+ status = handle_cmdline_files(sys_table, image, cmdline_ptr, "dtb=",
+ 0xffffffff, &fdt_addr, &fdt_size);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load device tree blob.\n");
+ goto fail_free_cmdline;
+ }
+
+ err = fdt_check_header((void *)(unsigned long)fdt_addr);
+ if (err != 0) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: device tree header not valid\n");
+ goto fail_free_fdt;
+ }
+ if (fdt_totalsize((void *)(unsigned long)fdt_addr) > fdt_size) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Incomplete device tree.\n");
+ goto fail_free_fdt;
+
+ }
+
+
+ /* Look up the base of DRAM from the device tree.*/
+ fdt = (void *)(u32)fdt_addr;
+ node = fdt_subnode_offset(fdt, 0, "memory");
+ region = fdt_getprop(fdt, node, "reg", NULL);
+ if (region) {
+ dram_base = fdt64_to_cpu(region->base);
+ } else {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: no 'memory' node in device tree.\n");
+ goto fail_free_fdt;
+ }
+
+ /* Reserve memory for the uncompressed kernel image. */
+ kernel_reserve_addr = dram_base;
+ kernel_reserve_size = MAX_UNCOMP_KERNEL_SIZE;
+ nr_pages = round_up(kernel_reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+ status = efi_call_phys4(sys_table->boottime->allocate_pages,
+ EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
+ nr_pages, &kernel_reserve_addr);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: unable to allocate memory for uncompressed kernel.\n");
+ goto fail_free_fdt;
+ }
+
+ /* Relocate the zImage, if required. */
+ zimage_size = image->image_size;
+ status = relocate_kernel(sys_table, zimage_addr, zimage_size,
+ dram_base + MIN_ZIMAGE_OFFSET,
+ dram_base + ZIMAGE_OFFSET_LIMIT);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to relocate kernel\n");
+ goto fail_free_kernel_reserve;
+ }
+
+ status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=",
+ dram_base + ZIMAGE_OFFSET_LIMIT,
+ &initrd_addr, &initrd_size);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load initrd\n");
+ goto fail_free_zimage;
+ }
+
+ /* Estimate size of new FDT, and allocate memory for it. We
+ * will allocate a bigger buffer if this ends up being too
+ * small, so a rough guess is OK here.*/
+ new_fdt_size = fdt_size + cmdline_size + 0x200;
+
+fdt_alloc_retry:
+ status = efi_high_alloc(sys_table, new_fdt_size, 0, &new_fdt_addr,
+ dram_base + ZIMAGE_OFFSET_LIMIT);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to allocate memory for new device tree.\n");
+ goto fail_free_initrd;
+ }
+
+ /* Now that we have done our final memory allocation (and free)
+ * we can get the memory map key needed
+ * forexit_boot_services.*/
+ status = efi_get_memory_map(sys_table, &memory_map, &map_size,
+ &desc_size, &mmap_key);
+ if (status != EFI_SUCCESS)
+ goto fail_free_new_fdt;
+
+ status = update_fdt(sys_table,
+ fdt, (void *)new_fdt_addr, new_fdt_size,
+ cmdline_ptr,
+ initrd_addr, initrd_size,
+ memory_map, map_size, desc_size);
+
+ if (status != EFI_SUCCESS) {
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ /* We need to allocate more space for the new
+ * device tree, so free existing buffer that is
+ * too small. Also free memory map, as we will need
+ * to get new one that reflects the free/alloc we do
+ * on the device tree buffer. */
+ efi_free(sys_table, new_fdt_size, new_fdt_addr);
+ efi_call_phys1(sys_table->boottime->free_pool,
+ memory_map);
+ new_fdt_size += new_fdt_size/4;
+ goto fdt_alloc_retry;
+ }
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to constuct new device tree.\n");
+ goto fail_free_initrd;
+ }
+
+ /* Now we are ready to exit_boot_services.*/
+ status = efi_call_phys2(sys_table->boottime->exit_boot_services,
+ handle, mmap_key);
+
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, PRINTK_PREFIX"ERROR: exit boot services failed.\n");
+ goto fail_free_mmap;
+ }
+
+
+ /* Now we need to return the FDT address to the calling
+ * assembly to this can be used as part of normal boot.
+ */
+ return new_fdt_addr;
+
+fail_free_mmap:
+ efi_call_phys1(sys_table->boottime->free_pool, memory_map);
+
+fail_free_new_fdt:
+ efi_free(sys_table, new_fdt_size, new_fdt_addr);
+
+fail_free_initrd:
+ efi_free(sys_table, initrd_size, initrd_addr);
+
+fail_free_zimage:
+ efi_free(sys_table, zimage_size, *zimage_addr);
+
+fail_free_kernel_reserve:
+ efi_free(sys_table, kernel_reserve_addr, kernel_reserve_size);
+
+fail_free_fdt:
+ efi_free(sys_table, fdt_size, fdt_addr);
+
+fail_free_cmdline:
+ efi_free(sys_table, cmdline_size, (u32)cmdline_ptr);
+
+fail:
+ return EFI_STUB_ERROR;
+}
diff --git a/arch/arm/boot/compressed/efi-stub.h b/arch/arm/boot/compressed/efi-stub.h
new file mode 100644
index 0000000..0fe9376
--- /dev/null
+++ b/arch/arm/boot/compressed/efi-stub.h
@@ -0,0 +1,5 @@
+#ifndef _ARM_EFI_STUB_H
+#define _ARM_EFI_STUB_H
+/* Error code returned to ASM code instead of valid FDT address. */
+#define EFI_STUB_ERROR (~0)
+#endif
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 75189f1..5401a3a 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -10,6 +10,7 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include "efi-stub.h"
.arch armv7-a
/*
@@ -120,21 +121,99 @@
*/
.align
.arm @ Always enter in ARM state
+ .text
start:
.type start,#function
- .rept 7
+#ifdef CONFIG_EFI_STUB
+ @ Magic MSDOS signature for PE/COFF + ADD opcode
+ .word 0x62805a4d
+#else
+ mov r0, r0
+#endif
+ .rept 5
mov r0, r0
.endr
- ARM( mov r0, r0 )
- ARM( b 1f )
- THUMB( adr r12, BSYM(1f) )
- THUMB( bx r12 )
+
+ adrl r12, BSYM(zimage_continue)
+ ARM( mov pc, r12 )
+ THUMB( bx r12 )
+ @ zimage_continue will be in ARM or thumb mode as configured
.word 0x016f2818 @ Magic numbers to help the loader
.word start @ absolute load/run zImage address
.word _edata @ zImage end address
+
+#ifdef CONFIG_EFI_STUB
+ @ Portions of the MSDOS file header must be at offset
+ @ 0x3c from the start of the file. All PE/COFF headers
+ @ are kept contiguous for simplicity.
+#include "efi-header.S"
+
+efi_stub_entry:
+ @ The EFI stub entry point is not at a fixed address, however
+ @ this address must be set in the PE/COFF header.
+ @ EFI entry point is in A32 mode, switch to T32 if configured.
+ THUMB( adr r12, BSYM(1f) )
+ THUMB( bx r12 )
THUMB( .thumb )
1:
+ @ Save lr on stack for possible return to EFI firmware.
+ @ Don't care about fp, but need 64 bit alignment....
+ stmfd sp!, {fp, lr}
+
+ @ allocate space on stack for return of new entry point of
+ @ zImage, as EFI stub may copy the kernel. Pass address
+ @ of space in r2 - EFI stub will fill in the pointer.
+
+ sub sp, sp, #8 @ we only need 4 bytes,
+ @ but keep stack 8 byte aligned.
+ mov r2, sp
+ @ Pass our actual runtime start address in pointer data
+ adr r11, LC0 @ address of LC0 at run time
+ ldr r12, [r11, #0] @ address of LC0 at link time
+
+ sub r3, r11, r12 @ calculate the delta offset
+ str r3, [r2, #0]
+ bl efi_entry
+
+ @ get new zImage entry address from stack, put into r3
+ ldr r3, [sp, #0]
+ add sp, sp, #8 @ restore stack
+
+ @ Check for error return from EFI stub
+ mov r1, #EFI_STUB_ERROR
+ cmp r0, r1
+ beq efi_load_fail
+
+
+ @ Save return values of efi_entry
+ stmfd sp!, {r0, r3}
+ bl cache_clean_flush
+ bl cache_off
+ ldmfd sp!, {r0, r3}
+
+ @ Set parameters for booting zImage according to boot protocol
+ @ put FDT address in r2, it was returned by efi_entry()
+ @ r1 is FDT machine type, and r0 needs to be 0
+ mov r2, r0
+ mov r1, #0xFFFFFFFF
+ mov r0, #0
+
+ @ Branch to (possibly) relocated zImage that is in r3
+ @ Make sure we are in A32 mode, as zImage requires
+ THUMB( bx r3 )
+ ARM( mov pc, r3 )
+
+efi_load_fail:
+ @ Return EFI_LOAD_ERROR to EFI firmware on error.
+ @ Switch back to ARM mode for EFI is done based on
+ @ return address on stack
+ ldr r0, =0x80000001
+ ldmfd sp!, {fp, pc}
+#endif
+
+ THUMB( .thumb )
+zimage_continue:
mrs r9, cpsr
#ifdef CONFIG_ARM_VIRT_EXT
bl __hyp_stub_install @ get into SVC mode, reversibly
@@ -167,7 +246,6 @@ not_angel:
* by the linker here, but it should preserve r7, r8, and r9.
*/
- .text
#ifdef CONFIG_AUTO_ZRELADDR
@ determine final kernel image address
--
1.7.10.4
The shared efi-stub-helper.c functions require a strstr
implementation.
Implementation copied from arch/x86/boot/string.c
Signed-off-by: Roy Franz <[email protected]>
---
arch/arm/boot/compressed/string.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c
index 36e53ef..5397792 100644
--- a/arch/arm/boot/compressed/string.c
+++ b/arch/arm/boot/compressed/string.c
@@ -111,6 +111,27 @@ char *strchr(const char *s, int c)
return (char *)s;
}
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+ size_t l1, l2;
+
+ l2 = strlen(s2);
+ if (!l2)
+ return (char *)s1;
+ l1 = strlen(s1);
+ while (l1 >= l2) {
+ l1--;
+ if (!memcmp(s1, s2, l2))
+ return (char *)s1;
+ s1++;
+ }
+ return NULL;
+}
#undef memset
void *memset(void *s, int c, size_t count)
--
1.7.10.4
Make efi_free() safely callable with size of 0, similar to free() being
callable with NULL pointers.
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 <[email protected]>
---
arch/x86/boot/compressed/eboot.c | 3 +--
drivers/firmware/efi/efi-stub-helper.c | 3 +++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index f44ef2f..bcfdcc2 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -537,8 +537,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
return boot_params;
fail2:
- if (options_size)
- efi_free(sys_table, options_size, hdr->cmd_line_ptr);
+ efi_free(sys_table, options_size, hdr->cmd_line_ptr);
fail:
efi_free(sys_table, 0x4000, (unsigned long)boot_params);
return NULL;
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 647b3ba..c45e287 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -253,6 +253,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);
}
--
1.7.10.4
2 unused labels
1 "value computed is not used"
Signed-off-by: Roy Franz <[email protected]>
---
drivers/firmware/efi/efi-stub-helper.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 4bb542f..3e82cb0 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -166,7 +166,6 @@ again:
*addr = max_addr;
}
-free_pool:
efi_call_phys1(sys_table_arg->boottime->free_pool, map);
fail:
@@ -242,7 +241,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;
@@ -357,7 +355,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
if (*str == '/') {
*p++ = '\\';
- *str++;
+ str++;
} else {
*p++ = *str++;
}
--
1.7.10.4
The x86/AMD64 EFI stubs must us a call wrapper to convert between
the Linux and EFI ABIs, so void pointers are sufficient. For ARM,
the ABIs are compatible, so we can directly invoke the function
pointers. The functions that are used by the ARM stub are updated
to match the EFI definitions.
Signed-off-by: Roy Franz <[email protected]>
---
arch/x86/boot/compressed/eboot.h | 2 --
include/linux/efi.h | 45 ++++++++++++++++++++++++--------------
2 files changed, 28 insertions(+), 19 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
index bafbd94..81b6b65 100644
--- a/arch/x86/boot/compressed/eboot.h
+++ b/arch/x86/boot/compressed/eboot.h
@@ -11,8 +11,6 @@
#define DESC_TYPE_CODE_DATA (1 << 0)
-#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
-
#define EFI_CONSOLE_OUT_DEVICE_GUID \
EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
0x3f, 0xc1, 0x4d)
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 51f5641..1a7ae34 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -39,6 +39,8 @@
typedef unsigned long efi_status_t;
typedef u8 efi_bool_t;
typedef u16 efi_char16_t; /* UNICODE character */
+typedef u64 efi_physical_addr_t;
+typedef void *efi_handle_t;
typedef struct {
@@ -96,6 +98,7 @@ typedef struct {
#define EFI_MEMORY_DESCRIPTOR_VERSION 1
#define EFI_PAGE_SHIFT 12
+#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
typedef struct {
u32 type;
@@ -157,11 +160,13 @@ typedef struct {
efi_table_hdr_t hdr;
void *raise_tpl;
void *restore_tpl;
- void *allocate_pages;
- void *free_pages;
- void *get_memory_map;
- void *allocate_pool;
- void *free_pool;
+ efi_status_t (*allocate_pages)(int, int, unsigned long,
+ efi_physical_addr_t *);
+ efi_status_t (*free_pages)(efi_physical_addr_t, unsigned long);
+ efi_status_t (*get_memory_map)(unsigned long *, void *, unsigned long *,
+ unsigned long *, u32 *);
+ efi_status_t (*allocate_pool)(int, unsigned long, void **);
+ efi_status_t (*free_pool)(void *);
void *create_event;
void *set_timer;
void *wait_for_event;
@@ -171,7 +176,7 @@ typedef struct {
void *install_protocol_interface;
void *reinstall_protocol_interface;
void *uninstall_protocol_interface;
- void *handle_protocol;
+ efi_status_t (*handle_protocol)(efi_handle_t, efi_guid_t *, void **);
void *__reserved;
void *register_protocol_notify;
void *locate_handle;
@@ -181,7 +186,7 @@ typedef struct {
void *start_image;
void *exit;
void *unload_image;
- void *exit_boot_services;
+ efi_status_t (*exit_boot_services)(efi_handle_t, unsigned long);
void *get_next_monotonic_count;
void *stall;
void *set_watchdog_timer;
@@ -488,10 +493,6 @@ typedef struct {
unsigned long unload;
} efi_loaded_image_t;
-typedef struct {
- u64 revision;
- void *open_volume;
-} efi_file_io_interface_t;
typedef struct {
u64 size;
@@ -504,20 +505,30 @@ typedef struct {
efi_char16_t filename[1];
} efi_file_info_t;
-typedef struct {
+typedef struct _efi_file_handle {
u64 revision;
- void *open;
- void *close;
+ efi_status_t (*open)(struct _efi_file_handle *,
+ struct _efi_file_handle **,
+ efi_char16_t *, u64, u64);
+ efi_status_t (*close)(struct _efi_file_handle *);
void *delete;
- void *read;
+ efi_status_t (*read)(struct _efi_file_handle *, unsigned long *,
+ void *);
void *write;
void *get_position;
void *set_position;
- void *get_info;
+ efi_status_t (*get_info)(struct _efi_file_handle *, efi_guid_t *,
+ unsigned long *, void *);
void *set_info;
void *flush;
} efi_file_handle_t;
+typedef struct _efi_file_io_interface {
+ u64 revision;
+ int (*open_volume)(struct _efi_file_io_interface *,
+ efi_file_handle_t **);
+} efi_file_io_interface_t;
+
#define EFI_FILE_MODE_READ 0x0000000000000001
#define EFI_FILE_MODE_WRITE 0x0000000000000002
#define EFI_FILE_MODE_CREATE 0x8000000000000000
@@ -787,7 +798,7 @@ struct efivar_entry {
struct efi_simple_text_output_protocol {
void *reset;
- void *output_string;
+ efi_status_t (*output_string)(void *, void *);
void *test_string;
};
--
1.7.10.4
This #define is only used the the shared code, so move
it there.
Signed-off-by: Roy Franz <[email protected]>
---
arch/x86/boot/compressed/eboot.h | 1 -
drivers/firmware/efi/efi-stub-helper.c | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
index faa0bdf..bafbd94 100644
--- a/arch/x86/boot/compressed/eboot.h
+++ b/arch/x86/boot/compressed/eboot.h
@@ -12,7 +12,6 @@
#define DESC_TYPE_CODE_DATA (1 << 0)
#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
-#define EFI_READ_CHUNK_SIZE (1024 * 1024)
#define EFI_CONSOLE_OUT_DEVICE_GUID \
EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 0f4d6e6..b707a9f 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -9,7 +9,7 @@
* under the terms of the GNU General Public License version 2.
*
*/
-
+#define EFI_READ_CHUNK_SIZE (1024 * 1024)
struct file_info {
efi_file_handle_t *handle;
--
1.7.10.4
Rename variables to be not initrd specific, as now the function
loads arbitrary files.
Signed-off-by: Roy Franz <[email protected]>
---
drivers/firmware/efi/efi-stub-helper.c | 92 ++++++++++++++++----------------
1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index b5ef766..0f4d6e6 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -11,7 +11,7 @@
*/
-struct initrd {
+struct file_info {
efi_file_handle_t *handle;
u64 size;
};
@@ -262,10 +262,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,
@@ -273,19 +273,19 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
u64 max_addr,
u64 *load_addr, u64 *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;
@@ -300,7 +300,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;
@@ -315,21 +315,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];
@@ -344,7 +344,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 */
@@ -375,13 +375,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;
}
}
@@ -394,7 +394,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,
@@ -428,37 +428,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)
@@ -466,36 +466,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;
--
1.7.10.4
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 <[email protected]>
---
drivers/firmware/efi/efi-stub-helper.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 1d0a079..647b3ba 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -105,6 +105,13 @@ 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++) {
@@ -184,6 +191,13 @@ 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;
--
1.7.10.4
Signed-off-by: Roy Franz <[email protected]>
---
drivers/firmware/efi/efi-stub-helper.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 40cd16e..1d0a079 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -46,10 +46,11 @@ 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,
+ unsigned long *key_ptr)
{
efi_memory_desc_t *m = NULL;
efi_status_t status;
@@ -77,6 +78,8 @@ again:
if (status != EFI_SUCCESS)
efi_call_phys1(sys_table_arg->boottime->free_pool, m);
+ if (key_ptr && status == EFI_SUCCESS)
+ *key_ptr = key;
fail:
*map = m;
@@ -97,7 +100,8 @@ 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,
+ NULL);
if (status != EFI_SUCCESS)
goto fail;
@@ -175,7 +179,8 @@ 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,
+ NULL);
if (status != EFI_SUCCESS)
goto fail;
--
1.7.10.4
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 <[email protected]>
---
arch/x86/boot/compressed/eboot.c | 19 ++++++++++---------
drivers/firmware/efi/efi-stub-helper.c | 14 +++++++-------
2 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 65b6a34..2a4430a 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -457,7 +457,8 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
return NULL;
}
- status = low_alloc(sys_table, 0x4000, 1, (unsigned long *)&boot_params);
+ status = efi_low_alloc(sys_table, 0x4000, 1,
+ (unsigned long *)&boot_params);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
return NULL;
@@ -503,7 +504,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
options_size++; /* NUL termination */
- status = low_alloc(sys_table, options_size, 1,
+ status = efi_low_alloc(sys_table, options_size, 1,
&cmdline);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for cmdline\n");
@@ -537,9 +538,9 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
return boot_params;
fail2:
if (options_size)
- low_free(sys_table, options_size, hdr->cmd_line_ptr);
+ efi_free(sys_table, options_size, hdr->cmd_line_ptr);
fail:
- low_free(sys_table, 0x4000, (unsigned long)boot_params);
+ efi_free(sys_table, 0x4000, (unsigned long)boot_params);
return NULL;
}
@@ -562,7 +563,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
again:
size += sizeof(*mem_map) * 2;
_size = size;
- status = low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
+ status = efi_low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
if (status != EFI_SUCCESS)
return status;
@@ -570,7 +571,7 @@ get_map:
status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
mem_map, &key, &desc_size, &desc_version);
if (status == EFI_BUFFER_TOO_SMALL) {
- low_free(sys_table, _size, (unsigned long)mem_map);
+ efi_free(sys_table, _size, (unsigned long)mem_map);
goto again;
}
@@ -672,7 +673,7 @@ get_map:
return EFI_SUCCESS;
free_mem_map:
- low_free(sys_table, _size, (unsigned long)mem_map);
+ efi_free(sys_table, _size, (unsigned long)mem_map);
return status;
}
@@ -695,7 +696,7 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &start);
if (status != EFI_SUCCESS) {
- status = low_alloc(sys_table, hdr->init_size,
+ 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");
@@ -743,7 +744,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
}
gdt->size = 0x800;
- status = low_alloc(sys_table, gdt->size, 8,
+ status = efi_low_alloc(sys_table, gdt->size, 8,
(unsigned long *)&gdt->address);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for gdt\n");
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index bd6c1a2..0218d535 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++)
--
1.7.10.4
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> * Change FDT memory allocation to retry with a larger allocation if
> first educated guess is inadequate.
With this change, it looks like you no longer free the original cmdline
and fdt memory. The current flow looks like:
retry:
allocate_memory_for_expanded_fdt
get_memory_map
if (update_fdt() fails) {
free new_fdt and memory_map
goto retry
}
So, this keeps the original fdt around and uses it as a starting point
for newly allocated expanded fdt. You don't know if the new fdt is big
enough until update_fdt() succeeds. But at that point, you already wrote
the efi-runtime-mmap property with the memory_map still having the
original cmdline and fdt in it.
I think you should be able to have an expand_fdt() function which bumps
the fdt size and uses the current fdt as the starting point instead of
the original fdt. That way you can free the original fdt on the first
iteration and free the original cmdline as soon as it is successfully
written. Then the last thing you do if get the memory_map and write it.
--Mark
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> +static int relocate_kernel(efi_system_table_t *sys_table,
> + unsigned long *zimage_addr,
> + unsigned long zimage_size,
> + unsigned long min_addr, unsigned long max_addr)
> +{
> + /* Get current address of kernel. */
> + unsigned long cur_zimage_addr = *zimage_addr;
> + unsigned long new_addr = 0;
> +
> + efi_status_t status;
> +
> + if (!zimage_addr || !zimage_size)
> + return EFI_INVALID_PARAMETER;
> +
This parameter check is too late. You already used zimage_addr to
initialize cur_zimage_addr.
--Mark
On Mon, Aug 12, 2013 at 7:51 AM, Mark Salter <[email protected]> wrote:
> On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
>> +static int relocate_kernel(efi_system_table_t *sys_table,
>> + unsigned long *zimage_addr,
>> + unsigned long zimage_size,
>> + unsigned long min_addr, unsigned long max_addr)
>> +{
>> + /* Get current address of kernel. */
>> + unsigned long cur_zimage_addr = *zimage_addr;
>> + unsigned long new_addr = 0;
>> +
>> + efi_status_t status;
>> +
>> + if (!zimage_addr || !zimage_size)
>> + return EFI_INVALID_PARAMETER;
>> +
>
> This parameter check is too late. You already used zimage_addr to
> initialize cur_zimage_addr.
>
> --Mark
>
Thanks - I'll fix this in the next version.
Roy
On Mon, Aug 12, 2013 at 7:02 AM, Mark Salter <[email protected]> wrote:
> On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
>> * Change FDT memory allocation to retry with a larger allocation if
>> first educated guess is inadequate.
>
> With this change, it looks like you no longer free the original cmdline
> and fdt memory. The current flow looks like:
>
> retry:
> allocate_memory_for_expanded_fdt
> get_memory_map
> if (update_fdt() fails) {
> free new_fdt and memory_map
> goto retry
> }
>
> So, this keeps the original fdt around and uses it as a starting point
> for newly allocated expanded fdt. You don't know if the new fdt is big
> enough until update_fdt() succeeds. But at that point, you already wrote
> the efi-runtime-mmap property with the memory_map still having the
> original cmdline and fdt in it.
>
> I think you should be able to have an expand_fdt() function which bumps
> the fdt size and uses the current fdt as the starting point instead of
> the original fdt. That way you can free the original fdt on the first
> iteration and free the original cmdline as soon as it is successfully
> written. Then the last thing you do if get the memory_map and write it.
>
> --Mark
Hi Mark,
I think this will work with the current FDT fields that are being set
by the stub. In earlier
versions, I was also updating the reserved memory map using
fdt_add_mem_rsv(), so
iteratively updating the device tree wouldn't work. The reserved
regions would change,
and so the repeated updates would cause there to be repeated and
incorrect reserved regions.
I'm inclined to leave it as is, which should correctly update the
device tree even if methods like
fdt_add_mem_rsv() are used, with the tradeoff being there will be a
few more memory regions
for the kernel to free when it processes the EFI memory map. The
kernel already needs to process
the EFI memory map to free the buffers use to load the kernel and
initrd, so these buffers will get freed, just not
by the stub.
Roy
On Fri, Aug 09, 2013 at 04:26:17PM -0700, Roy Franz wrote:
> Signed-off-by: Roy Franz <[email protected]>
> ---
> arch/arm/Kconfig | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 43594d5..8607d03 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1805,6 +1805,17 @@ config UACCESS_WITH_MEMCPY
> However, if the CPU data cache is using a write-allocate mode,
> this option is unlikely to provide any performance gain.
>
> +config EFI_STUB
> + bool "EFI stub support"
> + depends on EFI
&& !CPU_BIG_ENDIAN, in case you didn't get around to that.
Sooner or later, someone may try to fix that, so there should be a
comment somewhere explaining what is broken for BE.
Either in efi-stub.c or in the commit message accompanying this patch, I
guess.
Cheers
---Dave
> + ---help---
> + This kernel feature allows a zImage to be loaded directly
> + by EFI firmware without the use of a bootloader. A PE/COFF
> + header is added to the zImage in a way that makes the binary
> + both a Linux zImage and an PE/COFF executable that can be
> + executed directly by EFI firmware.
> + See Documentation/efi-stub.txt for more information.
> +
> config SECCOMP
> bool
> prompt "Enable seccomp to safely compute untrusted bytecode"
> --
> 1.7.10.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> No code changes made, just moving functions 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 <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> Signed-off-by: Roy Franz <[email protected]>
> ---
> arch/x86/boot/compressed/eboot.c | 38 +++++++------
> drivers/firmware/efi/efi-stub-helper.c | 96 +++++++++++++++++---------------
> 2 files changed, 72 insertions(+), 62 deletions(-)
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> This allows allocations to be made low in memory while
> avoiding allocations at the base of memory.
>
> Signed-off-by: Roy Franz <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> Signed-off-by: Roy Franz <[email protected]>
> ---
> drivers/firmware/efi/efi-stub-helper.c | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> 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 <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> Rename variables to be not initrd specific, as now the function
> loads arbitrary files.
>
> Signed-off-by: Roy Franz <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> This #define is only used the the shared code, so move
> it there.
>
> Signed-off-by: Roy Franz <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> 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.
>
> Signed-off-by: Roy Franz <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> 2 unused labels
> 1 "value computed is not used"
>
>
> Signed-off-by: Roy Franz <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> The x86/AMD64 EFI stubs must us a call wrapper to convert between
> the Linux and EFI ABIs, so void pointers are sufficient. For ARM,
> the ABIs are compatible, so we can directly invoke the function
> pointers. The functions that are used by the ARM stub are updated
> to match the EFI definitions.
>
> Signed-off-by: Roy Franz <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> 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 <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> 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 <[email protected]>
> ---
Tested on arm64.
Acked-by: Mark Salter <[email protected]>
On Fri, Aug 09, 2013 at 04:26:16PM -0700, Roy Franz wrote:
> This patch adds EFI stub support for the ARM Linux kernel. The EFI stub
> operations similarly to the x86 stub: it is a shim between the EFI firmware
> and the normal zImage entry point, and sets up the environment that the
> zImage is expecting. This includes loading the initrd (optionaly) and
> device tree from the system partition based on the kernel command line.
> The stub updates the device tree as necessary, including adding reserved
> memory regions and adding entries for EFI runtime services. The PE/COFF
> "MZ" header at offset 0 results in the first instruction being an add
> that corrupts r5, which is not used by the zImage interface.
Thanks for the update -- a few more comments, nothing major.
> Signed-off-by: Roy Franz <[email protected]>
> ---
> arch/arm/boot/compressed/Makefile | 15 +-
> arch/arm/boot/compressed/efi-header.S | 111 ++++++++
> arch/arm/boot/compressed/efi-stub.c | 448 +++++++++++++++++++++++++++++++++
> arch/arm/boot/compressed/efi-stub.h | 5 +
> arch/arm/boot/compressed/head.S | 90 ++++++-
> 5 files changed, 661 insertions(+), 8 deletions(-)
> create mode 100644 arch/arm/boot/compressed/efi-header.S
> create mode 100644 arch/arm/boot/compressed/efi-stub.c
> create mode 100644 arch/arm/boot/compressed/efi-stub.h
>
> diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
> index 7ac1610..5fad8bd 100644
> --- a/arch/arm/boot/compressed/Makefile
> +++ b/arch/arm/boot/compressed/Makefile
> @@ -103,11 +103,22 @@ libfdt_objs := $(addsuffix .o, $(basename $(libfdt)))
> $(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/%
> $(call cmd,shipped)
>
> -$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \
> +$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o efi-stub.o): \
> $(addprefix $(obj)/,$(libfdt_hdrs))
>
> ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
> -OBJS += $(libfdt_objs) atags_to_fdt.o
> +OBJS += atags_to_fdt.o
> +USE_LIBFDT = y
> +endif
> +
> +ifeq ($(CONFIG_EFI_STUB),y)
> +CFLAGS_efi-stub.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
> +OBJS += efi-stub.o
> +USE_LIBFDT = y
> +endif
> +
> +ifeq ($(USE_LIBFDT),y)
> +OBJS += $(libfdt_objs)
> endif
>
> targets := vmlinux vmlinux.lds \
> diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S
> new file mode 100644
> index 0000000..6965e0f
> --- /dev/null
> +++ b/arch/arm/boot/compressed/efi-header.S
> @@ -0,0 +1,111 @@
> +@ Copyright (C) 2013 Linaro Ltd; <[email protected]>
> +@
> +@ This file contains the PE/COFF header that is part of the
> +@ EFI stub.
> +@
> +
> + .org 0x3c
> + @
> + @ The PE header can be anywhere in the file, but for
> + @ simplicity we keep it together with the MSDOS header
> + @ The offset to the PE/COFF header needs to be at offset
> + @ 0x3C in the MSDOS header.
> + @ The only 2 fields of the MSDOS header that are used are this
> + @ PE/COFF offset, and the "MZ" bytes at offset 0x0.
> + @
> + .long pe_header @ Offset to the PE header.
> +
> + .align 3
> +pe_header:
> + .ascii "PE"
> + .short 0
> +
> +coff_header:
> + .short 0x01c2 @ ARM or Thumb
> + .short 2 @ nr_sections
> + .long 0 @ TimeDateStamp
> + .long 0 @ PointerToSymbolTable
> + .long 1 @ NumberOfSymbols
> + .short section_table - optional_header @ SizeOfOptionalHeader
> + .short 0x306 @ Characteristics.
> + @ IMAGE_FILE_32BIT_MACHINE |
> + @ IMAGE_FILE_DEBUG_STRIPPED |
> + @ IMAGE_FILE_EXECUTABLE_IMAGE |
> + @ IMAGE_FILE_LINE_NUMS_STRIPPED
> +
> +optional_header:
> + .short 0x10b @ PE32 format
> + .byte 0x02 @ MajorLinkerVersion
> + .byte 0x14 @ MinorLinkerVersion
> +
> + .long _edata - efi_stub_entry @ SizeOfCode
> +
> + .long 0 @ SizeOfInitializedData
> + .long 0 @ SizeOfUninitializedData
> +
> + .long efi_stub_entry @ AddressOfEntryPoint
> + .long efi_stub_entry @ BaseOfCode
> + .long 0 @ data
> +
> +extra_header_fields:
> + .long 0 @ ImageBase
> + .long 0x20 @ SectionAlignment
> + .long 0x20 @ FileAlignment
> + .short 0 @ MajorOperatingSystemVersion
> + .short 0 @ MinorOperatingSystemVersion
> + .short 0 @ MajorImageVersion
> + .short 0 @ MinorImageVersion
> + .short 0 @ MajorSubsystemVersion
> + .short 0 @ MinorSubsystemVersion
> + .long 0 @ Win32VersionValue
> +
> + .long _edata @ SizeOfImage
> +
> + @ Everything before the entry point is considered part of the header
> + .long efi_stub_entry @ SizeOfHeaders
> + .long 0 @ CheckSum
> + .short 0xa @ Subsystem (EFI application)
> + .short 0 @ DllCharacteristics
> + .long 0 @ SizeOfStackReserve
> + .long 0 @ SizeOfStackCommit
> + .long 0 @ SizeOfHeapReserve
> + .long 0 @ SizeOfHeapCommit
> + .long 0 @ LoaderFlags
> + .long 0x0 @ NumberOfRvaAndSizes
> +
> + # Section table
> +section_table:
> +
> + #
> + # The EFI application loader requires a relocation section
> + # because EFI applications must be relocatable. This is a
> + # dummy section as far as we are concerned.
> + #
> + .ascii ".reloc"
> + .byte 0
> + .byte 0 @ end of 0 padding of section name
> + .long 0
> + .long 0
> + .long 0 @ SizeOfRawData
> + .long 0 @ PointerToRawData
> + .long 0 @ PointerToRelocations
> + .long 0 @ PointerToLineNumbers
> + .short 0 @ NumberOfRelocations
> + .short 0 @ NumberOfLineNumbers
> + .long 0x42100040 @ Characteristics (section flags)
> +
> +
> + .ascii ".text"
> + .byte 0
> + .byte 0
> + .byte 0 @ end of 0 padding of section name
> + .long _edata - efi_stub_entry @ VirtualSize
> + .long efi_stub_entry @ VirtualAddress
> + .long _edata - efi_stub_entry @ SizeOfRawData
> + .long efi_stub_entry @ PointerToRawData
> +
> + .long 0 @ PointerToRelocations (0 for executables)
> + .long 0 @ PointerToLineNumbers (0 for executables)
> + .short 0 @ NumberOfRelocations (0 for executables)
> + .short 0 @ NumberOfLineNumbers (0 for executables)
> + .long 0xe0500020 @ Characteristics (section flags)
> diff --git a/arch/arm/boot/compressed/efi-stub.c b/arch/arm/boot/compressed/efi-stub.c
> new file mode 100644
> index 0000000..4fce68b
> --- /dev/null
> +++ b/arch/arm/boot/compressed/efi-stub.c
> @@ -0,0 +1,448 @@
> +/*
> + * linux/arch/arm/boot/compressed/efi-stub.c
> + *
> + * Copyright (C) 2013 Linaro Ltd; <[email protected]>
> + *
> + * This file implements the EFI boot stub for the ARM kernel
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +#include <linux/efi.h>
> +#include <libfdt.h>
> +#include "efi-stub.h"
> +
> +/* EFI function call wrappers. These are not required for
> + * ARM, but wrappers are required for X86 to convert between
> + * ABIs. These wrappers are provided to allow code sharing
> + * between X86 and ARM. Since these wrappers directly invoke the
> + * EFI function pointer, the function pointer type must be properly
> + * defined, which is not the case for X86 One advantage of this is
> + * it allows for type checking of arguments, which is not
> + * possible with the X86 wrappers.
> + */
> +#define efi_call_phys0(f) f()
> +#define efi_call_phys1(f, a1) f(a1)
> +#define efi_call_phys2(f, a1, a2) f(a1, a2)
> +#define efi_call_phys3(f, a1, a2, a3) f(a1, a2, a3)
> +#define efi_call_phys4(f, a1, a2, a3, a4) f(a1, a2, a3, a4)
> +#define efi_call_phys5(f, a1, a2, a3, a4, a5) f(a1, a2, a3, a4, a5)
> +
> +/* The maximum uncompressed kernel size is 32 MBytes, so we will reserve
> + * that for the decompressed kernel. We have no easy way to tell what
> + * the actuall size of code + data the uncompressed kernel will use.
> + */
> +#define MAX_UNCOMP_KERNEL_SIZE 0x02000000
> +
> +/* The kernel zImage should be located between 32 Mbytes
> + * and 128 MBytes from the base of DRAM. The min
> + * address leaves space for a maximal size uncompressed image,
> + * and the max address is due to how the zImage decompressor
> + * picks a destination address.
> + */
> +#define ZIMAGE_OFFSET_LIMIT 0x08000000
> +#define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE
> +
> +#define PRINTK_PREFIX "EFIstub: "
> +
> +struct fdt_region {
> + u64 base;
> + u64 size;
> +};
> +
> +
> +/* Include shared EFI stub code */
> +#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
> +
> +static int relocate_kernel(efi_system_table_t *sys_table,
> + unsigned long *zimage_addr,
> + unsigned long zimage_size,
> + unsigned long min_addr, unsigned long max_addr)
> +{
> + /* Get current address of kernel. */
> + unsigned long cur_zimage_addr = *zimage_addr;
> + unsigned long new_addr = 0;
> +
> + efi_status_t status;
> +
> + if (!zimage_addr || !zimage_size)
> + return EFI_INVALID_PARAMETER;
> +
> + if (cur_zimage_addr > min_addr
> + && (cur_zimage_addr + zimage_size) < max_addr) {
> + /* We don't need to do anything, as kernel is at an
> + * acceptable address already.
> + */
> + return EFI_SUCCESS;
> + }
> + /*
> + * The EFI firmware loader could have placed the kernel image
> + * anywhere in memory, but the kernel has restrictions on the
> + * min and max physical address it can run at.
> + */
> + status = efi_low_alloc(sys_table, zimage_size, 0,
> + &new_addr, min_addr);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to allocate usable memory for kernel.\n");
> + return status;
> + }
> +
> + if (new_addr > (max_addr - zimage_size)) {
> + efi_free(sys_table, zimage_size, new_addr);
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to allocate usable memory for kernel.\n");
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + /* 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 *)(unsigned long)cur_zimage_addr,
> + zimage_size);
> +
> + /* Return the load address */
> + *zimage_addr = new_addr;
> +
> + 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 *convert_cmdline_to_ascii(efi_system_table_t *sys_table,
> + efi_loaded_image_t *image,
> + unsigned long *cmd_line_len,
> + u32 max_addr)
> +{
> + u16 *s2;
> + u8 *s1 = NULL;
> + unsigned long cmdline_addr = 0;
> + int load_options_size = image->load_options_size / 2; /* ASCII */
> + void *options = (u16 *)image->load_options;
> + int options_size = 0;
> + int 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 */
> +
> + status = efi_high_alloc(sys_table, options_size, 0,
> + &cmdline_addr, max_addr);
> + if (status != EFI_SUCCESS)
> + return NULL;
> +
> + s1 = (u8 *)(unsigned long)cmdline_addr;
> + s2 = (u16 *)options;
> +
> + for (i = 0; i < options_size - 1; i++)
> + *s1++ = *s2++;
> +
> + *s1 = '\0';
> +
> + *cmd_line_len = options_size;
> + return (char *)(unsigned long)cmdline_addr;
> +}
> +
> +
> +static u32 update_fdt(efi_system_table_t *sys_table, void *orig_fdt, void *fdt,
> + int new_fdt_size, char *cmdline_ptr, u64 initrd_addr,
> + u64 initrd_size, efi_memory_desc_t *memory_map,
> + int map_size, int desc_size)
> +{
> + int node;
> + int status;
> + unsigned long fdt_val;
> +
> + status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
> + if (status != 0)
> + goto fdt_set_fail;
> +
> + node = fdt_subnode_offset(fdt, 0, "chosen");
> + if (node < 0) {
> + node = fdt_add_subnode(fdt, 0, "chosen");
> + if (node < 0) {
> + status = node; /* node is error code when negative */
> + goto fdt_set_fail;
> + }
> + }
> +
> + if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) {
> + status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
> + strlen(cmdline_ptr) + 1);
> + if (status)
> + goto fdt_set_fail;
> + }
> +
> + /* Set intird address/end in device tree, if present */
> + if (initrd_size != 0) {
> + u64 initrd_image_end;
> + u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
> + status = fdt_setprop(fdt, node, "linux,initrd-start",
> + &initrd_image_start, sizeof(u64));
> + if (status)
> + goto fdt_set_fail;
> + initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
> + status = fdt_setprop(fdt, node, "linux,initrd-end",
> + &initrd_image_end, sizeof(u64));
> + if (status)
> + goto fdt_set_fail;
> + }
> +
> + /* Add FDT entries for EFI runtime services in chosen node. */
> + node = fdt_subnode_offset(fdt, 0, "chosen");
> + fdt_val = cpu_to_fdt32((unsigned long)sys_table);
> + status = fdt_setprop(fdt, node, "efi-system-table",
> + &fdt_val, sizeof(fdt_val));
> + if (status)
> + goto fdt_set_fail;
> +
> + fdt_val = cpu_to_fdt32(desc_size);
> + status = fdt_setprop(fdt, node, "efi-mmap-desc-size",
> + &fdt_val, sizeof(fdt_val));
> + if (status)
> + goto fdt_set_fail;
> +
> + fdt_val = cpu_to_fdt32(map_size);
> + status = fdt_setprop(fdt, node, "efi-runtime-mmap-size",
> + &fdt_val, sizeof(fdt_val));
> + if (status)
> + goto fdt_set_fail;
> +
> + fdt_val = cpu_to_fdt32((unsigned long)memory_map);
> + status = fdt_setprop(fdt, node, "efi-runtime-mmap",
> + &fdt_val, sizeof(fdt_val));
> + if (status)
> + goto fdt_set_fail;
> +
> + return EFI_SUCCESS;
This looks better.
> +
> +fdt_set_fail:
> + if (status == -FDT_ERR_NOSPACE)
> + return EFI_BUFFER_TOO_SMALL;
> +
> + return EFI_LOAD_ERROR;
> +}
> +
> +
> +
Maybe add a comment to indicate that this returns the address of the
relocated fdt, or EFI_LOAD_ERROR.
By default "int" feels more likely to return a status code.
It is not common to return pointers using the "int" type: it may be
preferable to use unsigned long of void * instead. This won't
change the functionality.
Casts to (int) which could overflow the signed range can cause GCC
to generate bizarre code in some situations, because C doesn't
have to guarantee wrapping when casting to signed types. Since we
just pass that value through without doing any arithmetic I think we're
unlikely to hit that here, but it's best avoided anyhow.
> +int efi_entry(void *handle, efi_system_table_t *sys_table,
> + unsigned long *zimage_addr)
> +{
> + efi_loaded_image_t *image;
> + int status;
> + unsigned long nr_pages;
> + const struct fdt_region *region;
> +
> + void *fdt;
> + int err;
> + int node;
> + unsigned long zimage_size = 0;
> + unsigned long dram_base;
> + /* addr/point and size pairs for memory management*/
> + u64 initrd_addr;
> + u64 initrd_size = 0;
> + u64 fdt_addr;
> + u64 fdt_size = 0;
> + u64 kernel_reserve_addr;
> + u64 kernel_reserve_size = 0;
> + char *cmdline_ptr;
> + unsigned long cmdline_size = 0;
> +
> + unsigned long map_size, desc_size;
> + unsigned long mmap_key;
> + efi_memory_desc_t *memory_map;
> +
> + unsigned long new_fdt_size;
> + unsigned long new_fdt_addr;
> +
> + efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
> +
> + /* Check if we were booted by the EFI firmware */
> + if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
> + goto fail;
> +
> + efi_printk(sys_table, PRINTK_PREFIX"Booting Linux using EFI stub.\n");
> +
> +
> + /* get the command line from EFI, using the LOADED_IMAGE protocol */
> + status = efi_call_phys3(sys_table->boottime->handle_protocol,
> + handle, &proto, (void *)&image);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
> + goto fail;
> + }
> +
> + /* We are going to copy this into device tree, so we don't care where in
> + * memory it is.
> + */
> + cmdline_ptr = convert_cmdline_to_ascii(sys_table, image,
> + &cmdline_size, 0xFFFFFFFF);
> + if (!cmdline_ptr) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: converting command line to ascii failed.\n");
The real reason for this failure is failure to allocate memory: there's
no other way it can fail.
So, the error message could be "Unable to allocate memory for command
line"
> + goto fail;
> + }
> +
> + /* We first load the device tree, as we need to get the base address of
> + * DRAM from the device tree. The zImage, device tree, and initrd
> + * have address restrictions that are relative to the base of DRAM.
> + */
> + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "dtb=",
> + 0xffffffff, &fdt_addr, &fdt_size);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load device tree blob.\n");
> + goto fail_free_cmdline;
> + }
> +
> + err = fdt_check_header((void *)(unsigned long)fdt_addr);
> + if (err != 0) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: device tree header not valid\n");
> + goto fail_free_fdt;
> + }
> + if (fdt_totalsize((void *)(unsigned long)fdt_addr) > fdt_size) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Incomplete device tree.\n");
> + goto fail_free_fdt;
> +
> + }
> +
> +
> + /* Look up the base of DRAM from the device tree.*/
> + fdt = (void *)(u32)fdt_addr;
> + node = fdt_subnode_offset(fdt, 0, "memory");
> + region = fdt_getprop(fdt, node, "reg", NULL);
> + if (region) {
> + dram_base = fdt64_to_cpu(region->base);
> + } else {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: no 'memory' node in device tree.\n");
> + goto fail_free_fdt;
> + }
> +
> + /* Reserve memory for the uncompressed kernel image. */
> + kernel_reserve_addr = dram_base;
> + kernel_reserve_size = MAX_UNCOMP_KERNEL_SIZE;
> + nr_pages = round_up(kernel_reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
> + status = efi_call_phys4(sys_table->boottime->allocate_pages,
> + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
> + nr_pages, &kernel_reserve_addr);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: unable to allocate memory for uncompressed kernel.\n");
> + goto fail_free_fdt;
> + }
> +
> + /* Relocate the zImage, if required. */
> + zimage_size = image->image_size;
> + status = relocate_kernel(sys_table, zimage_addr, zimage_size,
> + dram_base + MIN_ZIMAGE_OFFSET,
> + dram_base + ZIMAGE_OFFSET_LIMIT);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to relocate kernel\n");
> + goto fail_free_kernel_reserve;
> + }
> +
> + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=",
> + dram_base + ZIMAGE_OFFSET_LIMIT,
> + &initrd_addr, &initrd_size);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load initrd\n");
> + goto fail_free_zimage;
> + }
> +
> + /* Estimate size of new FDT, and allocate memory for it. We
> + * will allocate a bigger buffer if this ends up being too
> + * small, so a rough guess is OK here.*/
> + new_fdt_size = fdt_size + cmdline_size + 0x200;
> +
> +fdt_alloc_retry:
Minor stylistic thing, but looping using goto is not too readable.
The following while loop might be a bit clearer, but I leave it
up to you.
while (1) {
> + status = efi_high_alloc(sys_table, new_fdt_size, 0, &new_fdt_addr,
> + dram_base + ZIMAGE_OFFSET_LIMIT);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to allocate memory for new device tree.\n");
> + goto fail_free_initrd;
> + }
> +
> + /* Now that we have done our final memory allocation (and free)
> + * we can get the memory map key needed
> + * forexit_boot_services.*/
> + status = efi_get_memory_map(sys_table, &memory_map, &map_size,
> + &desc_size, &mmap_key);
> + if (status != EFI_SUCCESS)
> + goto fail_free_new_fdt;
> +
> + status = update_fdt(sys_table,
> + fdt, (void *)new_fdt_addr, new_fdt_size,
> + cmdline_ptr,
> + initrd_addr, initrd_size,
> + memory_map, map_size, desc_size);
if (status == EFI_SUCCESS)
break;
instead of
> +
> + if (status != EFI_SUCCESS) {
then
if (status != EFI_BUFFER_TOO_SMALL)
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to constuct new device tree.\n");
> + goto fail_free_initrd;
instead of
> + if (status == EFI_BUFFER_TOO_SMALL) {
then
> + /* We need to allocate more space for the new
> + * device tree, so free existing buffer that is
> + * too small. Also free memory map, as we will need
> + * to get new one that reflects the free/alloc we do
> + * on the device tree buffer. */
> + efi_free(sys_table, new_fdt_size, new_fdt_addr);
> + efi_call_phys1(sys_table->boottime->free_pool,
> + memory_map);
> + new_fdt_size += new_fdt_size/4;
And then just loop
}
instead of the rest:
> + goto fdt_alloc_retry;
> + }
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to constuct new device tree.\n");
> + goto fail_free_initrd;
> + }
> +
> + /* Now we are ready to exit_boot_services.*/
> + status = efi_call_phys2(sys_table->boottime->exit_boot_services,
> + handle, mmap_key);
> +
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: exit boot services failed.\n");
> + goto fail_free_mmap;
> + }
> +
> +
> + /* Now we need to return the FDT address to the calling
> + * assembly to this can be used as part of normal boot.
> + */
> + return new_fdt_addr;
> +
> +fail_free_mmap:
> + efi_call_phys1(sys_table->boottime->free_pool, memory_map);
> +
> +fail_free_new_fdt:
> + efi_free(sys_table, new_fdt_size, new_fdt_addr);
> +
> +fail_free_initrd:
> + efi_free(sys_table, initrd_size, initrd_addr);
> +
> +fail_free_zimage:
> + efi_free(sys_table, zimage_size, *zimage_addr);
> +
> +fail_free_kernel_reserve:
> + efi_free(sys_table, kernel_reserve_addr, kernel_reserve_size);
> +
> +fail_free_fdt:
> + efi_free(sys_table, fdt_size, fdt_addr);
> +
> +fail_free_cmdline:
> + efi_free(sys_table, cmdline_size, (u32)cmdline_ptr);
> +
> +fail:
> + return EFI_STUB_ERROR;
> +}
> diff --git a/arch/arm/boot/compressed/efi-stub.h b/arch/arm/boot/compressed/efi-stub.h
> new file mode 100644
> index 0000000..0fe9376
> --- /dev/null
> +++ b/arch/arm/boot/compressed/efi-stub.h
> @@ -0,0 +1,5 @@
> +#ifndef _ARM_EFI_STUB_H
> +#define _ARM_EFI_STUB_H
> +/* Error code returned to ASM code instead of valid FDT address. */
> +#define EFI_STUB_ERROR (~0)
> +#endif
> diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
> index 75189f1..5401a3a 100644
> --- a/arch/arm/boot/compressed/head.S
> +++ b/arch/arm/boot/compressed/head.S
> @@ -10,6 +10,7 @@
> */
> #include <linux/linkage.h>
> #include <asm/assembler.h>
> +#include "efi-stub.h"
>
> .arch armv7-a
> /*
> @@ -120,21 +121,99 @@
> */
> .align
> .arm @ Always enter in ARM state
> + .text
> start:
> .type start,#function
> - .rept 7
> +#ifdef CONFIG_EFI_STUB
> + @ Magic MSDOS signature for PE/COFF + ADD opcode
> + .word 0x62805a4d
> +#else
> + mov r0, r0
> +#endif
> + .rept 5
> mov r0, r0
> .endr
> - ARM( mov r0, r0 )
> - ARM( b 1f )
> - THUMB( adr r12, BSYM(1f) )
> - THUMB( bx r12 )
> +
> + adrl r12, BSYM(zimage_continue)
> + ARM( mov pc, r12 )
> + THUMB( bx r12 )
> + @ zimage_continue will be in ARM or thumb mode as configured
>
> .word 0x016f2818 @ Magic numbers to help the loader
> .word start @ absolute load/run zImage address
> .word _edata @ zImage end address
> +
> +#ifdef CONFIG_EFI_STUB
> + @ Portions of the MSDOS file header must be at offset
> + @ 0x3c from the start of the file. All PE/COFF headers
> + @ are kept contiguous for simplicity.
> +#include "efi-header.S"
> +
> +efi_stub_entry:
> + @ The EFI stub entry point is not at a fixed address, however
> + @ this address must be set in the PE/COFF header.
> + @ EFI entry point is in A32 mode, switch to T32 if configured.
> + THUMB( adr r12, BSYM(1f) )
> + THUMB( bx r12 )
> THUMB( .thumb )
> 1:
> + @ Save lr on stack for possible return to EFI firmware.
> + @ Don't care about fp, but need 64 bit alignment....
> + stmfd sp!, {fp, lr}
> +
> + @ allocate space on stack for return of new entry point of
> + @ zImage, as EFI stub may copy the kernel. Pass address
> + @ of space in r2 - EFI stub will fill in the pointer.
> +
> + sub sp, sp, #8 @ we only need 4 bytes,
> + @ but keep stack 8 byte aligned.
> + mov r2, sp
You can save an instruction here: skip these two instructions, and see
below just before the call to efi_entry [1]
> + @ Pass our actual runtime start address in pointer data
> + adr r11, LC0 @ address of LC0 at run time
> + ldr r12, [r11, #0] @ address of LC0 at link time
Can we just move this delta calculation after efi_entry?
You don't need to specifiy an explicit offset if it's zero, btw:
ldr r12, [r11]
works just as well. Same for the other instances.
> +
> + sub r3, r11, r12 @ calculate the delta offset
> + str r3, [r2, #0]
I think r2 is still equal to sp, so
str r3, [sp]
should be OK.
[1]Or, combine this with the modification of sp:
str r3, [sp, #-8]!
mov r2, sp
> + bl efi_entry
> +
> + @ get new zImage entry address from stack, put into r3
> + ldr r3, [sp, #0]
> + add sp, sp, #8 @ restore stack
ldr r3, [sp], #8
> +
> + @ Check for error return from EFI stub
> + mov r1, #EFI_STUB_ERROR
> + cmp r0, r1
cmp r0, #EFI_STUB_ERROR
probably works. The assembler will turn this into a cmn as necessary.
> + beq efi_load_fail
> +
> +
> + @ Save return values of efi_entry
> + stmfd sp!, {r0, r3}
> + bl cache_clean_flush
> + bl cache_off
> + ldmfd sp!, {r0, r3}
> +
> + @ Set parameters for booting zImage according to boot protocol
> + @ put FDT address in r2, it was returned by efi_entry()
> + @ r1 is FDT machine type, and r0 needs to be 0
> + mov r2, r0
> + mov r1, #0xFFFFFFFF
> + mov r0, #0
> +
> + @ Branch to (possibly) relocated zImage that is in r3
> + @ Make sure we are in A32 mode, as zImage requires
> + THUMB( bx r3 )
> + ARM( mov pc, r3 )
> +
> +efi_load_fail:
> + @ Return EFI_LOAD_ERROR to EFI firmware on error.
> + @ Switch back to ARM mode for EFI is done based on
> + @ return address on stack
> + ldr r0, =0x80000001
> + ldmfd sp!, {fp, pc}
> +#endif
> +
> + THUMB( .thumb )
> +zimage_continue:
> mrs r9, cpsr
> #ifdef CONFIG_ARM_VIRT_EXT
> bl __hyp_stub_install @ get into SVC mode, reversibly
> @@ -167,7 +246,6 @@ not_angel:
> * by the linker here, but it should preserve r7, r8, and r9.
> */
>
> - .text
>
> #ifdef CONFIG_AUTO_ZRELADDR
> @ determine final kernel image address
> --
> 1.7.10.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Mon, 2013-08-12 at 18:13 -0700, Roy Franz wrote:
> On Mon, Aug 12, 2013 at 7:02 AM, Mark Salter <[email protected]> wrote:
> > On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> >> * Change FDT memory allocation to retry with a larger allocation if
> >> first educated guess is inadequate.
> >
> > With this change, it looks like you no longer free the original cmdline
> > and fdt memory. The current flow looks like:
> >
> > retry:
> > allocate_memory_for_expanded_fdt
> > get_memory_map
> > if (update_fdt() fails) {
> > free new_fdt and memory_map
> > goto retry
> > }
> >
> > So, this keeps the original fdt around and uses it as a starting point
> > for newly allocated expanded fdt. You don't know if the new fdt is big
> > enough until update_fdt() succeeds. But at that point, you already wrote
> > the efi-runtime-mmap property with the memory_map still having the
> > original cmdline and fdt in it.
> >
> > I think you should be able to have an expand_fdt() function which bumps
> > the fdt size and uses the current fdt as the starting point instead of
> > the original fdt. That way you can free the original fdt on the first
> > iteration and free the original cmdline as soon as it is successfully
> > written. Then the last thing you do if get the memory_map and write it.
> >
> > --Mark
>
> Hi Mark,
>
> I think this will work with the current FDT fields that are being set
> by the stub. In earlier
> versions, I was also updating the reserved memory map using
> fdt_add_mem_rsv(), so
> iteratively updating the device tree wouldn't work. The reserved
> regions would change,
> and so the repeated updates would cause there to be repeated and
> incorrect reserved regions.
> I'm inclined to leave it as is, which should correctly update the
> device tree even if methods like
> fdt_add_mem_rsv() are used, with the tradeoff being there will be a
> few more memory regions
> for the kernel to free when it processes the EFI memory map. The
> kernel already needs to process
> the EFI memory map to free the buffers use to load the kernel and
> initrd, so these buffers will get freed, just not
> by the stub.
>
Got it. Thanks for the explanation.
On Tue, Aug 13, 2013 at 6:18 AM, Dave Martin <[email protected]> wrote:
> On Fri, Aug 09, 2013 at 04:26:17PM -0700, Roy Franz wrote:
>> Signed-off-by: Roy Franz <[email protected]>
>> ---
>> arch/arm/Kconfig | 11 +++++++++++
>> 1 file changed, 11 insertions(+)
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 43594d5..8607d03 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -1805,6 +1805,17 @@ config UACCESS_WITH_MEMCPY
>> However, if the CPU data cache is using a write-allocate mode,
>> this option is unlikely to provide any performance gain.
>>
>> +config EFI_STUB
>> + bool "EFI stub support"
>> + depends on EFI
>
> && !CPU_BIG_ENDIAN, in case you didn't get around to that.
>
> Sooner or later, someone may try to fix that, so there should be a
> comment somewhere explaining what is broken for BE.
>
> Either in efi-stub.c or in the commit message accompanying this patch, I
> guess.
>
EFI will be !CPU_BIG_ENDIAN, so we will get the dependency
transitively through EFI.
That said, I think it may be better to have both be explicitly
!CPU_BIG_ENDIAN, as even
though the underlying reasons are the same (EFI services calls being
little endian), both
the stub and runtime services would need to be fixed to enable the
stub to run in BE mode.
I'll make this explicit in the stub Kconfig, and add a comment by the
PE/COFF magic number
regarding the LE requirement.
Thanks,
Roy
> Cheers
> ---Dave
>
>> + ---help---
>> + This kernel feature allows a zImage to be loaded directly
>> + by EFI firmware without the use of a bootloader. A PE/COFF
>> + header is added to the zImage in a way that makes the binary
>> + both a Linux zImage and an PE/COFF executable that can be
>> + executed directly by EFI firmware.
>> + See Documentation/efi-stub.txt for more information.
>> +
>> config SECCOMP
>> bool
>> prompt "Enable seccomp to safely compute untrusted bytecode"
>> --
>> 1.7.10.4
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, Aug 9, 2013 at 4:26 PM, Roy Franz <[email protected]> wrote:
>
> This patch series adds EFI stub support for the ARM architecture.
> Some code that was previously only used by x86/x86_64 is now shared
> and has been made more general. The stub for ARM is implemented in
> a similar manner to x86 in that it is a shim layer between EFI and
> the normal zImage/bzImage boot process, and that an image with the
> stub configured is bootable as both a zImage and EFI application.
>
> This patch now (new for v3) series depends on the
> "arm: Add [U]EFI runtime services support" patches by [email protected].
> The Kconfig option now depends on the "CONFIG_EFI" option that his series
> adds, and this option will ensure a little endian configuration. Also, the
> EFI support is used to handle the EFI memory map the stub passes to the kernel.
> There are some minor changes to be coordinated with the EFI runtime services
> patch series, so I have put this back to RFC status. These changes should be
> minor and relate to final device tree bindings.
>
> Changes since v2:
> * EFI bugfix "correct call to free_pages" that patch series
> depends on now in mainline
> * remove "-fno-stack-protector" from decompressor Makefile. The current code doesn't
> trigger the stack protection, so the decompressor now compiles with it still
> on. Note that there has never been any stack protection in the decompressor
> since the stack usage doesn't trigger the heuristic in GCC, so right now
> the "-fno-stack-protector" is a noop.
> * Changed EFI command line handling to not have a fixed limit.
> * Change FDT memory allocation to retry with a larger allocation if
> first educated guess is inadequate.
> * Correctly set 'SizeOfCode' in PE/COFF header.
> * Reviewed ".setup" section that is in x86 PE/COFF header. This is used for x86
> to account for code that is not in the .text section. We don't need this
> for ARM, as all of our code is in the .text section, or in the PE/COFF header
> itself.
> * Moved EFI_STUB_ERROR #define to header file to share between stub C and ASM.
> * Variety of cleanups and fixes in head.S.
> * Changed update_fdt_and_exit_boot() to just update the device tree, and
> renamed appropriately. Memory allocations moved out of this function as
> well, which enables the retries if the initial FDT size is too small.
> Note that in order to do the retried allocations, the original FDT and
> command line memory regions are left allocated. This is OK since the kernel
> has the memory map and will free these allocations along with the initrd
> and new fdt allocations.
> * Added prefix to all prints, reduced number of prints, and reviewed all
> messages.
> * Change mixed usage of dtb/fdt to all be fdt or "device tree" in efi-stub.c
> * remove unnecessary zimage_size variable from relocate_kernel()
> * correct return types on EFI functions - should be efi_status_t, not int.
>
>
>
> Changes since V1:
> * Updated head.S based on feedback from Dave Martin. ARM/THUMB
> switches now much cleaner.
> * Broke up changes to x86 and common code into more patches.
> 10 more patches in this series.
>
> Roy Franz (16):
> Move common EFI stub code from x86 arch code to common location
> Add system pointer argument to shared EFI stub related functions
> so they no longer use global system table pointer as they did
> when part of eboot.c. This code is now shared, so using a
> global variable as part of the interface is not that nice.
> Also, by avoiding any global variables in the ARM EFI stub,
> this allows the code to be position independent without
> requiring GOT fixups.
> Rename memory allocation/free functions
> Add minimum address parameter to efi_low_alloc()
> rename __get_map() to efi_get_memory_map(), add parameter to
> optionally return mmap key. The mmap key is required to exit
> EFI boot services, and allows efi_get_memory_map() to be used
> for getting final memory map.
> 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.
> Allow efi_free() to be called with size of 0, and do nothing in that
> case.
> Generalize handle_ramdisks() and rename to handle_cmdline_files().
> Renames in handle_cmdline_files() to complete generalization.
> Move EFI_READ_CHUNK_SIZE define to shared location.
> Add proper definitions for some EFI function pointers.
> Fix types in EFI calls to match EFI function definitions.
> resolve warnings found on ARM compile
> Add strstr to compressed string.c for ARM.
> Add EFI stub for ARM
> Add config EFI_STUB for ARM to Kconfig
>
> arch/arm/Kconfig | 11 +
> arch/arm/boot/compressed/Makefile | 15 +-
> arch/arm/boot/compressed/efi-header.S | 111 +++++++
> arch/arm/boot/compressed/efi-stub.c | 448 ++++++++++++++++++++++++++++
> arch/arm/boot/compressed/efi-stub.h | 5 +
> arch/arm/boot/compressed/head.S | 90 +++++-
> arch/arm/boot/compressed/string.c | 21 ++
> arch/x86/boot/compressed/eboot.c | 490 ++-----------------------------
> arch/x86/boot/compressed/eboot.h | 9 -
> drivers/firmware/efi/efi-stub-helper.c | 505 ++++++++++++++++++++++++++++++++
> include/linux/efi.h | 51 +++-
> 11 files changed, 1263 insertions(+), 493 deletions(-)
> create mode 100644 arch/arm/boot/compressed/efi-header.S
> create mode 100644 arch/arm/boot/compressed/efi-stub.c
> create mode 100644 arch/arm/boot/compressed/efi-stub.h
> create mode 100644 drivers/firmware/efi/efi-stub-helper.c
>
> --
> 1.7.10.4
>
Hi Matt,
Do you have any more feedback on the X86 and common code (patches
1-13) that needs to be addressed? Mark Salter has a working ARM64 EFI
stub implemented based on these patches, so the common code has now
been tested with another architecture, and he has acked these patches.
If the current patches are OK, can this be queued for 3.12? (and into
linux-next, if appropriate)
The ARM portion may take a little longer based on the EFI runtime
services patch dependencies, but getting the common code merged would
allow the ARM64 EFI stub work to go forward independently.
I can resend patches 1-13 as a new series of x86/common only changes
if you would like.
Thanks,
Roy
On Tue, Aug 13, 2013 at 6:44 PM, Roy Franz <[email protected]> wrote:
>
> Thanks Dave - comments inline, and I have an updated head.S diff at the end.
>
> Roy
>
>
> On Tue, Aug 13, 2013 at 7:19 AM, Dave Martin <[email protected]> wrote:
>>
>> On Fri, Aug 09, 2013 at 04:26:16PM -0700, Roy Franz wrote:
>> > This patch adds EFI stub support for the ARM Linux kernel. The EFI stub
>> > operations similarly to the x86 stub: it is a shim between the EFI
>> > firmware
>> > and the normal zImage entry point, and sets up the environment that the
>> > zImage is expecting. This includes loading the initrd (optionaly) and
>> > device tree from the system partition based on the kernel command line.
>> > The stub updates the device tree as necessary, including adding reserved
>> > memory regions and adding entries for EFI runtime services. The PE/COFF
>> > "MZ" header at offset 0 results in the first instruction being an add
>> > that corrupts r5, which is not used by the zImage interface.
>>
>> Thanks for the update -- a few more comments, nothing major.
>>
>> > Signed-off-by: Roy Franz <[email protected]>
>> > ---
>> > arch/arm/boot/compressed/Makefile | 15 +-
>> > arch/arm/boot/compressed/efi-header.S | 111 ++++++++
>
> ...
>>
>>
>> > + goto fdt_set_fail;
>> > +
>> > + return EFI_SUCCESS;
>>
>> This looks better.
>>
>> > +
>> > +fdt_set_fail:
>> > + if (status == -FDT_ERR_NOSPACE)
>> > + return EFI_BUFFER_TOO_SMALL;
>> > +
>> > + return EFI_LOAD_ERROR;
>> > +}
>> > +
>> > +
>> > +
>>
>> Maybe add a comment to indicate that this returns the address of the
>> relocated fdt, or EFI_LOAD_ERROR.
>>
>> By default "int" feels more likely to return a status code.
>>
>> It is not common to return pointers using the "int" type: it may be
>> preferable to use unsigned long of void * instead. This won't
>> change the functionality.
>>
>> Casts to (int) which could overflow the signed range can cause GCC
>> to generate bizarre code in some situations, because C doesn't
>> have to guarantee wrapping when casting to signed types. Since we
>> just pass that value through without doing any arithmetic I think we're
>> unlikely to hit that here, but it's best avoided anyhow.
>
>
> The function now returns only status, not the FDT address, so I have changed
> it to an int.
> When I changed the function to no longer do the memory allocation for the
> new FDT this changed,
> but I missed changing the return type to int.
>
>
>>
>>
>> > +int efi_entry(void *handle, efi_system_table_t *sys_table,
>> > + unsigned long *zimage_addr)
>> > +{
>> > + efi_loaded_image_t *image;
>> > + int status;
>> > + unsigned long nr_pages;
>> > + const struct fdt_region *region;
>> > +
>> > + void *fdt;
>> > + int err;
>> > + int node;
>> > + unsigned long zimage_size = 0;
>> > + unsigned long dram_base;
>> > + /* addr/point and size pairs for memory management*/
>> > + u64 initrd_addr;
>> > + u64 initrd_size = 0;
>> > + u64 fdt_addr;
>> > + u64 fdt_size = 0;
>> > + u64 kernel_reserve_addr;
>> > + u64 kernel_reserve_size = 0;
>> > + char *cmdline_ptr;
>> > + unsigned long cmdline_size = 0;
>> > +
>> > + unsigned long map_size, desc_size;
>> > + unsigned long mmap_key;
>> > + efi_memory_desc_t *memory_map;
>> > +
>> > + unsigned long new_fdt_size;
>> > + unsigned long new_fdt_addr;
>> > +
>> > + efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
>> > +
>> > + /* Check if we were booted by the EFI firmware */
>> > + if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
>> > + goto fail;
>> > +
>> > + efi_printk(sys_table, PRINTK_PREFIX"Booting Linux using EFI
>> > stub.\n");
>> > +
>> > +
>> > + /* get the command line from EFI, using the LOADED_IMAGE protocol
>> > */
>> > + status = efi_call_phys3(sys_table->boottime->handle_protocol,
>> > + handle, &proto, (void *)&image);
>> > + if (status != EFI_SUCCESS) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to get
>> > handle for LOADED_IMAGE_PROTOCOL\n");
>> > + goto fail;
>> > + }
>> > +
>> > + /* We are going to copy this into device tree, so we don't care
>> > where in
>> > + * memory it is.
>> > + */
>> > + cmdline_ptr = convert_cmdline_to_ascii(sys_table, image,
>> > + &cmdline_size, 0xFFFFFFFF);
>> > + if (!cmdline_ptr) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: converting
>> > command line to ascii failed.\n");
>>
>> The real reason for this failure is failure to allocate memory: there's
>> no other way it can fail.
>>
>> So, the error message could be "Unable to allocate memory for command
>> line"
>
>
> done.
>>
>>
>> > + goto fail;
>> > + }
>> > +
>> > + /* We first load the device tree, as we need to get the base
>> > address of
>> > + * DRAM from the device tree. The zImage, device tree, and initrd
>> > + * have address restrictions that are relative to the base of
>> > DRAM.
>> > + */
>> > + status = handle_cmdline_files(sys_table, image, cmdline_ptr,
>> > "dtb=",
>> > + 0xffffffff, &fdt_addr, &fdt_size);
>> > + if (status != EFI_SUCCESS) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load
>> > device tree blob.\n");
>> > + goto fail_free_cmdline;
>> > + }
>> > +
>> > + err = fdt_check_header((void *)(unsigned long)fdt_addr);
>> > + if (err != 0) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: device tree
>> > header not valid\n");
>> > + goto fail_free_fdt;
>> > + }
>> > + if (fdt_totalsize((void *)(unsigned long)fdt_addr) > fdt_size) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Incomplete
>> > device tree.\n");
>> > + goto fail_free_fdt;
>> > +
>> > + }
>> > +
>> > +
>> > + /* Look up the base of DRAM from the device tree.*/
>> > + fdt = (void *)(u32)fdt_addr;
>> > + node = fdt_subnode_offset(fdt, 0, "memory");
>> > + region = fdt_getprop(fdt, node, "reg", NULL);
>> > + if (region) {
>> > + dram_base = fdt64_to_cpu(region->base);
>> > + } else {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: no 'memory'
>> > node in device tree.\n");
>> > + goto fail_free_fdt;
>> > + }
>> > +
>> > + /* Reserve memory for the uncompressed kernel image. */
>> > + kernel_reserve_addr = dram_base;
>> > + kernel_reserve_size = MAX_UNCOMP_KERNEL_SIZE;
>> > + nr_pages = round_up(kernel_reserve_size, EFI_PAGE_SIZE) /
>> > EFI_PAGE_SIZE;
>> > + status = efi_call_phys4(sys_table->boottime->allocate_pages,
>> > + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
>> > + nr_pages, &kernel_reserve_addr);
>> > + if (status != EFI_SUCCESS) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: unable to
>> > allocate memory for uncompressed kernel.\n");
>> > + goto fail_free_fdt;
>> > + }
>> > +
>> > + /* Relocate the zImage, if required. */
>> > + zimage_size = image->image_size;
>> > + status = relocate_kernel(sys_table, zimage_addr, zimage_size,
>> > + dram_base + MIN_ZIMAGE_OFFSET,
>> > + dram_base + ZIMAGE_OFFSET_LIMIT);
>> > + if (status != EFI_SUCCESS) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to
>> > relocate kernel\n");
>> > + goto fail_free_kernel_reserve;
>> > + }
>> > +
>> > + status = handle_cmdline_files(sys_table, image, cmdline_ptr,
>> > "initrd=",
>> > + dram_base + ZIMAGE_OFFSET_LIMIT,
>> > + &initrd_addr, &initrd_size);
>> > + if (status != EFI_SUCCESS) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load
>> > initrd\n");
>> > + goto fail_free_zimage;
>> > + }
>> > +
>> > + /* Estimate size of new FDT, and allocate memory for it. We
>> > + * will allocate a bigger buffer if this ends up being too
>> > + * small, so a rough guess is OK here.*/
>> > + new_fdt_size = fdt_size + cmdline_size + 0x200;
>> > +
>> > +fdt_alloc_retry:
>>
>> Minor stylistic thing, but looping using goto is not too readable.
>>
>> The following while loop might be a bit clearer, but I leave it
>> up to you.
>>
>> while (1) {
>>
>> > + status = efi_high_alloc(sys_table, new_fdt_size, 0, &new_fdt_addr,
>> > + dram_base + ZIMAGE_OFFSET_LIMIT);
>> > + if (status != EFI_SUCCESS) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to
>> > allocate memory for new device tree.\n");
>> > + goto fail_free_initrd;
>> > + }
>> > +
>> > + /* Now that we have done our final memory allocation (and free)
>> > + * we can get the memory map key needed
>> > + * forexit_boot_services.*/
>> > + status = efi_get_memory_map(sys_table, &memory_map, &map_size,
>> > + &desc_size, &mmap_key);
>> > + if (status != EFI_SUCCESS)
>> > + goto fail_free_new_fdt;
>> > +
>> > + status = update_fdt(sys_table,
>> > + fdt, (void *)new_fdt_addr, new_fdt_size,
>> > + cmdline_ptr,
>> > + initrd_addr, initrd_size,
>> > + memory_map, map_size, desc_size);
>>
>> if (status == EFI_SUCCESS)
>> break;
>>
>> instead of
>>
>> > +
>> > + if (status != EFI_SUCCESS) {
>>
>> then
>>
>> if (status != EFI_BUFFER_TOO_SMALL)
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to
>> > constuct new device tree.\n");
>> > + goto fail_free_initrd;
>>
>> instead of
>>
>> > + if (status == EFI_BUFFER_TOO_SMALL) {
>>
>> then
>>
>> > + /* We need to allocate more space for the new
>> > + * device tree, so free existing buffer that is
>> > + * too small. Also free memory map, as we will
>> > need
>> > + * to get new one that reflects the free/alloc we
>> > do
>> > + * on the device tree buffer. */
>> > + efi_free(sys_table, new_fdt_size, new_fdt_addr);
>> > + efi_call_phys1(sys_table->boottime->free_pool,
>> > + memory_map);
>> > + new_fdt_size += new_fdt_size/4;
>>
>> And then just loop
>> }
>>
>> instead of the rest:
>>
> I have replaced the allocation retry with a while loop as suggested.
>
>> > + goto fdt_alloc_retry;
>> > + }
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to
>> > constuct new device tree.\n");
>> > + goto fail_free_initrd;
>> > + }
>> > +
>> > + /* Now we are ready to exit_boot_services.*/
>> > + status = efi_call_phys2(sys_table->boottime->exit_boot_services,
>> > + handle, mmap_key);
>> > +
>> > + if (status != EFI_SUCCESS) {
>> > + efi_printk(sys_table, PRINTK_PREFIX"ERROR: exit boot
>> > services failed.\n");
>> > + goto fail_free_mmap;
>> > + }
>> > +
>> > +
>> > + /* Now we need to return the FDT address to the calling
>> > + * assembly to this can be used as part of normal boot.
>> > + */
>> > + return new_fdt_addr;
>> > +
>> > +fail_free_mmap:
>> > + efi_call_phys1(sys_table->boottime->free_pool, memory_map);
>> > +
>> > +fail_free_new_fdt:
>> > + efi_free(sys_table, new_fdt_size, new_fdt_addr);
>> > +
>> > +fail_free_initrd:
>> > + efi_free(sys_table, initrd_size, initrd_addr);
>> > +
>> > +fail_free_zimage:
>> > + efi_free(sys_table, zimage_size, *zimage_addr);
>> > +
>> > +fail_free_kernel_reserve:
>> > + efi_free(sys_table, kernel_reserve_addr, kernel_reserve_size);
>> > +
>> > +fail_free_fdt:
>> > + efi_free(sys_table, fdt_size, fdt_addr);
>> > +
>> > +fail_free_cmdline:
>> > + efi_free(sys_table, cmdline_size, (u32)cmdline_ptr);
>> > +
>> > +fail:
>> > + return EFI_STUB_ERROR;
>> > +}
>> > diff --git a/arch/arm/boot/compressed/efi-stub.h
>> > b/arch/arm/boot/compressed/efi-stub.h
>> > new file mode 100644
>> > index 0000000..0fe9376
>> > --- /dev/null
>> > +++ b/arch/arm/boot/compressed/efi-stub.h
>> > @@ -0,0 +1,5 @@
>> > +#ifndef _ARM_EFI_STUB_H
>> > +#define _ARM_EFI_STUB_H
>> > +/* Error code returned to ASM code instead of valid FDT address. */
>> > +#define EFI_STUB_ERROR (~0)
>> > +#endif
>> > diff --git a/arch/arm/boot/compressed/head.S
>> > b/arch/arm/boot/compressed/head.S
>> > index 75189f1..5401a3a 100644
>> > --- a/arch/arm/boot/compressed/head.S
>> > +++ b/arch/arm/boot/compressed/head.S
>> > @@ -10,6 +10,7 @@
>> > */
>> > #include <linux/linkage.h>
>> > #include <asm/assembler.h>
>> > +#include "efi-stub.h"
>> >
>> > .arch armv7-a
>> > /*
>> > @@ -120,21 +121,99 @@
>> > */
>> > .align
>> > .arm @ Always enter in ARM
>> > state
>> > + .text
>> > start:
>> > .type start,#function
>> > - .rept 7
>> > +#ifdef CONFIG_EFI_STUB
>> > + @ Magic MSDOS signature for PE/COFF + ADD opcode
>> > + .word 0x62805a4d
>> > +#else
>> > + mov r0, r0
>> > +#endif
>> > + .rept 5
>> > mov r0, r0
>> > .endr
>> > - ARM( mov r0, r0 )
>> > - ARM( b 1f )
>> > - THUMB( adr r12, BSYM(1f) )
>> > - THUMB( bx r12 )
>> > +
>> > + adrl r12, BSYM(zimage_continue)
>> > + ARM( mov pc, r12 )
>> > + THUMB( bx r12 )
>> > + @ zimage_continue will be in ARM or thumb mode as
>> > configured
>> >
>> > .word 0x016f2818 @ Magic numbers to help
>> > the loader
>> > .word start @ absolute load/run zImage
>> > address
>> > .word _edata @ zImage end address
>> > +
>> > +#ifdef CONFIG_EFI_STUB
>> > + @ Portions of the MSDOS file header must be at offset
>> > + @ 0x3c from the start of the file. All PE/COFF headers
>> > + @ are kept contiguous for simplicity.
>> > +#include "efi-header.S"
>> > +
>> > +efi_stub_entry:
>> > + @ The EFI stub entry point is not at a fixed address,
>> > however
>> > + @ this address must be set in the PE/COFF header.
>> > + @ EFI entry point is in A32 mode, switch to T32 if
>> > configured.
>> > + THUMB( adr r12, BSYM(1f) )
>> > + THUMB( bx r12 )
>> > THUMB( .thumb )
>> > 1:
>> > + @ Save lr on stack for possible return to EFI firmware.
>> > + @ Don't care about fp, but need 64 bit alignment....
>> > + stmfd sp!, {fp, lr}
>> > +
>> > + @ allocate space on stack for return of new entry point of
>> > + @ zImage, as EFI stub may copy the kernel. Pass address
>> > + @ of space in r2 - EFI stub will fill in the pointer.
>> > +
>> > + sub sp, sp, #8 @ we only need 4 bytes,
>> > + @ but keep stack 8 byte
>> > aligned.
>> > + mov r2, sp
>>
>> You can save an instruction here: skip these two instructions, and see
>> below just before the call to efi_entry [1]
>>
>> > + @ Pass our actual runtime start address in pointer data
>> > + adr r11, LC0 @ address of LC0 at run
>> > time
>> > + ldr r12, [r11, #0] @ address of LC0 at link
>> > time
>>
>> Can we just move this delta calculation after efi_entry?
>>
>> You don't need to specifiy an explicit offset if it's zero, btw:
>>
>> ldr r12, [r11]
>>
>> works just as well. Same for the other instances.
>
>
> So after looking at this it was pretty messed up. The LC0 business was to
> compute the
> linktime/runtime offset, which I had used to lookup the uncompressed kernel
> size.
> That ended up not being useful, but this code stayed around. I've reworked
> this
> section of code to remove that cruft and incorporate your suggestions.
>
> I've put an updated diff of just head.S at the end of the email.
>
>>
>> > +
>> > + sub r3, r11, r12 @ calculate the delta
>> > offset
>> > + str r3, [r2, #0]
>>
>> I think r2 is still equal to sp, so
>>
>> str r3, [sp]
>>
>> should be OK.
>>
>> [1]Or, combine this with the modification of sp:
>>
>> str r3, [sp, #-8]!
>> mov r2, sp
>>
>> > + bl efi_entry
>> > +
>> > + @ get new zImage entry address from stack, put into r3
>> > + ldr r3, [sp, #0]
>> > + add sp, sp, #8 @ restore stack
>>
>> ldr r3, [sp], #8
>>
>> > +
>> > + @ Check for error return from EFI stub
>> > + mov r1, #EFI_STUB_ERROR
>> > + cmp r0, r1
>>
>> cmp r0, #EFI_STUB_ERROR
>>
>> probably works. The assembler will turn this into a cmn as necessary.
>>
>> > + beq efi_load_fail
>> > +
>> > +
>> > + @ Save return values of efi_entry
>> > + stmfd sp!, {r0, r3}
>> > + bl cache_clean_flush
>> > + bl cache_off
>> > + ldmfd sp!, {r0, r3}
>> > +
>> > + @ Set parameters for booting zImage according to boot
>> > protocol
>> > + @ put FDT address in r2, it was returned by efi_entry()
>> > + @ r1 is FDT machine type, and r0 needs to be 0
>> > + mov r2, r0
>> > + mov r1, #0xFFFFFFFF
>> > + mov r0, #0
>> > +
>> > + @ Branch to (possibly) relocated zImage that is in r3
>> > + @ Make sure we are in A32 mode, as zImage requires
>> > + THUMB( bx r3 )
>> > + ARM( mov pc, r3 )
>> > +
>> > +efi_load_fail:
>> > + @ Return EFI_LOAD_ERROR to EFI firmware on error.
>> > + @ Switch back to ARM mode for EFI is done based on
>> > + @ return address on stack
>> > + ldr r0, =0x80000001
>> > + ldmfd sp!, {fp, pc}
>> > +#endif
>> > +
>> > + THUMB( .thumb )
>> > +zimage_continue:
>> > mrs r9, cpsr
>> > #ifdef CONFIG_ARM_VIRT_EXT
>> > bl __hyp_stub_install @ get into SVC mode,
>> > reversibly
>> > @@ -167,7 +246,6 @@ not_angel:
>> > * by the linker here, but it should preserve r7, r8, and
>> > r9.
>> > */
>> >
>> > - .text
>> >
>> > #ifdef CONFIG_AUTO_ZRELADDR
>> > @ determine final kernel image address
>> > --
>> > 1.7.10.4
>> >
>> >
>> > _______________________________________________
>> > linux-arm-kernel mailing list
>> > [email protected]
>> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>
> diff --git a/arch/arm/boot/compressed/head.S
> b/arch/arm/boot/compressed/head.S
> index 75189f1..820a238 100644
> --- a/arch/arm/boot/compressed/head.S
> +++ b/arch/arm/boot/compressed/head.S
> @@ -10,6 +10,7 @@
> */
> #include <linux/linkage.h>
> #include <asm/assembler.h>
> +#include "efi-stub.h"
>
> .arch armv7-a
> /*
> @@ -120,21 +121,92 @@
> */
> .align
> .arm @ Always enter in ARM state
> + .text
> start:
> .type start,#function
> - .rept 7
> +#ifdef CONFIG_EFI_STUB
> + @ Magic MSDOS signature for PE/COFF + ADD opcode
> + @ the EFI stub only supports little endian, as the EFI functions
> + @ it invokes are little endian.
> + .word 0x62805a4d
> +#else
> + mov r0, r0
> +#endif
> + .rept 5
> mov r0, r0
> .endr
> - ARM( mov r0, r0 )
> - ARM( b 1f )
> - THUMB( adr r12, BSYM(1f) )
> - THUMB( bx r12 )
> +
> + adrl r12, BSYM(zimage_continue)
> + ARM( mov pc, r12 )
> + THUMB( bx r12 )
> + @ zimage_continue will be in ARM or thumb mode as configured
>
> .word 0x016f2818 @ Magic numbers to help the loader
> .word start @ absolute load/run zImage address
> .word _edata @ zImage end address
> +
> +#ifdef CONFIG_EFI_STUB
> + @ Portions of the MSDOS file header must be at offset
> + @ 0x3c from the start of the file. All PE/COFF headers
> + @ are kept contiguous for simplicity.
> +#include "efi-header.S"
> +
> +efi_stub_entry:
> + @ The EFI stub entry point is not at a fixed address, however
> + @ this address must be set in the PE/COFF header.
> + @ EFI entry point is in A32 mode, switch to T32 if configured.
> + THUMB( adr r12, BSYM(1f) )
> + THUMB( bx r12 )
> THUMB( .thumb )
> 1:
> + @ Save lr on stack for possible return to EFI firmware.
> + @ Don't care about fp, but need 64 bit alignment....
> + stmfd sp!, {fp, lr}
> +
> + @ allocate space on stack for passing current zImage address
> + @ and for the EFI stub to return of new entry point of
> + @ zImage, as EFI stub may copy the kernel. Pointer address
> + @ is passed in r2. r0 and r1 are passed through from the
> + @ EFI firmware to efi_entry
> + adr r3, start
> + str r3, [sp, #8]!
above line should be:
str r3, [sp, #-8]!
that - sign is really hard to see in gmail :)
> + mov r2, sp @ pass pointer in r2
> + bl efi_entry
> + ldr r3, [sp], #8 @ get new zImage address from stack
> +
> + @ Check for error return from EFI stub. r0 has FDT address
> + @ or EFI_STUB_ERROR error code.
> + cmp r0, #EFI_STUB_ERROR
> + beq efi_load_fail
> +
> + @ Save return values of efi_entry
> + stmfd sp!, {r0, r3}
> + bl cache_clean_flush
> + bl cache_off
> + ldmfd sp!, {r0, r3}
> +
> + @ Set parameters for booting zImage according to boot protocol
> + @ put FDT address in r2, it was returned by efi_entry()
> + @ r1 is FDT machine type, and r0 needs to be 0
> + mov r2, r0
> + mov r1, #0xFFFFFFFF
> + mov r0, #0
> +
> + @ Branch to (possibly) relocated zImage that is in r3
> + @ Make sure we are in A32 mode, as zImage requires
> + THUMB( bx r3 )
> + ARM( mov pc, r3 )
> +
> +efi_load_fail:
> + @ Return EFI_LOAD_ERROR to EFI firmware on error.
> + @ Switch back to ARM mode for EFI is done based on
> + @ return address on stack in case we are in THUMB mode
> + ldr r0, =0x80000001
> + ldmfd sp!, {fp, pc} @ put lr from stack into pc
> +#endif
> +
> + THUMB( .thumb )
> +zimage_continue:
> mrs r9, cpsr
> #ifdef CONFIG_ARM_VIRT_EXT
> bl __hyp_stub_install @ get into SVC mode, reversibly
> @@ -167,7 +239,6 @@ not_angel:
> * by the linker here, but it should preserve r7, r8, and r9.
> */
>
> - .text
>
> #ifdef CONFIG_AUTO_ZRELADDR
> @ determine final kernel image address
>
On Tue, Aug 13, 2013 at 10:58 AM, Roy Franz <[email protected]> wrote:
> On Fri, Aug 9, 2013 at 4:26 PM, Roy Franz <[email protected]> wrote:
>>
>> This patch series adds EFI stub support for the ARM architecture.
>> Some code that was previously only used by x86/x86_64 is now shared
>> and has been made more general. The stub for ARM is implemented in
>> a similar manner to x86 in that it is a shim layer between EFI and
>> the normal zImage/bzImage boot process, and that an image with the
>> stub configured is bootable as both a zImage and EFI application.
>>
>> This patch now (new for v3) series depends on the
>> "arm: Add [U]EFI runtime services support" patches by [email protected].
>> The Kconfig option now depends on the "CONFIG_EFI" option that his series
>> adds, and this option will ensure a little endian configuration. Also, the
>> EFI support is used to handle the EFI memory map the stub passes to the kernel.
>> There are some minor changes to be coordinated with the EFI runtime services
>> patch series, so I have put this back to RFC status. These changes should be
>> minor and relate to final device tree bindings.
>>
>> Changes since v2:
>> * EFI bugfix "correct call to free_pages" that patch series
>> depends on now in mainline
>> * remove "-fno-stack-protector" from decompressor Makefile. The current code doesn't
>> trigger the stack protection, so the decompressor now compiles with it still
>> on. Note that there has never been any stack protection in the decompressor
>> since the stack usage doesn't trigger the heuristic in GCC, so right now
>> the "-fno-stack-protector" is a noop.
>> * Changed EFI command line handling to not have a fixed limit.
>> * Change FDT memory allocation to retry with a larger allocation if
>> first educated guess is inadequate.
>> * Correctly set 'SizeOfCode' in PE/COFF header.
>> * Reviewed ".setup" section that is in x86 PE/COFF header. This is used for x86
>> to account for code that is not in the .text section. We don't need this
>> for ARM, as all of our code is in the .text section, or in the PE/COFF header
>> itself.
>> * Moved EFI_STUB_ERROR #define to header file to share between stub C and ASM.
>> * Variety of cleanups and fixes in head.S.
>> * Changed update_fdt_and_exit_boot() to just update the device tree, and
>> renamed appropriately. Memory allocations moved out of this function as
>> well, which enables the retries if the initial FDT size is too small.
>> Note that in order to do the retried allocations, the original FDT and
>> command line memory regions are left allocated. This is OK since the kernel
>> has the memory map and will free these allocations along with the initrd
>> and new fdt allocations.
>> * Added prefix to all prints, reduced number of prints, and reviewed all
>> messages.
>> * Change mixed usage of dtb/fdt to all be fdt or "device tree" in efi-stub.c
>> * remove unnecessary zimage_size variable from relocate_kernel()
>> * correct return types on EFI functions - should be efi_status_t, not int.
>>
>>
>>
>> Changes since V1:
>> * Updated head.S based on feedback from Dave Martin. ARM/THUMB
>> switches now much cleaner.
>> * Broke up changes to x86 and common code into more patches.
>> 10 more patches in this series.
>>
>> Roy Franz (16):
>> Move common EFI stub code from x86 arch code to common location
>> Add system pointer argument to shared EFI stub related functions
>> so they no longer use global system table pointer as they did
>> when part of eboot.c. This code is now shared, so using a
>> global variable as part of the interface is not that nice.
>> Also, by avoiding any global variables in the ARM EFI stub,
>> this allows the code to be position independent without
>> requiring GOT fixups.
>> Rename memory allocation/free functions
>> Add minimum address parameter to efi_low_alloc()
>> rename __get_map() to efi_get_memory_map(), add parameter to
>> optionally return mmap key. The mmap key is required to exit
>> EFI boot services, and allows efi_get_memory_map() to be used
>> for getting final memory map.
>> 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.
>> Allow efi_free() to be called with size of 0, and do nothing in that
>> case.
>> Generalize handle_ramdisks() and rename to handle_cmdline_files().
>> Renames in handle_cmdline_files() to complete generalization.
>> Move EFI_READ_CHUNK_SIZE define to shared location.
>> Add proper definitions for some EFI function pointers.
>> Fix types in EFI calls to match EFI function definitions.
>> resolve warnings found on ARM compile
>> Add strstr to compressed string.c for ARM.
>> Add EFI stub for ARM
>> Add config EFI_STUB for ARM to Kconfig
>>
>> arch/arm/Kconfig | 11 +
>> arch/arm/boot/compressed/Makefile | 15 +-
>> arch/arm/boot/compressed/efi-header.S | 111 +++++++
>> arch/arm/boot/compressed/efi-stub.c | 448 ++++++++++++++++++++++++++++
>> arch/arm/boot/compressed/efi-stub.h | 5 +
>> arch/arm/boot/compressed/head.S | 90 +++++-
>> arch/arm/boot/compressed/string.c | 21 ++
>> arch/x86/boot/compressed/eboot.c | 490 ++-----------------------------
>> arch/x86/boot/compressed/eboot.h | 9 -
>> drivers/firmware/efi/efi-stub-helper.c | 505 ++++++++++++++++++++++++++++++++
>> include/linux/efi.h | 51 +++-
>> 11 files changed, 1263 insertions(+), 493 deletions(-)
>> create mode 100644 arch/arm/boot/compressed/efi-header.S
>> create mode 100644 arch/arm/boot/compressed/efi-stub.c
>> create mode 100644 arch/arm/boot/compressed/efi-stub.h
>> create mode 100644 drivers/firmware/efi/efi-stub-helper.c
>>
>> --
>> 1.7.10.4
>>
>
> Hi Matt,
>
> Do you have any more feedback on the X86 and common code (patches
> 1-13) that needs to be addressed? Mark Salter has a working ARM64 EFI
> stub implemented based on these patches, so the common code has now
> been tested with another architecture, and he has acked these patches.
> If the current patches are OK, can this be queued for 3.12? (and into
> linux-next, if appropriate)
> The ARM portion may take a little longer based on the EFI runtime
> services patch dependencies, but getting the common code merged would
> allow the ARM64 EFI stub work to go forward independently.
>
> I can resend patches 1-13 as a new series of x86/common only changes
> if you would like.
>
> Thanks,
> Roy
Hi Matt,
Any thoughts on taking the x86/common parts for 3.12?
Thanks,
Roy
On Fri, Aug 16, 2013 at 5:16 PM, Roy Franz <[email protected]> wrote:
> On Tue, Aug 13, 2013 at 10:58 AM, Roy Franz <[email protected]> wrote:
>> On Fri, Aug 9, 2013 at 4:26 PM, Roy Franz <[email protected]> wrote:
>>>
>>> This patch series adds EFI stub support for the ARM architecture.
>>> Some code that was previously only used by x86/x86_64 is now shared
>>> and has been made more general. The stub for ARM is implemented in
>>> a similar manner to x86 in that it is a shim layer between EFI and
>>> the normal zImage/bzImage boot process, and that an image with the
>>> stub configured is bootable as both a zImage and EFI application.
>>>
>>> This patch now (new for v3) series depends on the
>>> "arm: Add [U]EFI runtime services support" patches by [email protected].
>>> The Kconfig option now depends on the "CONFIG_EFI" option that his series
>>> adds, and this option will ensure a little endian configuration. Also, the
>>> EFI support is used to handle the EFI memory map the stub passes to the kernel.
>>> There are some minor changes to be coordinated with the EFI runtime services
>>> patch series, so I have put this back to RFC status. These changes should be
>>> minor and relate to final device tree bindings.
>>>
>>> Changes since v2:
>>> * EFI bugfix "correct call to free_pages" that patch series
>>> depends on now in mainline
>>> * remove "-fno-stack-protector" from decompressor Makefile. The current code doesn't
>>> trigger the stack protection, so the decompressor now compiles with it still
>>> on. Note that there has never been any stack protection in the decompressor
>>> since the stack usage doesn't trigger the heuristic in GCC, so right now
>>> the "-fno-stack-protector" is a noop.
>>> * Changed EFI command line handling to not have a fixed limit.
>>> * Change FDT memory allocation to retry with a larger allocation if
>>> first educated guess is inadequate.
>>> * Correctly set 'SizeOfCode' in PE/COFF header.
>>> * Reviewed ".setup" section that is in x86 PE/COFF header. This is used for x86
>>> to account for code that is not in the .text section. We don't need this
>>> for ARM, as all of our code is in the .text section, or in the PE/COFF header
>>> itself.
>>> * Moved EFI_STUB_ERROR #define to header file to share between stub C and ASM.
>>> * Variety of cleanups and fixes in head.S.
>>> * Changed update_fdt_and_exit_boot() to just update the device tree, and
>>> renamed appropriately. Memory allocations moved out of this function as
>>> well, which enables the retries if the initial FDT size is too small.
>>> Note that in order to do the retried allocations, the original FDT and
>>> command line memory regions are left allocated. This is OK since the kernel
>>> has the memory map and will free these allocations along with the initrd
>>> and new fdt allocations.
>>> * Added prefix to all prints, reduced number of prints, and reviewed all
>>> messages.
>>> * Change mixed usage of dtb/fdt to all be fdt or "device tree" in efi-stub.c
>>> * remove unnecessary zimage_size variable from relocate_kernel()
>>> * correct return types on EFI functions - should be efi_status_t, not int.
>>>
>>>
>>>
>>> Changes since V1:
>>> * Updated head.S based on feedback from Dave Martin. ARM/THUMB
>>> switches now much cleaner.
>>> * Broke up changes to x86 and common code into more patches.
>>> 10 more patches in this series.
>>>
>>> Roy Franz (16):
>>> Move common EFI stub code from x86 arch code to common location
>>> Add system pointer argument to shared EFI stub related functions
>>> so they no longer use global system table pointer as they did
>>> when part of eboot.c. This code is now shared, so using a
>>> global variable as part of the interface is not that nice.
>>> Also, by avoiding any global variables in the ARM EFI stub,
>>> this allows the code to be position independent without
>>> requiring GOT fixups.
>>> Rename memory allocation/free functions
>>> Add minimum address parameter to efi_low_alloc()
>>> rename __get_map() to efi_get_memory_map(), add parameter to
>>> optionally return mmap key. The mmap key is required to exit
>>> EFI boot services, and allows efi_get_memory_map() to be used
>>> for getting final memory map.
>>> 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.
>>> Allow efi_free() to be called with size of 0, and do nothing in that
>>> case.
>>> Generalize handle_ramdisks() and rename to handle_cmdline_files().
>>> Renames in handle_cmdline_files() to complete generalization.
>>> Move EFI_READ_CHUNK_SIZE define to shared location.
>>> Add proper definitions for some EFI function pointers.
>>> Fix types in EFI calls to match EFI function definitions.
>>> resolve warnings found on ARM compile
>>> Add strstr to compressed string.c for ARM.
>>> Add EFI stub for ARM
>>> Add config EFI_STUB for ARM to Kconfig
>>>
>>> arch/arm/Kconfig | 11 +
>>> arch/arm/boot/compressed/Makefile | 15 +-
>>> arch/arm/boot/compressed/efi-header.S | 111 +++++++
>>> arch/arm/boot/compressed/efi-stub.c | 448 ++++++++++++++++++++++++++++
>>> arch/arm/boot/compressed/efi-stub.h | 5 +
>>> arch/arm/boot/compressed/head.S | 90 +++++-
>>> arch/arm/boot/compressed/string.c | 21 ++
>>> arch/x86/boot/compressed/eboot.c | 490 ++-----------------------------
>>> arch/x86/boot/compressed/eboot.h | 9 -
>>> drivers/firmware/efi/efi-stub-helper.c | 505 ++++++++++++++++++++++++++++++++
>>> include/linux/efi.h | 51 +++-
>>> 11 files changed, 1263 insertions(+), 493 deletions(-)
>>> create mode 100644 arch/arm/boot/compressed/efi-header.S
>>> create mode 100644 arch/arm/boot/compressed/efi-stub.c
>>> create mode 100644 arch/arm/boot/compressed/efi-stub.h
>>> create mode 100644 drivers/firmware/efi/efi-stub-helper.c
>>>
>>> --
>>> 1.7.10.4
>>>
>>
>> Hi Matt,
>>
>> Do you have any more feedback on the X86 and common code (patches
>> 1-13) that needs to be addressed? Mark Salter has a working ARM64 EFI
>> stub implemented based on these patches, so the common code has now
>> been tested with another architecture, and he has acked these patches.
>> If the current patches are OK, can this be queued for 3.12? (and into
>> linux-next, if appropriate)
>> The ARM portion may take a little longer based on the EFI runtime
>> services patch dependencies, but getting the common code merged would
>> allow the ARM64 EFI stub work to go forward independently.
>>
>> I can resend patches 1-13 as a new series of x86/common only changes
>> if you would like.
>>
>> Thanks,
>> Roy
>
> Hi Matt,
>
> Any thoughts on taking the x86/common parts for 3.12?
>
> Thanks,
> Roy
Hi Matt,
Do you have a tree I can monitor to see if you have taken this?
Would you like me to split out the x86/common only changes into a
separate series from the ARM changes?
Thanks,
Roy
On Tue, 13 Aug 2013 10:37:13 -0700, Roy Franz <[email protected]> wrote:
> On Tue, Aug 13, 2013 at 6:18 AM, Dave Martin <[email protected]> wrote:
> > On Fri, Aug 09, 2013 at 04:26:17PM -0700, Roy Franz wrote:
> >> Signed-off-by: Roy Franz <[email protected]>
> >> ---
> >> arch/arm/Kconfig | 11 +++++++++++
> >> 1 file changed, 11 insertions(+)
> >>
> >> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> >> index 43594d5..8607d03 100644
> >> --- a/arch/arm/Kconfig
> >> +++ b/arch/arm/Kconfig
> >> @@ -1805,6 +1805,17 @@ config UACCESS_WITH_MEMCPY
> >> However, if the CPU data cache is using a write-allocate mode,
> >> this option is unlikely to provide any performance gain.
> >>
> >> +config EFI_STUB
> >> + bool "EFI stub support"
> >> + depends on EFI
> >
> > && !CPU_BIG_ENDIAN, in case you didn't get around to that.
> >
> > Sooner or later, someone may try to fix that, so there should be a
> > comment somewhere explaining what is broken for BE.
> >
> > Either in efi-stub.c or in the commit message accompanying this patch, I
> > guess.
> >
> EFI will be !CPU_BIG_ENDIAN, so we will get the dependency
> transitively through EFI.
> That said, I think it may be better to have both be explicitly
> !CPU_BIG_ENDIAN, as even
> though the underlying reasons are the same (EFI services calls being
> little endian), both
> the stub and runtime services would need to be fixed to enable the
> stub to run in BE mode.
> I'll make this explicit in the stub Kconfig, and add a comment by the
> PE/COFF magic number
> regarding the LE requirement.
Actually, not true! Steve McIntyre is currently doing some of the BE
porting work on TC2 running UEFI. Eventually he will need this.
g.
On Tue, 13 Aug 2013 09:56:20 -0400, Mark Salter <[email protected]> wrote:
> On Fri, 2013-08-09 at 16:26 -0700, Roy Franz wrote:
> > No code changes made, just moving functions 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 <[email protected]>
> > ---
>
> Tested on arm64.
>
> Acked-by: Mark Salter <[email protected]>
Looks okay to me. I'm not a big fan of #including .c files, but I'm okay
with it as-is for the time being. It can be revisited later to
investigate a clean way to compile these functions as a separate .o file.
Reviewed-by: Grant Likely <[email protected]>
g.
On Fri, 9 Aug 2013 16:26:03 -0700, Roy Franz <[email protected]> wrote:
> Signed-off-by: Roy Franz <[email protected]>
The entire commit message is contained in the subject line! The first
line of a commit message needs to be a short summary, followed by a
blank line, followed by the full description. Commit text body should be
wrapped at column 72 so it looks nice in 'git log'
>From your commit message:
> Subject: Re: [PATCH 02/16] Add system pointer argument to shared EFI
> stub related functions so they no longer use global system table
> pointer as they did when part of eboot.c. This code is now shared, so
> using a global variable as part of the interface is not that nice.
> Also, by avoiding any global variables in the ARM EFI stub, this
> allows the code to be position independent without requiring GOT
> fixups.
The argument about avoiding GOT fixups is stronger than the global
variables comment. I don't see a problem at all with using a global
context pointer since this code will only ever run within the context of
the EFI environment where there must always be a system table pointer.
It isn't as if there will ever be multiple system tables.
How much of a concern are GOT fixups at this stage? I thought GOT fixups
were a solved problem for the EFI stub.
g.
> ---
> arch/x86/boot/compressed/eboot.c | 38 +++++++------
> drivers/firmware/efi/efi-stub-helper.c | 96 +++++++++++++++++---------------
> 2 files changed, 72 insertions(+), 62 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
> index ab0eefc..65b6a34 100644
> --- a/arch/x86/boot/compressed/eboot.c
> +++ b/arch/x86/boot/compressed/eboot.c
> @@ -453,13 +453,13 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
> status = efi_call_phys3(sys_table->boottime->handle_protocol,
> handle, &proto, (void *)&image);
> if (status != EFI_SUCCESS) {
> - efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
> + efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
> return NULL;
> }
>
> - status = low_alloc(0x4000, 1, (unsigned long *)&boot_params);
> + status = low_alloc(sys_table, 0x4000, 1, (unsigned long *)&boot_params);
> if (status != EFI_SUCCESS) {
> - efi_printk("Failed to alloc lowmem for boot params\n");
> + efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
> return NULL;
> }
>
> @@ -503,9 +503,10 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
>
> options_size++; /* NUL termination */
>
> - status = low_alloc(options_size, 1, &cmdline);
> + status = low_alloc(sys_table, options_size, 1,
> + &cmdline);
> if (status != EFI_SUCCESS) {
> - efi_printk("Failed to alloc mem for cmdline\n");
> + efi_printk(sys_table, "Failed to alloc mem for cmdline\n");
> goto fail;
> }
>
> @@ -529,16 +530,16 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
>
> memset(sdt, 0, sizeof(*sdt));
>
> - status = handle_ramdisks(image, hdr);
> + status = handle_ramdisks(sys_table, image, hdr);
> if (status != EFI_SUCCESS)
> goto fail2;
>
> return boot_params;
> fail2:
> if (options_size)
> - low_free(options_size, hdr->cmd_line_ptr);
> + low_free(sys_table, options_size, hdr->cmd_line_ptr);
> fail:
> - low_free(0x4000, (unsigned long)boot_params);
> + low_free(sys_table, 0x4000, (unsigned long)boot_params);
> return NULL;
> }
>
> @@ -561,7 +562,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
> again:
> size += sizeof(*mem_map) * 2;
> _size = size;
> - status = low_alloc(size, 1, (unsigned long *)&mem_map);
> + status = low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
> if (status != EFI_SUCCESS)
> return status;
>
> @@ -569,7 +570,7 @@ get_map:
> status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
> mem_map, &key, &desc_size, &desc_version);
> if (status == EFI_BUFFER_TOO_SMALL) {
> - low_free(_size, (unsigned long)mem_map);
> + low_free(sys_table, _size, (unsigned long)mem_map);
> goto again;
> }
>
> @@ -671,7 +672,7 @@ get_map:
> return EFI_SUCCESS;
>
> free_mem_map:
> - low_free(_size, (unsigned long)mem_map);
> + low_free(sys_table, _size, (unsigned long)mem_map);
> return status;
> }
>
> @@ -694,10 +695,10 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)
> EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
> nr_pages, &start);
> if (status != EFI_SUCCESS) {
> - status = low_alloc(hdr->init_size, hdr->kernel_alignment,
> - &start);
> + status = low_alloc(sys_table, hdr->init_size,
> + hdr->kernel_alignment, &start);
> if (status != EFI_SUCCESS)
> - efi_printk("Failed to alloc mem for kernel\n");
> + efi_printk(sys_table, "Failed to alloc mem for kernel\n");
> }
>
> if (status == EFI_SUCCESS)
> @@ -737,14 +738,15 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
> EFI_LOADER_DATA, sizeof(*gdt),
> (void **)&gdt);
> if (status != EFI_SUCCESS) {
> - efi_printk("Failed to alloc mem for gdt structure\n");
> + efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
> goto fail;
> }
>
> gdt->size = 0x800;
> - status = low_alloc(gdt->size, 8, (unsigned long *)&gdt->address);
> + status = low_alloc(sys_table, gdt->size, 8,
> + (unsigned long *)&gdt->address);
> if (status != EFI_SUCCESS) {
> - efi_printk("Failed to alloc mem for gdt\n");
> + efi_printk(sys_table, "Failed to alloc mem for gdt\n");
> goto fail;
> }
>
> @@ -752,7 +754,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
> EFI_LOADER_DATA, sizeof(*idt),
> (void **)&idt);
> if (status != EFI_SUCCESS) {
> - efi_printk("Failed to alloc mem for idt structure\n");
> + efi_printk(sys_table, "Failed to alloc mem for idt structure\n");
> goto fail;
> }
>
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index 47891bd..bd6c1a2 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;
> --
> 1.7.10.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, 9 Aug 2013 16:26:04 -0700, Roy Franz <[email protected]> wrote:
> 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 <[email protected]>
> ---
Looks reasonable.
Reviewed-by: Grant Likely <[email protected]>
> arch/x86/boot/compressed/eboot.c | 19 ++++++++++---------
> drivers/firmware/efi/efi-stub-helper.c | 14 +++++++-------
> 2 files changed, 17 insertions(+), 16 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
> index 65b6a34..2a4430a 100644
> --- a/arch/x86/boot/compressed/eboot.c
> +++ b/arch/x86/boot/compressed/eboot.c
> @@ -457,7 +457,8 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
> return NULL;
> }
>
> - status = low_alloc(sys_table, 0x4000, 1, (unsigned long *)&boot_params);
> + status = efi_low_alloc(sys_table, 0x4000, 1,
> + (unsigned long *)&boot_params);
> if (status != EFI_SUCCESS) {
> efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
> return NULL;
> @@ -503,7 +504,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
>
> options_size++; /* NUL termination */
>
> - status = low_alloc(sys_table, options_size, 1,
> + status = efi_low_alloc(sys_table, options_size, 1,
> &cmdline);
> if (status != EFI_SUCCESS) {
> efi_printk(sys_table, "Failed to alloc mem for cmdline\n");
> @@ -537,9 +538,9 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
> return boot_params;
> fail2:
> if (options_size)
> - low_free(sys_table, options_size, hdr->cmd_line_ptr);
> + efi_free(sys_table, options_size, hdr->cmd_line_ptr);
> fail:
> - low_free(sys_table, 0x4000, (unsigned long)boot_params);
> + efi_free(sys_table, 0x4000, (unsigned long)boot_params);
> return NULL;
> }
>
> @@ -562,7 +563,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
> again:
> size += sizeof(*mem_map) * 2;
> _size = size;
> - status = low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
> + status = efi_low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
> if (status != EFI_SUCCESS)
> return status;
>
> @@ -570,7 +571,7 @@ get_map:
> status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
> mem_map, &key, &desc_size, &desc_version);
> if (status == EFI_BUFFER_TOO_SMALL) {
> - low_free(sys_table, _size, (unsigned long)mem_map);
> + efi_free(sys_table, _size, (unsigned long)mem_map);
> goto again;
> }
>
> @@ -672,7 +673,7 @@ get_map:
> return EFI_SUCCESS;
>
> free_mem_map:
> - low_free(sys_table, _size, (unsigned long)mem_map);
> + efi_free(sys_table, _size, (unsigned long)mem_map);
> return status;
> }
>
> @@ -695,7 +696,7 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)
> EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
> nr_pages, &start);
> if (status != EFI_SUCCESS) {
> - status = low_alloc(sys_table, hdr->init_size,
> + 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");
> @@ -743,7 +744,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
> }
>
> gdt->size = 0x800;
> - status = low_alloc(sys_table, gdt->size, 8,
> + status = efi_low_alloc(sys_table, gdt->size, 8,
> (unsigned long *)&gdt->address);
> if (status != EFI_SUCCESS) {
> efi_printk(sys_table, "Failed to alloc mem for gdt\n");
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index bd6c1a2..0218d535 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++)
> --
> 1.7.10.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, 9 Aug 2013 16:26:05 -0700, Roy Franz <[email protected]> wrote:
> This allows allocations to be made low in memory while
> avoiding allocations at the base of memory.
Your commit message should include /why/ the change is needed. From the
above I understand what the patch does, but I don't understand why it is
necessary.
The patch looks fine to me, but it would be worth investigating merging
alloc_low and alloc_high. It looks like they both do pretty close to the
same calculations. A single core function could do both, could have both
minimum and maximum constraints, and could have a flag to determine if
low or high addresses should be preferred.
g.
Reviewed-by: Grant Likely <[email protected]>
>
> Signed-off-by: Roy Franz <[email protected]>
> ---
> arch/x86/boot/compressed/eboot.c | 11 ++++++-----
> drivers/firmware/efi/efi-stub-helper.c | 7 +++++--
> 2 files changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
> index 2a4430a..f44ef2f 100644
> --- a/arch/x86/boot/compressed/eboot.c
> +++ b/arch/x86/boot/compressed/eboot.c
> @@ -458,7 +458,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
> }
>
> status = efi_low_alloc(sys_table, 0x4000, 1,
> - (unsigned long *)&boot_params);
> + (unsigned long *)&boot_params, 0);
> if (status != EFI_SUCCESS) {
> efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
> return NULL;
> @@ -505,7 +505,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
> options_size++; /* NUL termination */
>
> status = efi_low_alloc(sys_table, options_size, 1,
> - &cmdline);
> + &cmdline, 0);
> if (status != EFI_SUCCESS) {
> efi_printk(sys_table, "Failed to alloc mem for cmdline\n");
> goto fail;
> @@ -563,7 +563,8 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
> again:
> size += sizeof(*mem_map) * 2;
> _size = size;
> - status = efi_low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
> + status = efi_low_alloc(sys_table, size, 1,
> + (unsigned long *)&mem_map, 0);
> if (status != EFI_SUCCESS)
> return status;
>
> @@ -697,7 +698,7 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)
> nr_pages, &start);
> if (status != EFI_SUCCESS) {
> status = efi_low_alloc(sys_table, hdr->init_size,
> - hdr->kernel_alignment, &start);
> + hdr->kernel_alignment, &start, 0);
> if (status != EFI_SUCCESS)
> efi_printk(sys_table, "Failed to alloc mem for kernel\n");
> }
> @@ -745,7 +746,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
>
> gdt->size = 0x800;
> status = efi_low_alloc(sys_table, gdt->size, 8,
> - (unsigned long *)&gdt->address);
> + (unsigned long *)&gdt->address, 0);
> if (status != EFI_SUCCESS) {
> efi_printk(sys_table, "Failed to alloc mem for gdt\n");
> goto fail;
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index 0218d535..40cd16e 100644
> --- a/drivers/firmware/efi/efi-stub-helper.c
> +++ b/drivers/firmware/efi/efi-stub-helper.c
> @@ -163,11 +163,11 @@ fail:
> }
>
> /*
> - * Allocate at the lowest possible address.
> + * Allocate at the lowest possible address, that is not below min.
> */
> 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 *addr, unsigned long min)
> {
> unsigned long map_size, desc_size;
> efi_memory_desc_t *map;
> @@ -204,6 +204,9 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
> if (start == 0x0)
> start += 8;
>
> + if (start < min)
> + start = min;
> +
> start = round_up(start, align);
> if ((start + size) > end)
> continue;
> --
> 1.7.10.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, 9 Aug 2013 16:26:06 -0700, Roy Franz <[email protected]> wrote:
> Signed-off-by: Roy Franz <[email protected]>
Same issue with the commit message here as for patch 4. Please include a
comment stating what is intended to use this new feature.
> ---
> drivers/firmware/efi/efi-stub-helper.c | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index 40cd16e..1d0a079 100644
> --- a/drivers/firmware/efi/efi-stub-helper.c
> +++ b/drivers/firmware/efi/efi-stub-helper.c
> @@ -46,10 +46,11 @@ 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,
> + unsigned long *key_ptr)
> {
> efi_memory_desc_t *m = NULL;
> efi_status_t status;
> @@ -77,6 +78,8 @@ again:
>
> if (status != EFI_SUCCESS)
> efi_call_phys1(sys_table_arg->boottime->free_pool, m);
> + if (key_ptr && status == EFI_SUCCESS)
> + *key_ptr = key;
>
> fail:
> *map = m;
> @@ -97,7 +100,8 @@ 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,
> + NULL);
> if (status != EFI_SUCCESS)
> goto fail;
>
> @@ -175,7 +179,8 @@ 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,
> + NULL);
> if (status != EFI_SUCCESS)
> goto fail;
>
> --
> 1.7.10.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, 9 Aug 2013 16:26:07 -0700, Roy Franz <[email protected]> wrote:
> 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.
Commit message. Otherwise looks reasonable.
Reviewed-by: Grant Likely <[email protected]>
> Signed-off-by: Roy Franz <[email protected]>
> ---
> drivers/firmware/efi/efi-stub-helper.c | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index 1d0a079..647b3ba 100644
> --- a/drivers/firmware/efi/efi-stub-helper.c
> +++ b/drivers/firmware/efi/efi-stub-helper.c
> @@ -105,6 +105,13 @@ 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++) {
> @@ -184,6 +191,13 @@ 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;
> --
> 1.7.10.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, 9 Aug 2013 16:26:09 -0700, Roy Franz <[email protected]> wrote:
> 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 <[email protected]>
Minor comment below, but otherwise looks good:
Reviewed-by: Grant Likely <[email protected]>
> ---
> @@ -380,7 +388,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 file: ");
"file file:"? Search and replace artifact?
On Fri, 9 Aug 2013 16:26:10 -0700, Roy Franz <[email protected]> wrote:
> Rename variables to be not initrd specific, as now the function
> loads arbitrary files.
>
> Signed-off-by: Roy Franz <[email protected]>
Reviewed-by: Grant Likely <[email protected]>
> ---
> drivers/firmware/efi/efi-stub-helper.c | 92 ++++++++++++++++----------------
> 1 file changed, 46 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index b5ef766..0f4d6e6 100644
> --- a/drivers/firmware/efi/efi-stub-helper.c
> +++ b/drivers/firmware/efi/efi-stub-helper.c
> @@ -11,7 +11,7 @@
> */
>
>
> -struct initrd {
> +struct file_info {
> efi_file_handle_t *handle;
> u64 size;
> };
> @@ -262,10 +262,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,
> @@ -273,19 +273,19 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
> u64 max_addr,
> u64 *load_addr, u64 *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;
>
> @@ -300,7 +300,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;
> @@ -315,21 +315,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];
> @@ -344,7 +344,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 */
> @@ -375,13 +375,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;
> }
> }
>
> @@ -394,7 +394,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,
> @@ -428,37 +428,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)
> @@ -466,36 +466,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;
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
On Fri, 9 Aug 2013 16:26:11 -0700, Roy Franz <[email protected]> wrote:
> This #define is only used the the shared code, so move
> it there.
>
> Signed-off-by: Roy Franz <[email protected]>
Can this be squashed into patch 1?
g.
> ---
> arch/x86/boot/compressed/eboot.h | 1 -
> drivers/firmware/efi/efi-stub-helper.c | 2 +-
> 2 files changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
> index faa0bdf..bafbd94 100644
> --- a/arch/x86/boot/compressed/eboot.h
> +++ b/arch/x86/boot/compressed/eboot.h
> @@ -12,7 +12,6 @@
> #define DESC_TYPE_CODE_DATA (1 << 0)
>
> #define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
> -#define EFI_READ_CHUNK_SIZE (1024 * 1024)
>
> #define EFI_CONSOLE_OUT_DEVICE_GUID \
> EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index 0f4d6e6..b707a9f 100644
> --- a/drivers/firmware/efi/efi-stub-helper.c
> +++ b/drivers/firmware/efi/efi-stub-helper.c
> @@ -9,7 +9,7 @@
> * under the terms of the GNU General Public License version 2.
> *
> */
> -
> +#define EFI_READ_CHUNK_SIZE (1024 * 1024)
>
> struct file_info {
> efi_file_handle_t *handle;
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
On Fri, 9 Aug 2013 16:26:12 -0700, Roy Franz <[email protected]> wrote:
> The x86/AMD64 EFI stubs must us a call wrapper to convert between
> the Linux and EFI ABIs, so void pointers are sufficient. For ARM,
> the ABIs are compatible, so we can directly invoke the function
> pointers. The functions that are used by the ARM stub are updated
> to match the EFI definitions.
>
> Signed-off-by: Roy Franz <[email protected]>
Looks reasonable.
Reviewed-by: Grant Likely <[email protected]>
> ---
> arch/x86/boot/compressed/eboot.h | 2 --
> include/linux/efi.h | 45 ++++++++++++++++++++++++--------------
> 2 files changed, 28 insertions(+), 19 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
> index bafbd94..81b6b65 100644
> --- a/arch/x86/boot/compressed/eboot.h
> +++ b/arch/x86/boot/compressed/eboot.h
> @@ -11,8 +11,6 @@
>
> #define DESC_TYPE_CODE_DATA (1 << 0)
>
> -#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
> -
> #define EFI_CONSOLE_OUT_DEVICE_GUID \
> EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
> 0x3f, 0xc1, 0x4d)
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 51f5641..1a7ae34 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -39,6 +39,8 @@
> typedef unsigned long efi_status_t;
> typedef u8 efi_bool_t;
> typedef u16 efi_char16_t; /* UNICODE character */
> +typedef u64 efi_physical_addr_t;
> +typedef void *efi_handle_t;
>
>
> typedef struct {
> @@ -96,6 +98,7 @@ typedef struct {
> #define EFI_MEMORY_DESCRIPTOR_VERSION 1
>
> #define EFI_PAGE_SHIFT 12
> +#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
>
> typedef struct {
> u32 type;
> @@ -157,11 +160,13 @@ typedef struct {
> efi_table_hdr_t hdr;
> void *raise_tpl;
> void *restore_tpl;
> - void *allocate_pages;
> - void *free_pages;
> - void *get_memory_map;
> - void *allocate_pool;
> - void *free_pool;
> + efi_status_t (*allocate_pages)(int, int, unsigned long,
> + efi_physical_addr_t *);
> + efi_status_t (*free_pages)(efi_physical_addr_t, unsigned long);
> + efi_status_t (*get_memory_map)(unsigned long *, void *, unsigned long *,
> + unsigned long *, u32 *);
> + efi_status_t (*allocate_pool)(int, unsigned long, void **);
> + efi_status_t (*free_pool)(void *);
> void *create_event;
> void *set_timer;
> void *wait_for_event;
> @@ -171,7 +176,7 @@ typedef struct {
> void *install_protocol_interface;
> void *reinstall_protocol_interface;
> void *uninstall_protocol_interface;
> - void *handle_protocol;
> + efi_status_t (*handle_protocol)(efi_handle_t, efi_guid_t *, void **);
> void *__reserved;
> void *register_protocol_notify;
> void *locate_handle;
> @@ -181,7 +186,7 @@ typedef struct {
> void *start_image;
> void *exit;
> void *unload_image;
> - void *exit_boot_services;
> + efi_status_t (*exit_boot_services)(efi_handle_t, unsigned long);
> void *get_next_monotonic_count;
> void *stall;
> void *set_watchdog_timer;
> @@ -488,10 +493,6 @@ typedef struct {
> unsigned long unload;
> } efi_loaded_image_t;
>
> -typedef struct {
> - u64 revision;
> - void *open_volume;
> -} efi_file_io_interface_t;
>
> typedef struct {
> u64 size;
> @@ -504,20 +505,30 @@ typedef struct {
> efi_char16_t filename[1];
> } efi_file_info_t;
>
> -typedef struct {
> +typedef struct _efi_file_handle {
> u64 revision;
> - void *open;
> - void *close;
> + efi_status_t (*open)(struct _efi_file_handle *,
> + struct _efi_file_handle **,
> + efi_char16_t *, u64, u64);
> + efi_status_t (*close)(struct _efi_file_handle *);
> void *delete;
> - void *read;
> + efi_status_t (*read)(struct _efi_file_handle *, unsigned long *,
> + void *);
> void *write;
> void *get_position;
> void *set_position;
> - void *get_info;
> + efi_status_t (*get_info)(struct _efi_file_handle *, efi_guid_t *,
> + unsigned long *, void *);
> void *set_info;
> void *flush;
> } efi_file_handle_t;
>
> +typedef struct _efi_file_io_interface {
> + u64 revision;
> + int (*open_volume)(struct _efi_file_io_interface *,
> + efi_file_handle_t **);
> +} efi_file_io_interface_t;
> +
> #define EFI_FILE_MODE_READ 0x0000000000000001
> #define EFI_FILE_MODE_WRITE 0x0000000000000002
> #define EFI_FILE_MODE_CREATE 0x8000000000000000
> @@ -787,7 +798,7 @@ struct efivar_entry {
>
> struct efi_simple_text_output_protocol {
> void *reset;
> - void *output_string;
> + efi_status_t (*output_string)(void *, void *);
> void *test_string;
> };
>
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
On Fri, 9 Aug 2013 16:26:13 -0700, Roy Franz <[email protected]> wrote:
> 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.
>
> Signed-off-by: Roy Franz <[email protected]>
> ---
> drivers/firmware/efi/efi-stub-helper.c | 15 +++++++++------
> 1 file changed, 9 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index b707a9f..4bb542f 100644
> --- a/drivers/firmware/efi/efi-stub-helper.c
> +++ b/drivers/firmware/efi/efi-stub-helper.c
> @@ -321,7 +321,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;
> @@ -372,7 +372,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;
> @@ -406,7 +407,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;
> @@ -456,18 +458,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);
I think you need some description in the commit text about why the type
of chunksize is changing. It's not clear why you're making this change.
It is a bug fix?
g.
On Fri, 9 Aug 2013 16:26:14 -0700, Roy Franz <[email protected]> wrote:
> 2 unused labels
> 1 "value computed is not used"
>
>
> Signed-off-by: Roy Franz <[email protected]>
When posting a patch to fix compile errors or warnings, it is helpful
inlude the output from the compiler with the error/warning message.
g.
> ---
> drivers/firmware/efi/efi-stub-helper.c | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
> index 4bb542f..3e82cb0 100644
> --- a/drivers/firmware/efi/efi-stub-helper.c
> +++ b/drivers/firmware/efi/efi-stub-helper.c
> @@ -166,7 +166,6 @@ again:
> *addr = max_addr;
> }
>
> -free_pool:
> efi_call_phys1(sys_table_arg->boottime->free_pool, map);
>
> fail:
> @@ -242,7 +241,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;
> @@ -357,7 +355,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
>
> if (*str == '/') {
> *p++ = '\\';
> - *str++;
> + str++;
> } else {
> *p++ = *str++;
> }
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
On Fri, 9 Aug 2013 16:26:15 -0700, Roy Franz <[email protected]> wrote:
> The shared efi-stub-helper.c functions require a strstr
> implementation.
> Implementation copied from arch/x86/boot/string.c
>
> Signed-off-by: Roy Franz <[email protected]>
Okay, but at some point arch/arm/boot/compressed/string.c should be
reworked into a common place.
Reviewed-by: Grant Likely <[email protected]>
> ---
> arch/arm/boot/compressed/string.c | 21 +++++++++++++++++++++
> 1 file changed, 21 insertions(+)
>
> diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c
> index 36e53ef..5397792 100644
> --- a/arch/arm/boot/compressed/string.c
> +++ b/arch/arm/boot/compressed/string.c
> @@ -111,6 +111,27 @@ char *strchr(const char *s, int c)
> return (char *)s;
> }
>
> +/**
> + * strstr - Find the first substring in a %NUL terminated string
> + * @s1: The string to be searched
> + * @s2: The string to search for
> + */
> +char *strstr(const char *s1, const char *s2)
> +{
> + size_t l1, l2;
> +
> + l2 = strlen(s2);
> + if (!l2)
> + return (char *)s1;
> + l1 = strlen(s1);
> + while (l1 >= l2) {
> + l1--;
> + if (!memcmp(s1, s2, l2))
> + return (char *)s1;
> + s1++;
> + }
> + return NULL;
> +}
> #undef memset
>
> void *memset(void *s, int c, size_t count)
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
On Fri, Aug 30, 2013 at 02:43:25PM +0100, Grant Likely wrote:
> On Fri, 9 Aug 2013 16:26:15 -0700, Roy Franz <[email protected]> wrote:
> > The shared efi-stub-helper.c functions require a strstr
> > implementation.
> > Implementation copied from arch/x86/boot/string.c
> >
> > Signed-off-by: Roy Franz <[email protected]>
>
> Okay, but at some point arch/arm/boot/compressed/string.c should be
> reworked into a common place.
Only if the common place can be built with arch specific compile options,
like -fpic, without impacting the rest of the kernel.
On Fri, Aug 30, 2013 at 2:47 PM, Russell King - ARM Linux
<[email protected]> wrote:
> On Fri, Aug 30, 2013 at 02:43:25PM +0100, Grant Likely wrote:
>> On Fri, 9 Aug 2013 16:26:15 -0700, Roy Franz <[email protected]> wrote:
>> > The shared efi-stub-helper.c functions require a strstr
>> > implementation.
>> > Implementation copied from arch/x86/boot/string.c
>> >
>> > Signed-off-by: Roy Franz <[email protected]>
>>
>> Okay, but at some point arch/arm/boot/compressed/string.c should be
>> reworked into a common place.
>
> Only if the common place can be built with arch specific compile options,
> like -fpic, without impacting the rest of the kernel.
agreed. It would be a bit of a science project to see how feasible.
g.
On Fri, Aug 30, 2013 at 7:02 AM, Grant Likely <[email protected]> wrote:
> On Fri, Aug 30, 2013 at 2:47 PM, Russell King - ARM Linux
> <[email protected]> wrote:
>> On Fri, Aug 30, 2013 at 02:43:25PM +0100, Grant Likely wrote:
>>> On Fri, 9 Aug 2013 16:26:15 -0700, Roy Franz <[email protected]> wrote:
>>> > The shared efi-stub-helper.c functions require a strstr
>>> > implementation.
>>> > Implementation copied from arch/x86/boot/string.c
>>> >
>>> > Signed-off-by: Roy Franz <[email protected]>
>>>
>>> Okay, but at some point arch/arm/boot/compressed/string.c should be
>>> reworked into a common place.
>>
>> Only if the common place can be built with arch specific compile options,
>> like -fpic, without impacting the rest of the kernel.
>
> agreed. It would be a bit of a science project to see how feasible.
>
> g.
The strstr implemtation here is pretty generic, but some architectures like
x86 use inline ASM for some of these string functions, so there are
some additional
complications to unifying this code across architectures.
Roy
On Fri, 9 Aug 2013 16:26:16 -0700, Roy Franz <[email protected]> wrote:
> This patch adds EFI stub support for the ARM Linux kernel. The EFI stub
> operations similarly to the x86 stub: it is a shim between the EFI firmware
> and the normal zImage entry point, and sets up the environment that the
> zImage is expecting. This includes loading the initrd (optionaly) and
> device tree from the system partition based on the kernel command line.
> The stub updates the device tree as necessary, including adding reserved
> memory regions and adding entries for EFI runtime services. The PE/COFF
> "MZ" header at offset 0 results in the first instruction being an add
> that corrupts r5, which is not used by the zImage interface.
>
> Signed-off-by: Roy Franz <[email protected]>
Hi Roy,
Looks like nice tight code. I've got some comments below, but in general
I'm pretty happy with it.
g.
> ---
> arch/arm/boot/compressed/Makefile | 15 +-
> arch/arm/boot/compressed/efi-header.S | 111 ++++++++
> arch/arm/boot/compressed/efi-stub.c | 448 +++++++++++++++++++++++++++++++++
> arch/arm/boot/compressed/efi-stub.h | 5 +
> arch/arm/boot/compressed/head.S | 90 ++++++-
> 5 files changed, 661 insertions(+), 8 deletions(-)
> create mode 100644 arch/arm/boot/compressed/efi-header.S
> create mode 100644 arch/arm/boot/compressed/efi-stub.c
> create mode 100644 arch/arm/boot/compressed/efi-stub.h
>
> diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
> index 7ac1610..5fad8bd 100644
> --- a/arch/arm/boot/compressed/Makefile
> +++ b/arch/arm/boot/compressed/Makefile
> @@ -103,11 +103,22 @@ libfdt_objs := $(addsuffix .o, $(basename $(libfdt)))
> $(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/%
> $(call cmd,shipped)
>
> -$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \
> +$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o efi-stub.o): \
> $(addprefix $(obj)/,$(libfdt_hdrs))
>
> ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
> -OBJS += $(libfdt_objs) atags_to_fdt.o
> +OBJS += atags_to_fdt.o
> +USE_LIBFDT = y
> +endif
> +
> +ifeq ($(CONFIG_EFI_STUB),y)
> +CFLAGS_efi-stub.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
> +OBJS += efi-stub.o
> +USE_LIBFDT = y
> +endif
> +
> +ifeq ($(USE_LIBFDT),y)
> +OBJS += $(libfdt_objs)
> endif
>
> targets := vmlinux vmlinux.lds \
> diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S
> new file mode 100644
> index 0000000..6965e0f
> --- /dev/null
> +++ b/arch/arm/boot/compressed/efi-header.S
> @@ -0,0 +1,111 @@
> +@ Copyright (C) 2013 Linaro Ltd; <[email protected]>
> +@
> +@ This file contains the PE/COFF header that is part of the
> +@ EFI stub.
> +@
> +
> + .org 0x3c
> + @
> + @ The PE header can be anywhere in the file, but for
> + @ simplicity we keep it together with the MSDOS header
> + @ The offset to the PE/COFF header needs to be at offset
> + @ 0x3C in the MSDOS header.
> + @ The only 2 fields of the MSDOS header that are used are this
> + @ PE/COFF offset, and the "MZ" bytes at offset 0x0.
> + @
> + .long pe_header @ Offset to the PE header.
> +
> + .align 3
> +pe_header:
> + .ascii "PE"
> + .short 0
> +
> +coff_header:
> + .short 0x01c2 @ ARM or Thumb
> + .short 2 @ nr_sections
> + .long 0 @ TimeDateStamp
> + .long 0 @ PointerToSymbolTable
> + .long 1 @ NumberOfSymbols
> + .short section_table - optional_header @ SizeOfOptionalHeader
> + .short 0x306 @ Characteristics.
> + @ IMAGE_FILE_32BIT_MACHINE |
> + @ IMAGE_FILE_DEBUG_STRIPPED |
> + @ IMAGE_FILE_EXECUTABLE_IMAGE |
> + @ IMAGE_FILE_LINE_NUMS_STRIPPED
> +
> +optional_header:
> + .short 0x10b @ PE32 format
> + .byte 0x02 @ MajorLinkerVersion
> + .byte 0x14 @ MinorLinkerVersion
> +
> + .long _edata - efi_stub_entry @ SizeOfCode
> +
> + .long 0 @ SizeOfInitializedData
> + .long 0 @ SizeOfUninitializedData
> +
> + .long efi_stub_entry @ AddressOfEntryPoint
> + .long efi_stub_entry @ BaseOfCode
> + .long 0 @ data
> +
> +extra_header_fields:
> + .long 0 @ ImageBase
> + .long 0x20 @ SectionAlignment
> + .long 0x20 @ FileAlignment
> + .short 0 @ MajorOperatingSystemVersion
> + .short 0 @ MinorOperatingSystemVersion
> + .short 0 @ MajorImageVersion
> + .short 0 @ MinorImageVersion
> + .short 0 @ MajorSubsystemVersion
> + .short 0 @ MinorSubsystemVersion
> + .long 0 @ Win32VersionValue
> +
> + .long _edata @ SizeOfImage
> +
> + @ Everything before the entry point is considered part of the header
> + .long efi_stub_entry @ SizeOfHeaders
> + .long 0 @ CheckSum
> + .short 0xa @ Subsystem (EFI application)
> + .short 0 @ DllCharacteristics
> + .long 0 @ SizeOfStackReserve
> + .long 0 @ SizeOfStackCommit
> + .long 0 @ SizeOfHeapReserve
> + .long 0 @ SizeOfHeapCommit
> + .long 0 @ LoaderFlags
> + .long 0x0 @ NumberOfRvaAndSizes
> +
> + # Section table
> +section_table:
> +
> + #
> + # The EFI application loader requires a relocation section
> + # because EFI applications must be relocatable. This is a
> + # dummy section as far as we are concerned.
> + #
> + .ascii ".reloc"
> + .byte 0
> + .byte 0 @ end of 0 padding of section name
> + .long 0
> + .long 0
> + .long 0 @ SizeOfRawData
> + .long 0 @ PointerToRawData
> + .long 0 @ PointerToRelocations
> + .long 0 @ PointerToLineNumbers
> + .short 0 @ NumberOfRelocations
> + .short 0 @ NumberOfLineNumbers
> + .long 0x42100040 @ Characteristics (section flags)
> +
> +
> + .ascii ".text"
> + .byte 0
> + .byte 0
> + .byte 0 @ end of 0 padding of section name
> + .long _edata - efi_stub_entry @ VirtualSize
> + .long efi_stub_entry @ VirtualAddress
> + .long _edata - efi_stub_entry @ SizeOfRawData
> + .long efi_stub_entry @ PointerToRawData
> +
> + .long 0 @ PointerToRelocations (0 for executables)
> + .long 0 @ PointerToLineNumbers (0 for executables)
> + .short 0 @ NumberOfRelocations (0 for executables)
> + .short 0 @ NumberOfLineNumbers (0 for executables)
> + .long 0xe0500020 @ Characteristics (section flags)
> diff --git a/arch/arm/boot/compressed/efi-stub.c b/arch/arm/boot/compressed/efi-stub.c
> new file mode 100644
> index 0000000..4fce68b
> --- /dev/null
> +++ b/arch/arm/boot/compressed/efi-stub.c
> @@ -0,0 +1,448 @@
> +/*
> + * linux/arch/arm/boot/compressed/efi-stub.c
> + *
> + * Copyright (C) 2013 Linaro Ltd; <[email protected]>
> + *
> + * This file implements the EFI boot stub for the ARM kernel
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +#include <linux/efi.h>
> +#include <libfdt.h>
> +#include "efi-stub.h"
> +
> +/* EFI function call wrappers. These are not required for
> + * ARM, but wrappers are required for X86 to convert between
> + * ABIs. These wrappers are provided to allow code sharing
> + * between X86 and ARM. Since these wrappers directly invoke the
> + * EFI function pointer, the function pointer type must be properly
> + * defined, which is not the case for X86 One advantage of this is
> + * it allows for type checking of arguments, which is not
> + * possible with the X86 wrappers.
> + */
> +#define efi_call_phys0(f) f()
> +#define efi_call_phys1(f, a1) f(a1)
> +#define efi_call_phys2(f, a1, a2) f(a1, a2)
> +#define efi_call_phys3(f, a1, a2, a3) f(a1, a2, a3)
> +#define efi_call_phys4(f, a1, a2, a3, a4) f(a1, a2, a3, a4)
> +#define efi_call_phys5(f, a1, a2, a3, a4, a5) f(a1, a2, a3, a4, a5)
> +
> +/* The maximum uncompressed kernel size is 32 MBytes, so we will reserve
> + * that for the decompressed kernel. We have no easy way to tell what
> + * the actuall size of code + data the uncompressed kernel will use.
> + */
> +#define MAX_UNCOMP_KERNEL_SIZE 0x02000000
> +
> +/* The kernel zImage should be located between 32 Mbytes
> + * and 128 MBytes from the base of DRAM. The min
> + * address leaves space for a maximal size uncompressed image,
> + * and the max address is due to how the zImage decompressor
> + * picks a destination address.
> + */
> +#define ZIMAGE_OFFSET_LIMIT 0x08000000
> +#define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE
> +
> +#define PRINTK_PREFIX "EFIstub: "
> +
> +struct fdt_region {
> + u64 base;
> + u64 size;
> +};
> +
> +
> +/* Include shared EFI stub code */
> +#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
> +
> +static int relocate_kernel(efi_system_table_t *sys_table,
> + unsigned long *zimage_addr,
> + unsigned long zimage_size,
> + unsigned long min_addr, unsigned long max_addr)
> +{
> + /* Get current address of kernel. */
> + unsigned long cur_zimage_addr = *zimage_addr;
> + unsigned long new_addr = 0;
> +
> + efi_status_t status;
> +
> + if (!zimage_addr || !zimage_size)
> + return EFI_INVALID_PARAMETER;
> +
> + if (cur_zimage_addr > min_addr
> + && (cur_zimage_addr + zimage_size) < max_addr) {
> + /* We don't need to do anything, as kernel is at an
> + * acceptable address already.
> + */
> + return EFI_SUCCESS;
> + }
> + /*
> + * The EFI firmware loader could have placed the kernel image
> + * anywhere in memory, but the kernel has restrictions on the
> + * min and max physical address it can run at.
> + */
> + status = efi_low_alloc(sys_table, zimage_size, 0,
> + &new_addr, min_addr);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to allocate usable memory for kernel.\n");
> + return status;
> + }
> +
> + if (new_addr > (max_addr - zimage_size)) {
> + efi_free(sys_table, zimage_size, new_addr);
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to allocate usable memory for kernel.\n");
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + /* 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 *)(unsigned long)cur_zimage_addr,
> + zimage_size);
> +
> + /* Return the load address */
> + *zimage_addr = new_addr;
> +
> + return status;
> +}
This function should be sharable with x86. ARM has more restrictions
that x86, but I don't see any reason for them to be separate. ARM64 is
certainly going to want to use some form of this too.
> +
> +
> +/* 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 *convert_cmdline_to_ascii(efi_system_table_t *sys_table,
> + efi_loaded_image_t *image,
> + unsigned long *cmd_line_len,
> + u32 max_addr)
x86 has equivalent code. This function should be factored out and used
by both.
> +{
> + u16 *s2;
> + u8 *s1 = NULL;
> + unsigned long cmdline_addr = 0;
> + int load_options_size = image->load_options_size / 2; /* ASCII */
> + void *options = (u16 *)image->load_options;
load_options is already a void*. What is the cast here for?
> + int options_size = 0;
> + int 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 */
> +
> + status = efi_high_alloc(sys_table, options_size, 0,
> + &cmdline_addr, max_addr);
> + if (status != EFI_SUCCESS)
> + return NULL;
> +
> + s1 = (u8 *)(unsigned long)cmdline_addr;
> + s2 = (u16 *)options;
> +
> + for (i = 0; i < options_size - 1; i++)
> + *s1++ = *s2++;
> +
> + *s1 = '\0';
> +
> + *cmd_line_len = options_size;
> + return (char *)(unsigned long)cmdline_addr;
Double casting? That looks wrong. Why does the (unsigned long) bit need
to be there?
> +}
> +
> +
> +static u32 update_fdt(efi_system_table_t *sys_table, void *orig_fdt, void *fdt,
> + int new_fdt_size, char *cmdline_ptr, u64 initrd_addr,
> + u64 initrd_size, efi_memory_desc_t *memory_map,
> + int map_size, int desc_size)
ARM64 will want access to this function.
> +{
> + int node;
> + int status;
> + unsigned long fdt_val;
> +
> + status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
> + if (status != 0)
> + goto fdt_set_fail;
> +
> + node = fdt_subnode_offset(fdt, 0, "chosen");
> + if (node < 0) {
> + node = fdt_add_subnode(fdt, 0, "chosen");
> + if (node < 0) {
> + status = node; /* node is error code when negative */
> + goto fdt_set_fail;
> + }
> + }
> +
> + if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) {
> + status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
> + strlen(cmdline_ptr) + 1);
> + if (status)
> + goto fdt_set_fail;
> + }
Some comments in this function would help poor readers like me.
> +
> + /* Set intird address/end in device tree, if present */
> + if (initrd_size != 0) {
> + u64 initrd_image_end;
> + u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
> + status = fdt_setprop(fdt, node, "linux,initrd-start",
> + &initrd_image_start, sizeof(u64));
> + if (status)
> + goto fdt_set_fail;
> + initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
> + status = fdt_setprop(fdt, node, "linux,initrd-end",
> + &initrd_image_end, sizeof(u64));
> + if (status)
> + goto fdt_set_fail;
> + }
> +
> + /* Add FDT entries for EFI runtime services in chosen node. */
> + node = fdt_subnode_offset(fdt, 0, "chosen");
> + fdt_val = cpu_to_fdt32((unsigned long)sys_table);
> + status = fdt_setprop(fdt, node, "efi-system-table",
> + &fdt_val, sizeof(fdt_val));
> + if (status)
> + goto fdt_set_fail;
> +
> + fdt_val = cpu_to_fdt32(desc_size);
> + status = fdt_setprop(fdt, node, "efi-mmap-desc-size",
> + &fdt_val, sizeof(fdt_val));
> + if (status)
> + goto fdt_set_fail;
> +
> + fdt_val = cpu_to_fdt32(map_size);
> + status = fdt_setprop(fdt, node, "efi-runtime-mmap-size",
> + &fdt_val, sizeof(fdt_val));
> + if (status)
> + goto fdt_set_fail;
> +
> + fdt_val = cpu_to_fdt32((unsigned long)memory_map);
> + status = fdt_setprop(fdt, node, "efi-runtime-mmap",
> + &fdt_val, sizeof(fdt_val));
> + if (status)
> + goto fdt_set_fail;
> +
> + return EFI_SUCCESS;
> +
> +fdt_set_fail:
> + if (status == -FDT_ERR_NOSPACE)
> + return EFI_BUFFER_TOO_SMALL;
> +
> + return EFI_LOAD_ERROR;
> +}
> +
> +
> +
> +int efi_entry(void *handle, efi_system_table_t *sys_table,
> + unsigned long *zimage_addr)
> +{
> + efi_loaded_image_t *image;
> + int status;
> + unsigned long nr_pages;
> + const struct fdt_region *region;
> +
> + void *fdt;
> + int err;
> + int node;
> + unsigned long zimage_size = 0;
> + unsigned long dram_base;
> + /* addr/point and size pairs for memory management*/
> + u64 initrd_addr;
> + u64 initrd_size = 0;
> + u64 fdt_addr;
> + u64 fdt_size = 0;
> + u64 kernel_reserve_addr;
> + u64 kernel_reserve_size = 0;
> + char *cmdline_ptr;
> + unsigned long cmdline_size = 0;
> +
> + unsigned long map_size, desc_size;
> + unsigned long mmap_key;
> + efi_memory_desc_t *memory_map;
> +
> + unsigned long new_fdt_size;
> + unsigned long new_fdt_addr;
> +
> + efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
> +
> + /* Check if we were booted by the EFI firmware */
> + if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
> + goto fail;
> +
> + efi_printk(sys_table, PRINTK_PREFIX"Booting Linux using EFI stub.\n");
> +
> +
> + /* get the command line from EFI, using the LOADED_IMAGE protocol */
> + status = efi_call_phys3(sys_table->boottime->handle_protocol,
> + handle, &proto, (void *)&image);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
> + goto fail;
> + }
> +
> + /* We are going to copy this into device tree, so we don't care where in
> + * memory it is.
> + */
> + cmdline_ptr = convert_cmdline_to_ascii(sys_table, image,
> + &cmdline_size, 0xFFFFFFFF);
> + if (!cmdline_ptr) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: converting command line to ascii failed.\n");
> + goto fail;
> + }
> +
> + /* We first load the device tree, as we need to get the base address of
> + * DRAM from the device tree. The zImage, device tree, and initrd
> + * have address restrictions that are relative to the base of DRAM.
> + */
> + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "dtb=",
> + 0xffffffff, &fdt_addr, &fdt_size);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load device tree blob.\n");
> + goto fail_free_cmdline;
> + }
> +
> + err = fdt_check_header((void *)(unsigned long)fdt_addr);
> + if (err != 0) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: device tree header not valid\n");
> + goto fail_free_fdt;
> + }
> + if (fdt_totalsize((void *)(unsigned long)fdt_addr) > fdt_size) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Incomplete device tree.\n");
> + goto fail_free_fdt;
> +
> + }
> +
> +
> + /* Look up the base of DRAM from the device tree.*/
> + fdt = (void *)(u32)fdt_addr;
More double casting. This one might be legitimate, but you need to
describe why. Is there any possibility that the FDT would appear above
4G?
> + node = fdt_subnode_offset(fdt, 0, "memory");
> + region = fdt_getprop(fdt, node, "reg", NULL);
> + if (region) {
> + dram_base = fdt64_to_cpu(region->base);
> + } else {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: no 'memory' node in device tree.\n");
> + goto fail_free_fdt;
Shouldn't fail here. If there is no memory node then create one.
> + }
> +
> + /* Reserve memory for the uncompressed kernel image. */
> + kernel_reserve_addr = dram_base;
> + kernel_reserve_size = MAX_UNCOMP_KERNEL_SIZE;
> + nr_pages = round_up(kernel_reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
> + status = efi_call_phys4(sys_table->boottime->allocate_pages,
> + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
> + nr_pages, &kernel_reserve_addr);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: unable to allocate memory for uncompressed kernel.\n");
> + goto fail_free_fdt;
> + }
> +
> + /* Relocate the zImage, if required. */
> + zimage_size = image->image_size;
> + status = relocate_kernel(sys_table, zimage_addr, zimage_size,
> + dram_base + MIN_ZIMAGE_OFFSET,
> + dram_base + ZIMAGE_OFFSET_LIMIT);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to relocate kernel\n");
> + goto fail_free_kernel_reserve;
> + }
> +
> + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=",
> + dram_base + ZIMAGE_OFFSET_LIMIT,
> + &initrd_addr, &initrd_size);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load initrd\n");
> + goto fail_free_zimage;
> + }
> +
> + /* Estimate size of new FDT, and allocate memory for it. We
> + * will allocate a bigger buffer if this ends up being too
> + * small, so a rough guess is OK here.*/
> + new_fdt_size = fdt_size + cmdline_size + 0x200;
> +
> +fdt_alloc_retry:
> + status = efi_high_alloc(sys_table, new_fdt_size, 0, &new_fdt_addr,
> + dram_base + ZIMAGE_OFFSET_LIMIT);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to allocate memory for new device tree.\n");
> + goto fail_free_initrd;
> + }
> +
> + /* Now that we have done our final memory allocation (and free)
> + * we can get the memory map key needed
> + * forexit_boot_services.*/
> + status = efi_get_memory_map(sys_table, &memory_map, &map_size,
> + &desc_size, &mmap_key);
> + if (status != EFI_SUCCESS)
> + goto fail_free_new_fdt;
> +
> + status = update_fdt(sys_table,
> + fdt, (void *)new_fdt_addr, new_fdt_size,
> + cmdline_ptr,
> + initrd_addr, initrd_size,
> + memory_map, map_size, desc_size);
> +
> + if (status != EFI_SUCCESS) {
> + if (status == EFI_BUFFER_TOO_SMALL) {
> + /* We need to allocate more space for the new
> + * device tree, so free existing buffer that is
> + * too small. Also free memory map, as we will need
> + * to get new one that reflects the free/alloc we do
> + * on the device tree buffer. */
> + efi_free(sys_table, new_fdt_size, new_fdt_addr);
> + efi_call_phys1(sys_table->boottime->free_pool,
> + memory_map);
> + new_fdt_size += new_fdt_size/4;
> + goto fdt_alloc_retry;
> + }
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to constuct new device tree.\n");
> + goto fail_free_initrd;
> + }
> +
> + /* Now we are ready to exit_boot_services.*/
> + status = efi_call_phys2(sys_table->boottime->exit_boot_services,
> + handle, mmap_key);
> +
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: exit boot services failed.\n");
> + goto fail_free_mmap;
> + }
> +
> +
> + /* Now we need to return the FDT address to the calling
> + * assembly to this can be used as part of normal boot.
> + */
> + return new_fdt_addr;
> +
> +fail_free_mmap:
> + efi_call_phys1(sys_table->boottime->free_pool, memory_map);
> +
> +fail_free_new_fdt:
> + efi_free(sys_table, new_fdt_size, new_fdt_addr);
> +
> +fail_free_initrd:
> + efi_free(sys_table, initrd_size, initrd_addr);
> +
> +fail_free_zimage:
> + efi_free(sys_table, zimage_size, *zimage_addr);
> +
> +fail_free_kernel_reserve:
> + efi_free(sys_table, kernel_reserve_addr, kernel_reserve_size);
> +
> +fail_free_fdt:
> + efi_free(sys_table, fdt_size, fdt_addr);
> +
> +fail_free_cmdline:
> + efi_free(sys_table, cmdline_size, (u32)cmdline_ptr);
> +
> +fail:
> + return EFI_STUB_ERROR;
> +}
> diff --git a/arch/arm/boot/compressed/efi-stub.h b/arch/arm/boot/compressed/efi-stub.h
> new file mode 100644
> index 0000000..0fe9376
> --- /dev/null
> +++ b/arch/arm/boot/compressed/efi-stub.h
> @@ -0,0 +1,5 @@
> +#ifndef _ARM_EFI_STUB_H
> +#define _ARM_EFI_STUB_H
> +/* Error code returned to ASM code instead of valid FDT address. */
> +#define EFI_STUB_ERROR (~0)
> +#endif
> diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
> index 75189f1..5401a3a 100644
> --- a/arch/arm/boot/compressed/head.S
> +++ b/arch/arm/boot/compressed/head.S
> @@ -10,6 +10,7 @@
> */
> #include <linux/linkage.h>
> #include <asm/assembler.h>
> +#include "efi-stub.h"
>
> .arch armv7-a
> /*
> @@ -120,21 +121,99 @@
> */
> .align
> .arm @ Always enter in ARM state
> + .text
> start:
> .type start,#function
> - .rept 7
> +#ifdef CONFIG_EFI_STUB
> + @ Magic MSDOS signature for PE/COFF + ADD opcode
> + .word 0x62805a4d
> +#else
> + mov r0, r0
> +#endif
> + .rept 5
> mov r0, r0
> .endr
> - ARM( mov r0, r0 )
> - ARM( b 1f )
> - THUMB( adr r12, BSYM(1f) )
> - THUMB( bx r12 )
> +
> + adrl r12, BSYM(zimage_continue)
> + ARM( mov pc, r12 )
> + THUMB( bx r12 )
> + @ zimage_continue will be in ARM or thumb mode as configured
>
> .word 0x016f2818 @ Magic numbers to help the loader
> .word start @ absolute load/run zImage address
> .word _edata @ zImage end address
> +
> +#ifdef CONFIG_EFI_STUB
> + @ Portions of the MSDOS file header must be at offset
> + @ 0x3c from the start of the file. All PE/COFF headers
> + @ are kept contiguous for simplicity.
> +#include "efi-header.S"
> +
> +efi_stub_entry:
> + @ The EFI stub entry point is not at a fixed address, however
> + @ this address must be set in the PE/COFF header.
> + @ EFI entry point is in A32 mode, switch to T32 if configured.
> + THUMB( adr r12, BSYM(1f) )
> + THUMB( bx r12 )
> THUMB( .thumb )
> 1:
> + @ Save lr on stack for possible return to EFI firmware.
> + @ Don't care about fp, but need 64 bit alignment....
> + stmfd sp!, {fp, lr}
> +
> + @ allocate space on stack for return of new entry point of
> + @ zImage, as EFI stub may copy the kernel. Pass address
> + @ of space in r2 - EFI stub will fill in the pointer.
> +
> + sub sp, sp, #8 @ we only need 4 bytes,
> + @ but keep stack 8 byte aligned.
> + mov r2, sp
> + @ Pass our actual runtime start address in pointer data
> + adr r11, LC0 @ address of LC0 at run time
> + ldr r12, [r11, #0] @ address of LC0 at link time
> +
> + sub r3, r11, r12 @ calculate the delta offset
> + str r3, [r2, #0]
> + bl efi_entry
> +
> + @ get new zImage entry address from stack, put into r3
> + ldr r3, [sp, #0]
> + add sp, sp, #8 @ restore stack
> +
> + @ Check for error return from EFI stub
> + mov r1, #EFI_STUB_ERROR
> + cmp r0, r1
> + beq efi_load_fail
> +
> +
> + @ Save return values of efi_entry
> + stmfd sp!, {r0, r3}
> + bl cache_clean_flush
> + bl cache_off
> + ldmfd sp!, {r0, r3}
> +
> + @ Set parameters for booting zImage according to boot protocol
> + @ put FDT address in r2, it was returned by efi_entry()
> + @ r1 is FDT machine type, and r0 needs to be 0
> + mov r2, r0
> + mov r1, #0xFFFFFFFF
> + mov r0, #0
> +
> + @ Branch to (possibly) relocated zImage that is in r3
> + @ Make sure we are in A32 mode, as zImage requires
> + THUMB( bx r3 )
> + ARM( mov pc, r3 )
> +
> +efi_load_fail:
> + @ Return EFI_LOAD_ERROR to EFI firmware on error.
> + @ Switch back to ARM mode for EFI is done based on
> + @ return address on stack
> + ldr r0, =0x80000001
> + ldmfd sp!, {fp, pc}
> +#endif
> +
> + THUMB( .thumb )
> +zimage_continue:
> mrs r9, cpsr
> #ifdef CONFIG_ARM_VIRT_EXT
> bl __hyp_stub_install @ get into SVC mode, reversibly
> @@ -167,7 +246,6 @@ not_angel:
> * by the linker here, but it should preserve r7, r8, and r9.
> */
>
> - .text
>
> #ifdef CONFIG_AUTO_ZRELADDR
> @ determine final kernel image address
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
On Fri, Aug 30, 2013 at 5:53 AM, Grant Likely <[email protected]> wrote:
> On Fri, 9 Aug 2013 16:26:03 -0700, Roy Franz <[email protected]> wrote:
>> Signed-off-by: Roy Franz <[email protected]>
>
> The entire commit message is contained in the subject line! The first
> line of a commit message needs to be a short summary, followed by a
> blank line, followed by the full description. Commit text body should be
> wrapped at column 72 so it looks nice in 'git log'
Commit formatting fixed, benefits of no GOT relocation expanded upon.
>
> From your commit message:
>> Subject: Re: [PATCH 02/16] Add system pointer argument to shared EFI
>> stub related functions so they no longer use global system table
>> pointer as they did when part of eboot.c. This code is now shared, so
>> using a global variable as part of the interface is not that nice.
>> Also, by avoiding any global variables in the ARM EFI stub, this
>> allows the code to be position independent without requiring GOT
>> fixups.
>
> The argument about avoiding GOT fixups is stronger than the global
> variables comment. I don't see a problem at all with using a global
> context pointer since this code will only ever run within the context of
> the EFI environment where there must always be a system table pointer.
> It isn't as if there will ever be multiple system tables.
>
> How much of a concern are GOT fixups at this stage? I thought GOT fixups
> were a solved problem for the EFI stub.
I can do the GOT fixups if required, but it simplifies the code a fair
bit if we don't have to do them.
When relocating the zImage to a location it can boot from, right now I
can just copy it since the GOT
hasn't been fixed up. If I fixup the GOT for the location that the
EFI firmware loads it, after I copy it
to the bootable location, then un-fixup the GOT so that the GOT fixup
code that the decompressor code
does will work. I get to avoid all this by not having any global variables.
>
> g.
>
>> ---
>> arch/x86/boot/compressed/eboot.c | 38 +++++++------
>> drivers/firmware/efi/efi-stub-helper.c | 96 +++++++++++++++++---------------
>> 2 files changed, 72 insertions(+), 62 deletions(-)
>>
>> diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
>> index ab0eefc..65b6a34 100644
>> --- a/arch/x86/boot/compressed/eboot.c
>> +++ b/arch/x86/boot/compressed/eboot.c
>> @@ -453,13 +453,13 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
>> status = efi_call_phys3(sys_table->boottime->handle_protocol,
>> handle, &proto, (void *)&image);
>> if (status != EFI_SUCCESS) {
>> - efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
>> + efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
>> return NULL;
>> }
>>
>> - status = low_alloc(0x4000, 1, (unsigned long *)&boot_params);
>> + status = low_alloc(sys_table, 0x4000, 1, (unsigned long *)&boot_params);
>> if (status != EFI_SUCCESS) {
>> - efi_printk("Failed to alloc lowmem for boot params\n");
>> + efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
>> return NULL;
>> }
>>
>> @@ -503,9 +503,10 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
>>
>> options_size++; /* NUL termination */
>>
>> - status = low_alloc(options_size, 1, &cmdline);
>> + status = low_alloc(sys_table, options_size, 1,
>> + &cmdline);
>> if (status != EFI_SUCCESS) {
>> - efi_printk("Failed to alloc mem for cmdline\n");
>> + efi_printk(sys_table, "Failed to alloc mem for cmdline\n");
>> goto fail;
>> }
>>
>> @@ -529,16 +530,16 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
>>
>> memset(sdt, 0, sizeof(*sdt));
>>
>> - status = handle_ramdisks(image, hdr);
>> + status = handle_ramdisks(sys_table, image, hdr);
>> if (status != EFI_SUCCESS)
>> goto fail2;
>>
>> return boot_params;
>> fail2:
>> if (options_size)
>> - low_free(options_size, hdr->cmd_line_ptr);
>> + low_free(sys_table, options_size, hdr->cmd_line_ptr);
>> fail:
>> - low_free(0x4000, (unsigned long)boot_params);
>> + low_free(sys_table, 0x4000, (unsigned long)boot_params);
>> return NULL;
>> }
>>
>> @@ -561,7 +562,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
>> again:
>> size += sizeof(*mem_map) * 2;
>> _size = size;
>> - status = low_alloc(size, 1, (unsigned long *)&mem_map);
>> + status = low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
>> if (status != EFI_SUCCESS)
>> return status;
>>
>> @@ -569,7 +570,7 @@ get_map:
>> status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
>> mem_map, &key, &desc_size, &desc_version);
>> if (status == EFI_BUFFER_TOO_SMALL) {
>> - low_free(_size, (unsigned long)mem_map);
>> + low_free(sys_table, _size, (unsigned long)mem_map);
>> goto again;
>> }
>>
>> @@ -671,7 +672,7 @@ get_map:
>> return EFI_SUCCESS;
>>
>> free_mem_map:
>> - low_free(_size, (unsigned long)mem_map);
>> + low_free(sys_table, _size, (unsigned long)mem_map);
>> return status;
>> }
>>
>> @@ -694,10 +695,10 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)
>> EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
>> nr_pages, &start);
>> if (status != EFI_SUCCESS) {
>> - status = low_alloc(hdr->init_size, hdr->kernel_alignment,
>> - &start);
>> + status = low_alloc(sys_table, hdr->init_size,
>> + hdr->kernel_alignment, &start);
>> if (status != EFI_SUCCESS)
>> - efi_printk("Failed to alloc mem for kernel\n");
>> + efi_printk(sys_table, "Failed to alloc mem for kernel\n");
>> }
>>
>> if (status == EFI_SUCCESS)
>> @@ -737,14 +738,15 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
>> EFI_LOADER_DATA, sizeof(*gdt),
>> (void **)&gdt);
>> if (status != EFI_SUCCESS) {
>> - efi_printk("Failed to alloc mem for gdt structure\n");
>> + efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
>> goto fail;
>> }
>>
>> gdt->size = 0x800;
>> - status = low_alloc(gdt->size, 8, (unsigned long *)&gdt->address);
>> + status = low_alloc(sys_table, gdt->size, 8,
>> + (unsigned long *)&gdt->address);
>> if (status != EFI_SUCCESS) {
>> - efi_printk("Failed to alloc mem for gdt\n");
>> + efi_printk(sys_table, "Failed to alloc mem for gdt\n");
>> goto fail;
>> }
>>
>> @@ -752,7 +754,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
>> EFI_LOADER_DATA, sizeof(*idt),
>> (void **)&idt);
>> if (status != EFI_SUCCESS) {
>> - efi_printk("Failed to alloc mem for idt structure\n");
>> + efi_printk(sys_table, "Failed to alloc mem for idt structure\n");
>> goto fail;
>> }
>>
>> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
>> index 47891bd..bd6c1a2 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;
>> --
>> 1.7.10.4
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
On Fri, Aug 30, 2013 at 6:01 AM, Grant Likely <[email protected]> wrote:
> On Fri, 9 Aug 2013 16:26:05 -0700, Roy Franz <[email protected]> wrote:
>> This allows allocations to be made low in memory while
>> avoiding allocations at the base of memory.
>
> Your commit message should include /why/ the change is needed. From the
> above I understand what the patch does, but I don't understand why it is
> necessary.
This was used to avoid relocating the zImage so low in memory that it
would conflict
with memory range that it was decompressed into. This is now handled
by allocating
the memory for the decompressed kernel, so the lower limit is no
longer required.
I'll remove it, as it is not necessary any more.
>
> The patch looks fine to me, but it would be worth investigating merging
> alloc_low and alloc_high. It looks like they both do pretty close to the
> same calculations. A single core function could do both, could have both
> minimum and maximum constraints, and could have a flag to determine if
> low or high addresses should be preferred.
>
> g.
>
> Reviewed-by: Grant Likely <[email protected]>
>
>>
>> Signed-off-by: Roy Franz <[email protected]>
>> ---
>> arch/x86/boot/compressed/eboot.c | 11 ++++++-----
>> drivers/firmware/efi/efi-stub-helper.c | 7 +++++--
>> 2 files changed, 11 insertions(+), 7 deletions(-)
>>
>> diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
>> index 2a4430a..f44ef2f 100644
>> --- a/arch/x86/boot/compressed/eboot.c
>> +++ b/arch/x86/boot/compressed/eboot.c
>> @@ -458,7 +458,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
>> }
>>
>> status = efi_low_alloc(sys_table, 0x4000, 1,
>> - (unsigned long *)&boot_params);
>> + (unsigned long *)&boot_params, 0);
>> if (status != EFI_SUCCESS) {
>> efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
>> return NULL;
>> @@ -505,7 +505,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
>> options_size++; /* NUL termination */
>>
>> status = efi_low_alloc(sys_table, options_size, 1,
>> - &cmdline);
>> + &cmdline, 0);
>> if (status != EFI_SUCCESS) {
>> efi_printk(sys_table, "Failed to alloc mem for cmdline\n");
>> goto fail;
>> @@ -563,7 +563,8 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
>> again:
>> size += sizeof(*mem_map) * 2;
>> _size = size;
>> - status = efi_low_alloc(sys_table, size, 1, (unsigned long *)&mem_map);
>> + status = efi_low_alloc(sys_table, size, 1,
>> + (unsigned long *)&mem_map, 0);
>> if (status != EFI_SUCCESS)
>> return status;
>>
>> @@ -697,7 +698,7 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)
>> nr_pages, &start);
>> if (status != EFI_SUCCESS) {
>> status = efi_low_alloc(sys_table, hdr->init_size,
>> - hdr->kernel_alignment, &start);
>> + hdr->kernel_alignment, &start, 0);
>> if (status != EFI_SUCCESS)
>> efi_printk(sys_table, "Failed to alloc mem for kernel\n");
>> }
>> @@ -745,7 +746,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
>>
>> gdt->size = 0x800;
>> status = efi_low_alloc(sys_table, gdt->size, 8,
>> - (unsigned long *)&gdt->address);
>> + (unsigned long *)&gdt->address, 0);
>> if (status != EFI_SUCCESS) {
>> efi_printk(sys_table, "Failed to alloc mem for gdt\n");
>> goto fail;
>> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
>> index 0218d535..40cd16e 100644
>> --- a/drivers/firmware/efi/efi-stub-helper.c
>> +++ b/drivers/firmware/efi/efi-stub-helper.c
>> @@ -163,11 +163,11 @@ fail:
>> }
>>
>> /*
>> - * Allocate at the lowest possible address.
>> + * Allocate at the lowest possible address, that is not below min.
>> */
>> 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 *addr, unsigned long min)
>> {
>> unsigned long map_size, desc_size;
>> efi_memory_desc_t *map;
>> @@ -204,6 +204,9 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
>> if (start == 0x0)
>> start += 8;
>>
>> + if (start < min)
>> + start = min;
>> +
>> start = round_up(start, align);
>> if ((start + size) > end)
>> continue;
>> --
>> 1.7.10.4
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
On Fri, Aug 30, 2013 at 6:33 AM, Grant Likely <[email protected]> wrote:
> On Fri, 9 Aug 2013 16:26:11 -0700, Roy Franz <[email protected]> wrote:
>> This #define is only used the the shared code, so move
>> it there.
>>
>> Signed-off-by: Roy Franz <[email protected]>
>
> Can this be squashed into patch 1?
Yes, that makes sense.
>
> g.
>
>> ---
>> arch/x86/boot/compressed/eboot.h | 1 -
>> drivers/firmware/efi/efi-stub-helper.c | 2 +-
>> 2 files changed, 1 insertion(+), 2 deletions(-)
>>
>> diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
>> index faa0bdf..bafbd94 100644
>> --- a/arch/x86/boot/compressed/eboot.h
>> +++ b/arch/x86/boot/compressed/eboot.h
>> @@ -12,7 +12,6 @@
>> #define DESC_TYPE_CODE_DATA (1 << 0)
>>
>> #define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
>> -#define EFI_READ_CHUNK_SIZE (1024 * 1024)
>>
>> #define EFI_CONSOLE_OUT_DEVICE_GUID \
>> EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
>> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
>> index 0f4d6e6..b707a9f 100644
>> --- a/drivers/firmware/efi/efi-stub-helper.c
>> +++ b/drivers/firmware/efi/efi-stub-helper.c
>> @@ -9,7 +9,7 @@
>> * under the terms of the GNU General Public License version 2.
>> *
>> */
>> -
>> +#define EFI_READ_CHUNK_SIZE (1024 * 1024)
>>
>> struct file_info {
>> efi_file_handle_t *handle;
>> --
>> 1.7.10.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
>
On Fri, Aug 30, 2013 at 11:12 PM, Roy Franz <[email protected]> wrote:
> On Fri, Aug 30, 2013 at 6:01 AM, Grant Likely <[email protected]> wrote:
>> On Fri, 9 Aug 2013 16:26:05 -0700, Roy Franz <[email protected]> wrote:
>>> This allows allocations to be made low in memory while
>>> avoiding allocations at the base of memory.
>>
>> Your commit message should include /why/ the change is needed. From the
>> above I understand what the patch does, but I don't understand why it is
>> necessary.
>
> This was used to avoid relocating the zImage so low in memory that it
> would conflict
> with memory range that it was decompressed into. This is now handled
> by allocating
> the memory for the decompressed kernel, so the lower limit is no
> longer required.
> I'll remove it, as it is not necessary any more.
Even better! :-)
g.
On Fri, Aug 30, 2013 at 6:39 AM, Grant Likely <[email protected]> wrote:
> On Fri, 9 Aug 2013 16:26:13 -0700, Roy Franz <[email protected]> wrote:
>> 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.
>>
>> Signed-off-by: Roy Franz <[email protected]>
>> ---
>> drivers/firmware/efi/efi-stub-helper.c | 15 +++++++++------
>> 1 file changed, 9 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
>> index b707a9f..4bb542f 100644
>> --- a/drivers/firmware/efi/efi-stub-helper.c
>> +++ b/drivers/firmware/efi/efi-stub-helper.c
>> @@ -321,7 +321,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;
>> @@ -372,7 +372,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;
>> @@ -406,7 +407,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;
>> @@ -456,18 +458,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);
>
> I think you need some description in the commit text about why the type
> of chunksize is changing. It's not clear why you're making this change.
> It is a bug fix?
The type was changed to match the EFI_FILE_PROTOCOL specification -
chunk size is
defined as a native width unsigned integer. So yes, this is a bug in
that this is wrong for
ia32, since that really should be a u32 in that case.
Since the x86 wrappers break type checking by the compiler these types
were never checked at compile time
before. chunksize is the the only change that isn't a cast to a type
of void pointer.
I can break this change out as a separate patch if desired.
Matt - would you like me to split the chunksize type change into a
separate patch from the arm EFI stub series?
Roy
>
> g.
On Sat, Aug 31, 2013 at 12:12 AM, Roy Franz <[email protected]> wrote:
> On Fri, Aug 30, 2013 at 6:39 AM, Grant Likely <[email protected]> wrote:
>> I think you need some description in the commit text about why the type
>> of chunksize is changing. It's not clear why you're making this change.
>> It is a bug fix?
>
> The type was changed to match the EFI_FILE_PROTOCOL specification -
> chunk size is
> defined as a native width unsigned integer. So yes, this is a bug in
> that this is wrong for
> ia32, since that really should be a u32 in that case.
> Since the x86 wrappers break type checking by the compiler these types
> were never checked at compile time
> before. chunksize is the the only change that isn't a cast to a type
> of void pointer.
>
> I can break this change out as a separate patch if desired.
I don't think it needs to be in a separate patch, but it does need to
be described in the patch description.
g.
On Fri, Aug 30, 2013 at 4:14 PM, Grant Likely <[email protected]> wrote:
> On Sat, Aug 31, 2013 at 12:12 AM, Roy Franz <[email protected]> wrote:
>> On Fri, Aug 30, 2013 at 6:39 AM, Grant Likely <[email protected]> wrote:
>>> I think you need some description in the commit text about why the type
>>> of chunksize is changing. It's not clear why you're making this change.
>>> It is a bug fix?
>>
>> The type was changed to match the EFI_FILE_PROTOCOL specification -
>> chunk size is
>> defined as a native width unsigned integer. So yes, this is a bug in
>> that this is wrong for
>> ia32, since that really should be a u32 in that case.
>> Since the x86 wrappers break type checking by the compiler these types
>> were never checked at compile time
>> before. chunksize is the the only change that isn't a cast to a type
>> of void pointer.
>>
>> I can break this change out as a separate patch if desired.
>
> I don't think it needs to be in a separate patch, but it does need to
> be described in the patch description.
>
> g.
Did that - how about:
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 <[email protected]>
On Fri, Aug 30, 2013 at 7:36 AM, Grant Likely <[email protected]> wrote:
> On Fri, 9 Aug 2013 16:26:16 -0700, Roy Franz <[email protected]> wrote:
>> This patch adds EFI stub support for the ARM Linux kernel. The EFI stub
>> operations similarly to the x86 stub: it is a shim between the EFI firmware
>> and the normal zImage entry point, and sets up the environment that the
>> zImage is expecting. This includes loading the initrd (optionaly) and
>> device tree from the system partition based on the kernel command line.
>> The stub updates the device tree as necessary, including adding reserved
>> memory regions and adding entries for EFI runtime services. The PE/COFF
>> "MZ" header at offset 0 results in the first instruction being an add
>> that corrupts r5, which is not used by the zImage interface.
>>
>> Signed-off-by: Roy Franz <[email protected]>
>
> Hi Roy,
>
> Looks like nice tight code. I've got some comments below, but in general
> I'm pretty happy with it.
>
> g.
>
>> ---
>> arch/arm/boot/compressed/Makefile | 15 +-
>> arch/arm/boot/compressed/efi-header.S | 111 ++++++++
>> arch/arm/boot/compressed/efi-stub.c | 448 +++++++++++++++++++++++++++++++++
>> arch/arm/boot/compressed/efi-stub.h | 5 +
>> arch/arm/boot/compressed/head.S | 90 ++++++-
>> 5 files changed, 661 insertions(+), 8 deletions(-)
>> create mode 100644 arch/arm/boot/compressed/efi-header.S
>> create mode 100644 arch/arm/boot/compressed/efi-stub.c
>> create mode 100644 arch/arm/boot/compressed/efi-stub.h
>>
>> diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
>> index 7ac1610..5fad8bd 100644
>> --- a/arch/arm/boot/compressed/Makefile
>> +++ b/arch/arm/boot/compressed/Makefile
>> @@ -103,11 +103,22 @@ libfdt_objs := $(addsuffix .o, $(basename $(libfdt)))
>> $(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/%
>> $(call cmd,shipped)
>>
>> -$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \
>> +$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o efi-stub.o): \
>> $(addprefix $(obj)/,$(libfdt_hdrs))
>>
>> ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
>> -OBJS += $(libfdt_objs) atags_to_fdt.o
>> +OBJS += atags_to_fdt.o
>> +USE_LIBFDT = y
>> +endif
>> +
>> +ifeq ($(CONFIG_EFI_STUB),y)
>> +CFLAGS_efi-stub.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
>> +OBJS += efi-stub.o
>> +USE_LIBFDT = y
>> +endif
>> +
>> +ifeq ($(USE_LIBFDT),y)
>> +OBJS += $(libfdt_objs)
>> endif
>>
>> targets := vmlinux vmlinux.lds \
>> diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S
>> new file mode 100644
>> index 0000000..6965e0f
>> --- /dev/null
>> +++ b/arch/arm/boot/compressed/efi-header.S
>> @@ -0,0 +1,111 @@
>> +@ Copyright (C) 2013 Linaro Ltd; <[email protected]>
>> +@
>> +@ This file contains the PE/COFF header that is part of the
>> +@ EFI stub.
>> +@
>> +
>> + .org 0x3c
>> + @
>> + @ The PE header can be anywhere in the file, but for
>> + @ simplicity we keep it together with the MSDOS header
>> + @ The offset to the PE/COFF header needs to be at offset
>> + @ 0x3C in the MSDOS header.
>> + @ The only 2 fields of the MSDOS header that are used are this
>> + @ PE/COFF offset, and the "MZ" bytes at offset 0x0.
>> + @
>> + .long pe_header @ Offset to the PE header.
>> +
>> + .align 3
>> +pe_header:
>> + .ascii "PE"
>> + .short 0
>> +
>> +coff_header:
>> + .short 0x01c2 @ ARM or Thumb
>> + .short 2 @ nr_sections
>> + .long 0 @ TimeDateStamp
>> + .long 0 @ PointerToSymbolTable
>> + .long 1 @ NumberOfSymbols
>> + .short section_table - optional_header @ SizeOfOptionalHeader
>> + .short 0x306 @ Characteristics.
>> + @ IMAGE_FILE_32BIT_MACHINE |
>> + @ IMAGE_FILE_DEBUG_STRIPPED |
>> + @ IMAGE_FILE_EXECUTABLE_IMAGE |
>> + @ IMAGE_FILE_LINE_NUMS_STRIPPED
>> +
>> +optional_header:
>> + .short 0x10b @ PE32 format
>> + .byte 0x02 @ MajorLinkerVersion
>> + .byte 0x14 @ MinorLinkerVersion
>> +
>> + .long _edata - efi_stub_entry @ SizeOfCode
>> +
>> + .long 0 @ SizeOfInitializedData
>> + .long 0 @ SizeOfUninitializedData
>> +
>> + .long efi_stub_entry @ AddressOfEntryPoint
>> + .long efi_stub_entry @ BaseOfCode
>> + .long 0 @ data
>> +
>> +extra_header_fields:
>> + .long 0 @ ImageBase
>> + .long 0x20 @ SectionAlignment
>> + .long 0x20 @ FileAlignment
>> + .short 0 @ MajorOperatingSystemVersion
>> + .short 0 @ MinorOperatingSystemVersion
>> + .short 0 @ MajorImageVersion
>> + .short 0 @ MinorImageVersion
>> + .short 0 @ MajorSubsystemVersion
>> + .short 0 @ MinorSubsystemVersion
>> + .long 0 @ Win32VersionValue
>> +
>> + .long _edata @ SizeOfImage
>> +
>> + @ Everything before the entry point is considered part of the header
>> + .long efi_stub_entry @ SizeOfHeaders
>> + .long 0 @ CheckSum
>> + .short 0xa @ Subsystem (EFI application)
>> + .short 0 @ DllCharacteristics
>> + .long 0 @ SizeOfStackReserve
>> + .long 0 @ SizeOfStackCommit
>> + .long 0 @ SizeOfHeapReserve
>> + .long 0 @ SizeOfHeapCommit
>> + .long 0 @ LoaderFlags
>> + .long 0x0 @ NumberOfRvaAndSizes
>> +
>> + # Section table
>> +section_table:
>> +
>> + #
>> + # The EFI application loader requires a relocation section
>> + # because EFI applications must be relocatable. This is a
>> + # dummy section as far as we are concerned.
>> + #
>> + .ascii ".reloc"
>> + .byte 0
>> + .byte 0 @ end of 0 padding of section name
>> + .long 0
>> + .long 0
>> + .long 0 @ SizeOfRawData
>> + .long 0 @ PointerToRawData
>> + .long 0 @ PointerToRelocations
>> + .long 0 @ PointerToLineNumbers
>> + .short 0 @ NumberOfRelocations
>> + .short 0 @ NumberOfLineNumbers
>> + .long 0x42100040 @ Characteristics (section flags)
>> +
>> +
>> + .ascii ".text"
>> + .byte 0
>> + .byte 0
>> + .byte 0 @ end of 0 padding of section name
>> + .long _edata - efi_stub_entry @ VirtualSize
>> + .long efi_stub_entry @ VirtualAddress
>> + .long _edata - efi_stub_entry @ SizeOfRawData
>> + .long efi_stub_entry @ PointerToRawData
>> +
>> + .long 0 @ PointerToRelocations (0 for executables)
>> + .long 0 @ PointerToLineNumbers (0 for executables)
>> + .short 0 @ NumberOfRelocations (0 for executables)
>> + .short 0 @ NumberOfLineNumbers (0 for executables)
>> + .long 0xe0500020 @ Characteristics (section flags)
>> diff --git a/arch/arm/boot/compressed/efi-stub.c b/arch/arm/boot/compressed/efi-stub.c
>> new file mode 100644
>> index 0000000..4fce68b
>> --- /dev/null
>> +++ b/arch/arm/boot/compressed/efi-stub.c
>> @@ -0,0 +1,448 @@
>> +/*
>> + * linux/arch/arm/boot/compressed/efi-stub.c
>> + *
>> + * Copyright (C) 2013 Linaro Ltd; <[email protected]>
>> + *
>> + * This file implements the EFI boot stub for the ARM kernel
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +#include <linux/efi.h>
>> +#include <libfdt.h>
>> +#include "efi-stub.h"
>> +
>> +/* EFI function call wrappers. These are not required for
>> + * ARM, but wrappers are required for X86 to convert between
>> + * ABIs. These wrappers are provided to allow code sharing
>> + * between X86 and ARM. Since these wrappers directly invoke the
>> + * EFI function pointer, the function pointer type must be properly
>> + * defined, which is not the case for X86 One advantage of this is
>> + * it allows for type checking of arguments, which is not
>> + * possible with the X86 wrappers.
>> + */
>> +#define efi_call_phys0(f) f()
>> +#define efi_call_phys1(f, a1) f(a1)
>> +#define efi_call_phys2(f, a1, a2) f(a1, a2)
>> +#define efi_call_phys3(f, a1, a2, a3) f(a1, a2, a3)
>> +#define efi_call_phys4(f, a1, a2, a3, a4) f(a1, a2, a3, a4)
>> +#define efi_call_phys5(f, a1, a2, a3, a4, a5) f(a1, a2, a3, a4, a5)
>> +
>> +/* The maximum uncompressed kernel size is 32 MBytes, so we will reserve
>> + * that for the decompressed kernel. We have no easy way to tell what
>> + * the actuall size of code + data the uncompressed kernel will use.
>> + */
>> +#define MAX_UNCOMP_KERNEL_SIZE 0x02000000
>> +
>> +/* The kernel zImage should be located between 32 Mbytes
>> + * and 128 MBytes from the base of DRAM. The min
>> + * address leaves space for a maximal size uncompressed image,
>> + * and the max address is due to how the zImage decompressor
>> + * picks a destination address.
>> + */
>> +#define ZIMAGE_OFFSET_LIMIT 0x08000000
>> +#define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE
>> +
>> +#define PRINTK_PREFIX "EFIstub: "
>> +
>> +struct fdt_region {
>> + u64 base;
>> + u64 size;
>> +};
>> +
>> +
>> +/* Include shared EFI stub code */
>> +#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
>> +
>> +static int relocate_kernel(efi_system_table_t *sys_table,
>> + unsigned long *zimage_addr,
>> + unsigned long zimage_size,
>> + unsigned long min_addr, unsigned long max_addr)
>> +{
>> + /* Get current address of kernel. */
>> + unsigned long cur_zimage_addr = *zimage_addr;
>> + unsigned long new_addr = 0;
>> +
>> + efi_status_t status;
>> +
>> + if (!zimage_addr || !zimage_size)
>> + return EFI_INVALID_PARAMETER;
>> +
>> + if (cur_zimage_addr > min_addr
>> + && (cur_zimage_addr + zimage_size) < max_addr) {
>> + /* We don't need to do anything, as kernel is at an
>> + * acceptable address already.
>> + */
>> + return EFI_SUCCESS;
>> + }
>> + /*
>> + * The EFI firmware loader could have placed the kernel image
>> + * anywhere in memory, but the kernel has restrictions on the
>> + * min and max physical address it can run at.
>> + */
>> + status = efi_low_alloc(sys_table, zimage_size, 0,
>> + &new_addr, min_addr);
>> + if (status != EFI_SUCCESS) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to allocate usable memory for kernel.\n");
>> + return status;
>> + }
>> +
>> + if (new_addr > (max_addr - zimage_size)) {
>> + efi_free(sys_table, zimage_size, new_addr);
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to allocate usable memory for kernel.\n");
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + /* 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 *)(unsigned long)cur_zimage_addr,
>> + zimage_size);
>> +
>> + /* Return the load address */
>> + *zimage_addr = new_addr;
>> +
>> + return status;
>> +}
>
> This function should be sharable with x86. ARM has more restrictions
> that x86, but I don't see any reason for them to be separate. ARM64 is
> certainly going to want to use some form of this too.
I'll look at sharing this with x86. x86 has the additional concept of
a preferred address
but other than that looks similar.
>
>> +
>> +
>> +/* 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 *convert_cmdline_to_ascii(efi_system_table_t *sys_table,
>> + efi_loaded_image_t *image,
>> + unsigned long *cmd_line_len,
>> + u32 max_addr)
>
> x86 has equivalent code. This function should be factored out and used
> by both.
I'll update x86 to use this.
>
>> +{
>> + u16 *s2;
>> + u8 *s1 = NULL;
>> + unsigned long cmdline_addr = 0;
>> + int load_options_size = image->load_options_size / 2; /* ASCII */
>> + void *options = (u16 *)image->load_options;
>
> load_options is already a void*. What is the cast here for?
Removed.
>
>> + int options_size = 0;
>> + int 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 */
>> +
>> + status = efi_high_alloc(sys_table, options_size, 0,
>> + &cmdline_addr, max_addr);
>> + if (status != EFI_SUCCESS)
>> + return NULL;
>> +
>> + s1 = (u8 *)(unsigned long)cmdline_addr;
>> + s2 = (u16 *)options;
>> +
>> + for (i = 0; i < options_size - 1; i++)
>> + *s1++ = *s2++;
>> +
>> + *s1 = '\0';
>> +
>> + *cmd_line_len = options_size;
>> + return (char *)(unsigned long)cmdline_addr;
>
> Double casting? That looks wrong. Why does the (unsigned long) bit need
> to be there?
Removed. likely a holdover from a version where that was a 64 bit type.
(see more on this below...)
>
>> +}
>> +
>> +
>> +static u32 update_fdt(efi_system_table_t *sys_table, void *orig_fdt, void *fdt,
>> + int new_fdt_size, char *cmdline_ptr, u64 initrd_addr,
>> + u64 initrd_size, efi_memory_desc_t *memory_map,
>> + int map_size, int desc_size)
>
> ARM64 will want access to this function.
I will move this to be shared. I have discussed with Leif making the
EFI FDT entries used by EFI runtime services 64 bit for
both ARM32/ARM64, so this function should be identical in both cases.
>
>> +{
>> + int node;
>> + int status;
>> + unsigned long fdt_val;
>> +
>> + status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
>> + if (status != 0)
>> + goto fdt_set_fail;
>> +
>> + node = fdt_subnode_offset(fdt, 0, "chosen");
>> + if (node < 0) {
>> + node = fdt_add_subnode(fdt, 0, "chosen");
>> + if (node < 0) {
>> + status = node; /* node is error code when negative */
>> + goto fdt_set_fail;
>> + }
>> + }
>> +
>> + if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) {
>> + status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
>> + strlen(cmdline_ptr) + 1);
>> + if (status)
>> + goto fdt_set_fail;
>> + }
>
> Some comments in this function would help poor readers like me.
I'll review and improve the commenting for this this function
>
>> +
>> + /* Set intird address/end in device tree, if present */
>> + if (initrd_size != 0) {
>> + u64 initrd_image_end;
>> + u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
>> + status = fdt_setprop(fdt, node, "linux,initrd-start",
>> + &initrd_image_start, sizeof(u64));
>> + if (status)
>> + goto fdt_set_fail;
>> + initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
>> + status = fdt_setprop(fdt, node, "linux,initrd-end",
>> + &initrd_image_end, sizeof(u64));
>> + if (status)
>> + goto fdt_set_fail;
>> + }
>> +
>> + /* Add FDT entries for EFI runtime services in chosen node. */
>> + node = fdt_subnode_offset(fdt, 0, "chosen");
>> + fdt_val = cpu_to_fdt32((unsigned long)sys_table);
>> + status = fdt_setprop(fdt, node, "efi-system-table",
>> + &fdt_val, sizeof(fdt_val));
>> + if (status)
>> + goto fdt_set_fail;
>> +
>> + fdt_val = cpu_to_fdt32(desc_size);
>> + status = fdt_setprop(fdt, node, "efi-mmap-desc-size",
>> + &fdt_val, sizeof(fdt_val));
>> + if (status)
>> + goto fdt_set_fail;
>> +
>> + fdt_val = cpu_to_fdt32(map_size);
>> + status = fdt_setprop(fdt, node, "efi-runtime-mmap-size",
>> + &fdt_val, sizeof(fdt_val));
>> + if (status)
>> + goto fdt_set_fail;
>> +
>> + fdt_val = cpu_to_fdt32((unsigned long)memory_map);
>> + status = fdt_setprop(fdt, node, "efi-runtime-mmap",
>> + &fdt_val, sizeof(fdt_val));
>> + if (status)
>> + goto fdt_set_fail;
>> +
>> + return EFI_SUCCESS;
>> +
>> +fdt_set_fail:
>> + if (status == -FDT_ERR_NOSPACE)
>> + return EFI_BUFFER_TOO_SMALL;
>> +
>> + return EFI_LOAD_ERROR;
>> +}
>> +
>> +
>> +
>> +int efi_entry(void *handle, efi_system_table_t *sys_table,
>> + unsigned long *zimage_addr)
>> +{
>> + efi_loaded_image_t *image;
>> + int status;
>> + unsigned long nr_pages;
>> + const struct fdt_region *region;
>> +
>> + void *fdt;
>> + int err;
>> + int node;
>> + unsigned long zimage_size = 0;
>> + unsigned long dram_base;
>> + /* addr/point and size pairs for memory management*/
>> + u64 initrd_addr;
>> + u64 initrd_size = 0;
>> + u64 fdt_addr;
>> + u64 fdt_size = 0;
>> + u64 kernel_reserve_addr;
>> + u64 kernel_reserve_size = 0;
>> + char *cmdline_ptr;
>> + unsigned long cmdline_size = 0;
>> +
>> + unsigned long map_size, desc_size;
>> + unsigned long mmap_key;
>> + efi_memory_desc_t *memory_map;
>> +
>> + unsigned long new_fdt_size;
>> + unsigned long new_fdt_addr;
>> +
>> + efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
>> +
>> + /* Check if we were booted by the EFI firmware */
>> + if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
>> + goto fail;
>> +
>> + efi_printk(sys_table, PRINTK_PREFIX"Booting Linux using EFI stub.\n");
>> +
>> +
>> + /* get the command line from EFI, using the LOADED_IMAGE protocol */
>> + status = efi_call_phys3(sys_table->boottime->handle_protocol,
>> + handle, &proto, (void *)&image);
>> + if (status != EFI_SUCCESS) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
>> + goto fail;
>> + }
>> +
>> + /* We are going to copy this into device tree, so we don't care where in
>> + * memory it is.
>> + */
>> + cmdline_ptr = convert_cmdline_to_ascii(sys_table, image,
>> + &cmdline_size, 0xFFFFFFFF);
>> + if (!cmdline_ptr) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: converting command line to ascii failed.\n");
>> + goto fail;
>> + }
>> +
>> + /* We first load the device tree, as we need to get the base address of
>> + * DRAM from the device tree. The zImage, device tree, and initrd
>> + * have address restrictions that are relative to the base of DRAM.
>> + */
>> + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "dtb=",
>> + 0xffffffff, &fdt_addr, &fdt_size);
>> + if (status != EFI_SUCCESS) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load device tree blob.\n");
>> + goto fail_free_cmdline;
>> + }
>> +
>> + err = fdt_check_header((void *)(unsigned long)fdt_addr);
>> + if (err != 0) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: device tree header not valid\n");
>> + goto fail_free_fdt;
>> + }
>> + if (fdt_totalsize((void *)(unsigned long)fdt_addr) > fdt_size) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Incomplete device tree.\n");
>> + goto fail_free_fdt;
>> +
>> + }
>> +
>> +
>> + /* Look up the base of DRAM from the device tree.*/
>> + fdt = (void *)(u32)fdt_addr;
>
> More double casting. This one might be legitimate, but you need to
> describe why. Is there any possibility that the FDT would appear above
> 4G?
It can't be above 4GiB. This highlights some inconsistencies in the
shared APIs that I need to clean up - some that
I added use u64 for passing addresses, which lead to casts like this.
I will change the new functions
to match the existing alloc/free to use native sizes, as this works
for the arm32 and x86 32 bit architectures
as well as the 64 bit ones. (The alternative is to move all the APIs
to u64/efi_phys_addr_t but this would be more intrusive
to the existing x86 code.)
>
>> + node = fdt_subnode_offset(fdt, 0, "memory");
>> + region = fdt_getprop(fdt, node, "reg", NULL);
>> + if (region) {
>> + dram_base = fdt64_to_cpu(region->base);
>> + } else {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: no 'memory' node in device tree.\n");
>> + goto fail_free_fdt;
>
> Shouldn't fail here. If there is no memory node then create one.
It would be good to do that, however I don't know of a way to get this
information using boot services.
This is available from within the UEFI firmware, but not exposed to
EFI applications as far as I can tell.
I think that the way to fix this is to have the UEFI firmware 'own'
the device tree and make it available to
the stub, after filling in platform specific stuff like this. I think
this goes along the lines of you have suggested
regarding adding a FDT protocol to UEFI.
>
>> + }
>> +
>> + /* Reserve memory for the uncompressed kernel image. */
>> + kernel_reserve_addr = dram_base;
>> + kernel_reserve_size = MAX_UNCOMP_KERNEL_SIZE;
>> + nr_pages = round_up(kernel_reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
>> + status = efi_call_phys4(sys_table->boottime->allocate_pages,
>> + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
>> + nr_pages, &kernel_reserve_addr);
>> + if (status != EFI_SUCCESS) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: unable to allocate memory for uncompressed kernel.\n");
>> + goto fail_free_fdt;
>> + }
>> +
>> + /* Relocate the zImage, if required. */
>> + zimage_size = image->image_size;
>> + status = relocate_kernel(sys_table, zimage_addr, zimage_size,
>> + dram_base + MIN_ZIMAGE_OFFSET,
>> + dram_base + ZIMAGE_OFFSET_LIMIT);
>> + if (status != EFI_SUCCESS) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Failed to relocate kernel\n");
>> + goto fail_free_kernel_reserve;
>> + }
>> +
>> + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=",
>> + dram_base + ZIMAGE_OFFSET_LIMIT,
>> + &initrd_addr, &initrd_size);
>> + if (status != EFI_SUCCESS) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to load initrd\n");
>> + goto fail_free_zimage;
>> + }
>> +
>> + /* Estimate size of new FDT, and allocate memory for it. We
>> + * will allocate a bigger buffer if this ends up being too
>> + * small, so a rough guess is OK here.*/
>> + new_fdt_size = fdt_size + cmdline_size + 0x200;
>> +
>> +fdt_alloc_retry:
>> + status = efi_high_alloc(sys_table, new_fdt_size, 0, &new_fdt_addr,
>> + dram_base + ZIMAGE_OFFSET_LIMIT);
>> + if (status != EFI_SUCCESS) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to allocate memory for new device tree.\n");
>> + goto fail_free_initrd;
>> + }
>> +
>> + /* Now that we have done our final memory allocation (and free)
>> + * we can get the memory map key needed
>> + * forexit_boot_services.*/
>> + status = efi_get_memory_map(sys_table, &memory_map, &map_size,
>> + &desc_size, &mmap_key);
>> + if (status != EFI_SUCCESS)
>> + goto fail_free_new_fdt;
>> +
>> + status = update_fdt(sys_table,
>> + fdt, (void *)new_fdt_addr, new_fdt_size,
>> + cmdline_ptr,
>> + initrd_addr, initrd_size,
>> + memory_map, map_size, desc_size);
>> +
>> + if (status != EFI_SUCCESS) {
>> + if (status == EFI_BUFFER_TOO_SMALL) {
>> + /* We need to allocate more space for the new
>> + * device tree, so free existing buffer that is
>> + * too small. Also free memory map, as we will need
>> + * to get new one that reflects the free/alloc we do
>> + * on the device tree buffer. */
>> + efi_free(sys_table, new_fdt_size, new_fdt_addr);
>> + efi_call_phys1(sys_table->boottime->free_pool,
>> + memory_map);
>> + new_fdt_size += new_fdt_size/4;
>> + goto fdt_alloc_retry;
>> + }
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: Unable to constuct new device tree.\n");
>> + goto fail_free_initrd;
>> + }
>> +
>> + /* Now we are ready to exit_boot_services.*/
>> + status = efi_call_phys2(sys_table->boottime->exit_boot_services,
>> + handle, mmap_key);
>> +
>> + if (status != EFI_SUCCESS) {
>> + efi_printk(sys_table, PRINTK_PREFIX"ERROR: exit boot services failed.\n");
>> + goto fail_free_mmap;
>> + }
>> +
>> +
>> + /* Now we need to return the FDT address to the calling
>> + * assembly to this can be used as part of normal boot.
>> + */
>> + return new_fdt_addr;
>> +
>> +fail_free_mmap:
>> + efi_call_phys1(sys_table->boottime->free_pool, memory_map);
>> +
>> +fail_free_new_fdt:
>> + efi_free(sys_table, new_fdt_size, new_fdt_addr);
>> +
>> +fail_free_initrd:
>> + efi_free(sys_table, initrd_size, initrd_addr);
>> +
>> +fail_free_zimage:
>> + efi_free(sys_table, zimage_size, *zimage_addr);
>> +
>> +fail_free_kernel_reserve:
>> + efi_free(sys_table, kernel_reserve_addr, kernel_reserve_size);
>> +
>> +fail_free_fdt:
>> + efi_free(sys_table, fdt_size, fdt_addr);
>> +
>> +fail_free_cmdline:
>> + efi_free(sys_table, cmdline_size, (u32)cmdline_ptr);
>> +
>> +fail:
>> + return EFI_STUB_ERROR;
>> +}
>> diff --git a/arch/arm/boot/compressed/efi-stub.h b/arch/arm/boot/compressed/efi-stub.h
>> new file mode 100644
>> index 0000000..0fe9376
>> --- /dev/null
>> +++ b/arch/arm/boot/compressed/efi-stub.h
>> @@ -0,0 +1,5 @@
>> +#ifndef _ARM_EFI_STUB_H
>> +#define _ARM_EFI_STUB_H
>> +/* Error code returned to ASM code instead of valid FDT address. */
>> +#define EFI_STUB_ERROR (~0)
>> +#endif
>> diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
>> index 75189f1..5401a3a 100644
>> --- a/arch/arm/boot/compressed/head.S
>> +++ b/arch/arm/boot/compressed/head.S
>> @@ -10,6 +10,7 @@
>> */
>> #include <linux/linkage.h>
>> #include <asm/assembler.h>
>> +#include "efi-stub.h"
>>
>> .arch armv7-a
>> /*
>> @@ -120,21 +121,99 @@
>> */
>> .align
>> .arm @ Always enter in ARM state
>> + .text
>> start:
>> .type start,#function
>> - .rept 7
>> +#ifdef CONFIG_EFI_STUB
>> + @ Magic MSDOS signature for PE/COFF + ADD opcode
>> + .word 0x62805a4d
>> +#else
>> + mov r0, r0
>> +#endif
>> + .rept 5
>> mov r0, r0
>> .endr
>> - ARM( mov r0, r0 )
>> - ARM( b 1f )
>> - THUMB( adr r12, BSYM(1f) )
>> - THUMB( bx r12 )
>> +
>> + adrl r12, BSYM(zimage_continue)
>> + ARM( mov pc, r12 )
>> + THUMB( bx r12 )
>> + @ zimage_continue will be in ARM or thumb mode as configured
>>
>> .word 0x016f2818 @ Magic numbers to help the loader
>> .word start @ absolute load/run zImage address
>> .word _edata @ zImage end address
>> +
>> +#ifdef CONFIG_EFI_STUB
>> + @ Portions of the MSDOS file header must be at offset
>> + @ 0x3c from the start of the file. All PE/COFF headers
>> + @ are kept contiguous for simplicity.
>> +#include "efi-header.S"
>> +
>> +efi_stub_entry:
>> + @ The EFI stub entry point is not at a fixed address, however
>> + @ this address must be set in the PE/COFF header.
>> + @ EFI entry point is in A32 mode, switch to T32 if configured.
>> + THUMB( adr r12, BSYM(1f) )
>> + THUMB( bx r12 )
>> THUMB( .thumb )
>> 1:
>> + @ Save lr on stack for possible return to EFI firmware.
>> + @ Don't care about fp, but need 64 bit alignment....
>> + stmfd sp!, {fp, lr}
>> +
>> + @ allocate space on stack for return of new entry point of
>> + @ zImage, as EFI stub may copy the kernel. Pass address
>> + @ of space in r2 - EFI stub will fill in the pointer.
>> +
>> + sub sp, sp, #8 @ we only need 4 bytes,
>> + @ but keep stack 8 byte aligned.
>> + mov r2, sp
>> + @ Pass our actual runtime start address in pointer data
>> + adr r11, LC0 @ address of LC0 at run time
>> + ldr r12, [r11, #0] @ address of LC0 at link time
>> +
>> + sub r3, r11, r12 @ calculate the delta offset
>> + str r3, [r2, #0]
>> + bl efi_entry
>> +
>> + @ get new zImage entry address from stack, put into r3
>> + ldr r3, [sp, #0]
>> + add sp, sp, #8 @ restore stack
>> +
>> + @ Check for error return from EFI stub
>> + mov r1, #EFI_STUB_ERROR
>> + cmp r0, r1
>> + beq efi_load_fail
>> +
>> +
>> + @ Save return values of efi_entry
>> + stmfd sp!, {r0, r3}
>> + bl cache_clean_flush
>> + bl cache_off
>> + ldmfd sp!, {r0, r3}
>> +
>> + @ Set parameters for booting zImage according to boot protocol
>> + @ put FDT address in r2, it was returned by efi_entry()
>> + @ r1 is FDT machine type, and r0 needs to be 0
>> + mov r2, r0
>> + mov r1, #0xFFFFFFFF
>> + mov r0, #0
>> +
>> + @ Branch to (possibly) relocated zImage that is in r3
>> + @ Make sure we are in A32 mode, as zImage requires
>> + THUMB( bx r3 )
>> + ARM( mov pc, r3 )
>> +
>> +efi_load_fail:
>> + @ Return EFI_LOAD_ERROR to EFI firmware on error.
>> + @ Switch back to ARM mode for EFI is done based on
>> + @ return address on stack
>> + ldr r0, =0x80000001
>> + ldmfd sp!, {fp, pc}
>> +#endif
>> +
>> + THUMB( .thumb )
>> +zimage_continue:
>> mrs r9, cpsr
>> #ifdef CONFIG_ARM_VIRT_EXT
>> bl __hyp_stub_install @ get into SVC mode, reversibly
>> @@ -167,7 +246,6 @@ not_angel:
>> * by the linker here, but it should preserve r7, r8, and r9.
>> */
>>
>> - .text
>>
>> #ifdef CONFIG_AUTO_ZRELADDR
>> @ determine final kernel image address
>> --
>> 1.7.10.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
>
On Fri, 23 Aug, at 03:40:04PM, Roy Franz wrote:
> Hi Matt,
>
> Do you have a tree I can monitor to see if you have taken this?
> Would you like me to split out the x86/common only changes into a
> separate series from the ARM changes?
I've just returned from my honeymoon. I'll reply to your emails asap.
--
Matt Fleming, Intel Open Source Technology Center
On Tue, 13 Aug, at 10:58:16AM, Roy Franz wrote:
> Hi Matt,
>
> Do you have any more feedback on the X86 and common code (patches
> 1-13) that needs to be addressed? Mark Salter has a working ARM64 EFI
> stub implemented based on these patches, so the common code has now
> been tested with another architecture, and he has acked these patches.
> If the current patches are OK, can this be queued for 3.12? (and into
> linux-next, if appropriate)
> The ARM portion may take a little longer based on the EFI runtime
> services patch dependencies, but getting the common code merged would
> allow the ARM64 EFI stub work to go forward independently.
>
> I can resend patches 1-13 as a new series of x86/common only changes
> if you would like.
I think resending the common patches as a new series, including Acked-by
and Reviewed-by tags, and after addressing Grant's comments is the best
idea.
We've missed the v3.12 merge window now, but we can certainly get these
into linux-next for some testing.
--
Matt Fleming, Intel Open Source Technology Center
On Mon, Sep 2, 2013 at 3:33 AM, Matt Fleming <[email protected]> wrote:
> On Tue, 13 Aug, at 10:58:16AM, Roy Franz wrote:
>> Hi Matt,
>>
>> Do you have any more feedback on the X86 and common code (patches
>> 1-13) that needs to be addressed? Mark Salter has a working ARM64 EFI
>> stub implemented based on these patches, so the common code has now
>> been tested with another architecture, and he has acked these patches.
>> If the current patches are OK, can this be queued for 3.12? (and into
>> linux-next, if appropriate)
>> The ARM portion may take a little longer based on the EFI runtime
>> services patch dependencies, but getting the common code merged would
>> allow the ARM64 EFI stub work to go forward independently.
>>
>> I can resend patches 1-13 as a new series of x86/common only changes
>> if you would like.
>
> I think resending the common patches as a new series, including Acked-by
> and Reviewed-by tags, and after addressing Grant's comments is the best
> idea.
>
> We've missed the v3.12 merge window now, but we can certainly get these
> into linux-next for some testing.
>
> --
> Matt Fleming, Intel Open Source Technology Center
Thanks Matt - I'll split the common patches out to a new series and resubmit
after taking care of Grant's feeback.
Thanks,
Roy