aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2018-12-03 17:52:40 -0500
committerTom Rini <trini@konsulko.com>2018-12-03 17:52:40 -0500
commitf388e3bed7318efe97058b673801dda6f563d319 (patch)
treeed391f6b8cfad1bc53dabeb7239ffcc716a8ca4e
parentec0d0d8742df12a4c0d3e8382b77c0672cd4aab6 (diff)
parent1a82b3413cb577cd52cf8a1dc22dd306e4ce0772 (diff)
downloadu-boot-f388e3bed7318efe97058b673801dda6f563d319.zip
u-boot-f388e3bed7318efe97058b673801dda6f563d319.tar.gz
u-boot-f388e3bed7318efe97058b673801dda6f563d319.tar.bz2
Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot
Patch queue for efi - 2018-12-03 This release is fully packed with lots of glorious improvements in UEFI land again! - Make PE images more standards compliant - Improve sandbox support - Improve correctness - Fix RISC-V execution on virt model - Honor board defined top of ram (fixes a few boards) - Imply DM USB access when distro boot is available - Code cleanups
-rw-r--r--Kconfig1
-rw-r--r--MAINTAINERS3
-rw-r--r--arch/arm/cpu/armv7/smccc-call.S2
-rw-r--r--arch/arm/cpu/armv8/Kconfig1
-rw-r--r--arch/arm/cpu/armv8/fwcall.c52
-rw-r--r--arch/arm/cpu/armv8/smccc-call.S2
-rw-r--r--arch/arm/lib/crt0_aarch64_efi.S12
-rw-r--r--arch/arm/lib/crt0_arm_efi.S16
-rw-r--r--arch/riscv/lib/crt0_riscv_efi.S12
-rw-r--r--arch/x86/config.mk4
-rw-r--r--cmd/bootefi.c244
-rw-r--r--common/board_r.c3
-rw-r--r--common/fdt_support.c3
-rw-r--r--configs/vf610twr_defconfig2
-rw-r--r--configs/vf610twr_nand_defconfig2
-rw-r--r--doc/README.iscsi35
-rw-r--r--drivers/firmware/psci.c100
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--fs/fs.c1
-rw-r--r--include/asm-generic/pe.h18
-rw-r--r--include/common.h11
-rw-r--r--include/efi.h2
-rw-r--r--include/efi_api.h14
-rw-r--r--include/efi_loader.h73
-rw-r--r--include/efi_selftest.h2
-rw-r--r--include/linux/psci.h6
-rw-r--r--lib/Makefile2
-rw-r--r--lib/efi/efi.c2
-rw-r--r--lib/efi_loader/efi_bootmgr.c95
-rw-r--r--lib/efi_loader/efi_boottime.c191
-rw-r--r--lib/efi_loader/efi_console.c24
-rw-r--r--lib/efi_loader/efi_device_path.c75
-rw-r--r--lib/efi_loader/efi_device_path_to_text.c8
-rw-r--r--lib/efi_loader/efi_disk.c42
-rw-r--r--lib/efi_loader/efi_file.c2
-rw-r--r--lib/efi_loader/efi_gop.c32
-rw-r--r--lib/efi_loader/efi_memory.c85
-rw-r--r--lib/efi_loader/efi_net.c444
-rw-r--r--lib/efi_loader/efi_runtime.c13
-rw-r--r--lib/efi_loader/efi_smbios.c20
-rw-r--r--lib/efi_loader/helloworld.c40
-rw-r--r--lib/efi_selftest/Kconfig2
-rw-r--r--lib/efi_selftest/Makefile12
-rw-r--r--lib/efi_selftest/efi_selftest.c31
-rw-r--r--lib/efi_selftest/efi_selftest_config_table.c12
-rw-r--r--lib/efi_selftest/efi_selftest_controllers.c2
-rw-r--r--lib/efi_selftest/efi_selftest_crc32.c4
-rw-r--r--lib/efi_selftest/efi_selftest_devicepath.c2
-rw-r--r--lib/efi_selftest/efi_selftest_event_groups.c4
-rw-r--r--lib/efi_selftest/efi_selftest_events.c2
-rw-r--r--lib/efi_selftest/efi_selftest_exception.c50
-rw-r--r--lib/efi_selftest/efi_selftest_fdt.c2
-rw-r--r--lib/efi_selftest/efi_selftest_loaded_image.c2
-rw-r--r--lib/efi_selftest/efi_selftest_manageprotocols.c18
-rw-r--r--lib/efi_selftest/efi_selftest_memory.c187
-rw-r--r--lib/efi_selftest/efi_selftest_snp.c16
-rw-r--r--lib/efi_selftest/efi_selftest_textinput.c2
-rw-r--r--lib/efi_selftest/efi_selftest_tpl.c2
-rw-r--r--lib/efi_selftest/efi_selftest_unicode_collation.c6
-rw-r--r--lib/efi_selftest/efi_selftest_variables.c6
-rw-r--r--lib/efi_selftest/efi_selftest_watchdog.c2
-rw-r--r--lib/fdtdec.c6
-rw-r--r--lib/smbios.c52
-rw-r--r--scripts/Makefile.lib2
-rw-r--r--test/py/tests/test_efi_selftest.py10
65 files changed, 1549 insertions, 582 deletions
diff --git a/Kconfig b/Kconfig
index 3120553..42672a9 100644
--- a/Kconfig
+++ b/Kconfig
@@ -86,6 +86,7 @@ config DISTRO_DEFAULTS
select SUPPORT_RAW_INITRD
select SYS_LONGHELP
imply CMD_MII if NET
+ imply USB_STORAGE
imply USE_BOOTCOMMAND
help
Select this to enable various options and commands which are suitable
diff --git a/MAINTAINERS b/MAINTAINERS
index 214629e..8ea8ef9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2,6 +2,8 @@ Descriptions of section entries:
P: Person (obsolete)
M: Mail patches to: FullName <address@domain>
+ R: Designated reviewer: FullName <address@domain>
+ These reviewers should be CCed on patches.
L: Mailing list that is relevant to this area
W: Web-page with status/info
Q: Patchwork web based patch tracking system site
@@ -414,6 +416,7 @@ F: test/dm/
EFI PAYLOAD
M: Alexander Graf <agraf@suse.de>
+R: Heinrich Schuchardt <xypron.glpk@gmx.de>
S: Maintained
T: git git://github.com/agraf/u-boot.git
F: doc/README.uefi
diff --git a/arch/arm/cpu/armv7/smccc-call.S b/arch/arm/cpu/armv7/smccc-call.S
index 0d8b59e..eae69e3 100644
--- a/arch/arm/cpu/armv7/smccc-call.S
+++ b/arch/arm/cpu/armv7/smccc-call.S
@@ -7,6 +7,8 @@
#include <asm/opcodes-sec.h>
#include <asm/opcodes-virt.h>
+ .section .text.efi_runtime
+
#define UNWIND(x...)
/*
* Wrap c macros in asm macros to delay expansion until after the
diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig
index ff42791..1c12bbd 100644
--- a/arch/arm/cpu/armv8/Kconfig
+++ b/arch/arm/cpu/armv8/Kconfig
@@ -96,6 +96,7 @@ endmenu
config PSCI_RESET
bool "Use PSCI for reset and shutdown"
default y
+ select ARM_SMCCC if OF_CONTROL
depends on !ARCH_EXYNOS7 && !ARCH_BCM283X && \
!TARGET_LS2080A_SIMU && !TARGET_LS2080AQDS && \
!TARGET_LS2080ARDB && !TARGET_LS2080A_EMU && \
diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c
index 0ba3dad..9957c29 100644
--- a/arch/arm/cpu/armv8/fwcall.c
+++ b/arch/arm/cpu/armv8/fwcall.c
@@ -7,7 +7,6 @@
#include <asm-offsets.h>
#include <config.h>
-#include <efi_loader.h>
#include <version.h>
#include <asm/macro.h>
#include <asm/psci.h>
@@ -19,7 +18,7 @@
* x0~x7: input arguments
* x0~x3: output arguments
*/
-static void __efi_runtime hvc_call(struct pt_regs *args)
+static void hvc_call(struct pt_regs *args)
{
asm volatile(
"ldr x0, %0\n"
@@ -53,7 +52,7 @@ static void __efi_runtime hvc_call(struct pt_regs *args)
* x0~x3: output arguments
*/
-void __efi_runtime smc_call(struct pt_regs *args)
+void smc_call(struct pt_regs *args)
{
asm volatile(
"ldr x0, %0\n"
@@ -83,9 +82,9 @@ void __efi_runtime smc_call(struct pt_regs *args)
* use PSCI on U-Boot running below a hypervisor, please detect
* this and set the flag accordingly.
*/
-static const __efi_runtime_data bool use_smc_for_psci = true;
+static const bool use_smc_for_psci = true;
-void __noreturn __efi_runtime psci_system_reset(void)
+void __noreturn psci_system_reset(void)
{
struct pt_regs regs;
@@ -100,7 +99,7 @@ void __noreturn __efi_runtime psci_system_reset(void)
;
}
-void __noreturn __efi_runtime psci_system_off(void)
+void __noreturn psci_system_off(void)
{
struct pt_regs regs;
@@ -114,44 +113,3 @@ void __noreturn __efi_runtime psci_system_off(void)
while (1)
;
}
-
-#ifdef CONFIG_CMD_POWEROFF
-int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
- puts("poweroff ...\n");
-
- udelay(50000); /* wait 50 ms */
-
- disable_interrupts();
-
- psci_system_off();
-
- /*NOTREACHED*/
- return 0;
-}
-#endif
-
-#ifdef CONFIG_PSCI_RESET
-void reset_misc(void)
-{
- psci_system_reset();
-}
-
-#ifdef CONFIG_EFI_LOADER
-void __efi_runtime EFIAPI efi_reset_system(
- enum efi_reset_type reset_type,
- efi_status_t reset_status,
- unsigned long data_size, void *reset_data)
-{
- if (reset_type == EFI_RESET_COLD ||
- reset_type == EFI_RESET_WARM ||
- reset_type == EFI_RESET_PLATFORM_SPECIFIC) {
- psci_system_reset();
- } else if (reset_type == EFI_RESET_SHUTDOWN) {
- psci_system_off();
- }
-
- while (1) { }
-}
-#endif /* CONFIG_EFI_LOADER */
-#endif /* CONFIG_PSCI_RESET */
diff --git a/arch/arm/cpu/armv8/smccc-call.S b/arch/arm/cpu/armv8/smccc-call.S
index 16c9e29..86de4b4 100644
--- a/arch/arm/cpu/armv8/smccc-call.S
+++ b/arch/arm/cpu/armv8/smccc-call.S
@@ -6,6 +6,8 @@
#include <linux/arm-smccc.h>
#include <generated/asm-offsets.h>
+ .section .text.efi_runtime
+
.macro SMCCC instr
.cfi_startproc
\instr #0
diff --git a/arch/arm/lib/crt0_aarch64_efi.S b/arch/arm/lib/crt0_aarch64_efi.S
index 0db4360..cb205fa 100644
--- a/arch/arm/lib/crt0_aarch64_efi.S
+++ b/arch/arm/lib/crt0_aarch64_efi.S
@@ -28,13 +28,13 @@ coff_header:
.short 2 /* nr_sections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
- .long 1 /* NumberOfSymbols */
+ .long 0 /* NumberOfSymbols */
.short section_table - optional_header /* SizeOfOptionalHeader */
- /*
- * Characteristics: IMAGE_FILE_DEBUG_STRIPPED |
- * IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED
- */
- .short 0x206
+ /* Characteristics */
+ .short (IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED | \
+ IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
+ IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
.short 0x20b /* PE32+ format */
.byte 0x02 /* MajorLinkerVersion */
diff --git a/arch/arm/lib/crt0_arm_efi.S b/arch/arm/lib/crt0_arm_efi.S
index 23db49f..5470e2f 100644
--- a/arch/arm/lib/crt0_arm_efi.S
+++ b/arch/arm/lib/crt0_arm_efi.S
@@ -27,16 +27,16 @@ coff_header:
.short 2 /* nr_sections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
- .long 1 /* NumberOfSymbols */
+ .long 0 /* NumberOfSymbols */
.short section_table - optional_header /* SizeOfOptionalHeader */
- /*
- * Characteristics: IMAGE_FILE_32BIT_MACHINE |
- * IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
- * IMAGE_FILE_LINE_NUMS_STRIPPED
- */
- .short 0x306
+ /* Characteristics */
+ .short (IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED | \
+ IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
+ IMAGE_FILE_32BIT_MACHINE | \
+ IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
- .short 0x10b /* PE32+ format */
+ .short 0x10b /* PE32 format */
.byte 0x02 /* MajorLinkerVersion */
.byte 0x14 /* MinorLinkerVersion */
.long _edata - _start /* SizeOfCode */
diff --git a/arch/riscv/lib/crt0_riscv_efi.S b/arch/riscv/lib/crt0_riscv_efi.S
index 18f61f5..b7b5329 100644
--- a/arch/riscv/lib/crt0_riscv_efi.S
+++ b/arch/riscv/lib/crt0_riscv_efi.S
@@ -41,13 +41,13 @@ coff_header:
.short 2 /* nr_sections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
- .long 1 /* NumberOfSymbols */
+ .long 0 /* NumberOfSymbols */
.short section_table - optional_header /* SizeOfOptionalHeader */
- /*
- * Characteristics: IMAGE_FILE_DEBUG_STRIPPED |
- * IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED
- */
- .short 0x206
+ /* Characteristics */
+ .short (IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED | \
+ IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
+ IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
.short 0x20b /* PE32+ format */
.byte 0x02 /* MajorLinkerVersion */
diff --git a/arch/x86/config.mk b/arch/x86/config.mk
index 8151e47..b5e8f46 100644
--- a/arch/x86/config.mk
+++ b/arch/x86/config.mk
@@ -34,7 +34,7 @@ PLATFORM_LDFLAGS += -m $(if $(IS_32BIT),elf_i386,elf_x86_64)
# This is used in the top-level Makefile which does not include
# PLATFORM_LDFLAGS
-LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined
+LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined -s
OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
-j .rel -j .rela -j .reloc
@@ -65,7 +65,7 @@ CPPFLAGS_crt0-efi-$(EFIARCH).o += $(CFLAGS_EFI)
ifeq ($(CONFIG_EFI_APP),y)
PLATFORM_CPPFLAGS += $(CFLAGS_EFI)
-LDFLAGS_FINAL += -znocombreloc -shared
+LDFLAGS_FINAL += -znocombreloc -shared -s
LDSCRIPT := $(LDSCRIPT_EFI)
else
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 4d68d80..38679ff 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -148,16 +148,16 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info,
/**
* copy_fdt() - Copy the device tree to a new location available to EFI
*
- * The FDT is relocated into a suitable location within the EFI memory map.
- * An additional 12KB is added to the space in case the device tree needs to be
+ * The FDT is copied to a suitable location within the EFI memory map.
+ * Additional 12 KiB are added to the space in case the device tree needs to be
* expanded later with fdt_open_into().
*
- * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated
- * FDT start
- * @fdt_sizep: Returns new size of FDT, including
- * @return new relocated address of FDT
+ * @fdtp: On entry a pointer to the flattened device tree.
+ * On exit a pointer to the copy of the flattened device tree.
+ * FDT start
+ * Return: status code
*/
-static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
+static efi_status_t copy_fdt(void **fdtp)
{
unsigned long fdt_ram_start = -1L, fdt_pages;
efi_status_t ret = 0;
@@ -178,17 +178,19 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
}
/*
- * Give us at least 4KB of breathing room in case the device tree needs
- * to be expanded later. Round up to the nearest EFI page boundary.
+ * Give us at least 12 KiB of breathing room in case the device tree
+ * needs to be expanded later.
*/
- fdt = map_sysmem(*fdt_addrp, 0);
- fdt_size = fdt_totalsize(fdt);
- fdt_size += 4096 * 3;
- fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE);
- fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
-
- /* Safe fdt location is at 127MB */
- new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size;
+ fdt = *fdtp;
+ fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
+ fdt_size = fdt_pages << EFI_PAGE_SHIFT;
+
+ /*
+ * Safe fdt location is at 127 MiB.
+ * On the sandbox convert from the sandbox address space.
+ */
+ new_fdt_addr = (uintptr_t)map_sysmem(fdt_ram_start + 0x7f00000 +
+ fdt_size, 0);
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
EFI_RUNTIME_SERVICES_DATA, fdt_pages,
&new_fdt_addr);
@@ -203,13 +205,11 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
goto done;
}
}
-
- new_fdt = map_sysmem(new_fdt_addr, fdt_size);
+ new_fdt = (void *)(uintptr_t)new_fdt_addr;
memcpy(new_fdt, fdt, fdt_totalsize(fdt));
fdt_set_totalsize(new_fdt, fdt_size);
- *fdt_addrp = new_fdt_addr;
- *fdt_sizep = fdt_size;
+ *fdtp = (void *)(uintptr_t)new_fdt_addr;
done:
return ret;
}
@@ -277,7 +277,11 @@ static void efi_carve_out_dt_rsv(void *fdt)
if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
continue;
- pages = ALIGN(size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT;
+ /* Convert from sandbox address space. */
+ addr = (uintptr_t)map_sysmem(addr, 0);
+
+ pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
+ addr &= ~EFI_PAGE_MASK;
if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
false))
printf("FDT memrsv map %d: Failed to add to map\n", i);
@@ -287,7 +291,6 @@ static void efi_carve_out_dt_rsv(void *fdt)
static efi_status_t efi_install_fdt(ulong fdt_addr)
{
bootm_headers_t img = { 0 };
- ulong fdt_pages, fdt_size, fdt_start;
efi_status_t ret;
void *fdt;
@@ -297,34 +300,58 @@ static efi_status_t efi_install_fdt(ulong fdt_addr)
return EFI_INVALID_PARAMETER;
}
+ /* Create memory reservation as indicated by the device tree */
+ efi_carve_out_dt_rsv(fdt);
+
/* Prepare fdt for payload */
- ret = copy_fdt(&fdt_addr, &fdt_size);
+ ret = copy_fdt(&fdt);
if (ret)
return ret;
- unmap_sysmem(fdt);
- fdt = map_sysmem(fdt_addr, 0);
- fdt_size = fdt_totalsize(fdt);
if (image_setup_libfdt(&img, fdt, 0, NULL)) {
printf("ERROR: failed to process device tree\n");
return EFI_LOAD_ERROR;
}
- efi_carve_out_dt_rsv(fdt);
-
/* Link to it in the efi tables */
ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
if (ret != EFI_SUCCESS)
return EFI_OUT_OF_RESOURCES;
- /* And reserve the space in the memory map */
- fdt_start = fdt_addr;
- fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
+ return ret;
+}
+
+static efi_status_t bootefi_run_prepare(const char *load_options_path,
+ struct efi_device_path *device_path,
+ struct efi_device_path *image_path,
+ struct efi_loaded_image_obj **image_objp,
+ struct efi_loaded_image **loaded_image_infop)
+{
+ efi_status_t ret;
- ret = efi_add_memory_map(fdt_start, fdt_pages,
- EFI_BOOT_SERVICES_DATA, true);
+ ret = efi_setup_loaded_image(device_path, image_path, image_objp,
+ loaded_image_infop);
+ if (ret != EFI_SUCCESS)
+ return ret;
- return ret;
+ /* Transfer environment variable as load options */
+ set_load_options(*loaded_image_infop, load_options_path);
+
+ return 0;
+}
+
+/**
+ * bootefi_run_finish() - finish up after running an EFI test
+ *
+ * @loaded_image_info: Pointer to a struct which holds the loaded image info
+ * @image_objj: Pointer to a struct which holds the loaded image object
+ */
+static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj,
+ struct efi_loaded_image *loaded_image_info)
+{
+ efi_restore_gd();
+ free(loaded_image_info->load_options);
+ efi_delete_handle(&image_obj->header);
}
/**
@@ -345,7 +372,7 @@ static efi_status_t do_bootefi_exec(void *efi,
efi_handle_t mem_handle = NULL;
struct efi_device_path *memdp = NULL;
efi_status_t ret;
- struct efi_loaded_image_obj *image_handle = NULL;
+ struct efi_loaded_image_obj *image_obj = NULL;
struct efi_loaded_image *loaded_image_info = NULL;
EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
@@ -354,7 +381,7 @@ static efi_status_t do_bootefi_exec(void *efi,
/*
* Special case for efi payload not loaded from disk, such as
* 'bootefi hello' or for example payload loaded directly into
- * memory via jtag, etc:
+ * memory via JTAG, etc:
*/
if (!device_path && !image_path) {
printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
@@ -367,27 +394,25 @@ static efi_status_t do_bootefi_exec(void *efi,
*/
ret = efi_create_handle(&mem_handle);
if (ret != EFI_SUCCESS)
- goto exit;
+ return ret; /* TODO: leaks device_path */
ret = efi_add_protocol(mem_handle, &efi_guid_device_path,
device_path);
if (ret != EFI_SUCCESS)
- goto exit;
+ goto err_add_protocol;
} else {
assert(device_path && image_path);
}
- ret = efi_setup_loaded_image(device_path, image_path, &image_handle,
- &loaded_image_info);
- if (ret != EFI_SUCCESS)
- goto exit;
+ ret = bootefi_run_prepare("bootargs", device_path, image_path,
+ &image_obj, &loaded_image_info);
+ if (ret)
+ goto err_prepare;
- /* Transfer environment variable bootargs as load options */
- set_load_options(loaded_image_info, "bootargs");
/* Load the EFI payload */
- entry = efi_load_pe(image_handle, efi, loaded_image_info);
+ entry = efi_load_pe(image_obj, efi, loaded_image_info);
if (!entry) {
ret = EFI_LOAD_ERROR;
- goto exit;
+ goto err_prepare;
}
if (memdp) {
@@ -405,9 +430,9 @@ static efi_status_t do_bootefi_exec(void *efi,
/* Call our payload! */
debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
- if (setjmp(&image_handle->exit_jmp)) {
- ret = image_handle->exit_status;
- goto exit;
+ if (setjmp(&image_obj->exit_jmp)) {
+ ret = image_obj->exit_status;
+ goto err_prepare;
}
#ifdef CONFIG_ARM64
@@ -418,7 +443,7 @@ static efi_status_t do_bootefi_exec(void *efi,
/* Move into EL2 and keep running there */
armv8_switch_to_el2((ulong)entry,
- (ulong)image_handle,
+ (ulong)&image_obj->header,
(ulong)&systab, 0, (ulong)efi_run_in_el2,
ES_TO_AARCH64);
@@ -435,7 +460,7 @@ static efi_status_t do_bootefi_exec(void *efi,
secure_ram_addr(_do_nonsec_entry)(
efi_run_in_hyp,
(uintptr_t)entry,
- (uintptr_t)image_handle,
+ (uintptr_t)&image_obj->header,
(uintptr_t)&systab);
/* Should never reach here, efi exits with longjmp */
@@ -443,18 +468,59 @@ static efi_status_t do_bootefi_exec(void *efi,
}
#endif
- ret = efi_do_enter(image_handle, &systab, entry);
+ ret = efi_do_enter(&image_obj->header, &systab, entry);
-exit:
+err_prepare:
/* image has returned, loaded-image obj goes *poof*: */
- if (image_handle)
- efi_delete_handle(&image_handle->parent);
+ bootefi_run_finish(image_obj, loaded_image_info);
+
+err_add_protocol:
if (mem_handle)
efi_delete_handle(mem_handle);
return ret;
}
+#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
+/**
+ * bootefi_test_prepare() - prepare to run an EFI test
+ *
+ * This sets things up so we can call EFI functions. This involves preparing
+ * the 'gd' pointer and setting up the load ed image data structures.
+ *
+ * @image_objp: loaded_image_infop: Pointer to a struct which will hold the
+ * loaded image object. This struct will be inited by this function before
+ * use.
+ * @loaded_image_infop: Pointer to a struct which will hold the loaded image
+ * info. This struct will be inited by this function before use.
+ * @path: File path to the test being run (often just the test name with a
+ * backslash before it
+ * @test_func: Address of the test function that is being run
+ * @load_options_path: U-Boot environment variable to use as load options
+ * @return 0 if OK, -ve on error
+ */
+static efi_status_t bootefi_test_prepare
+ (struct efi_loaded_image_obj **image_objp,
+ struct efi_loaded_image **loaded_image_infop, const char *path,
+ ulong test_func, const char *load_options_path)
+{
+ /* Construct a dummy device path */
+ bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
+ (uintptr_t)test_func,
+ (uintptr_t)test_func);
+ if (!bootefi_device_path)
+ return EFI_OUT_OF_RESOURCES;
+ bootefi_image_path = efi_dp_from_file(NULL, 0, path);
+ if (!bootefi_image_path)
+ return EFI_OUT_OF_RESOURCES;
+
+ return bootefi_run_prepare(load_options_path, bootefi_device_path,
+ bootefi_image_path, image_objp,
+ loaded_image_infop);
+}
+
+#endif /* CONFIG_CMD_BOOTEFI_SELFTEST */
+
static int do_bootefi_bootmgr_exec(void)
{
struct efi_device_path *device_path, *file_path;
@@ -527,29 +593,17 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
#endif
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
if (!strcmp(argv[1], "selftest")) {
- struct efi_loaded_image_obj *image_handle;
+ struct efi_loaded_image_obj *image_obj;
struct efi_loaded_image *loaded_image_info;
- /* Construct a dummy device path. */
- bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
- (uintptr_t)&efi_selftest,
- (uintptr_t)&efi_selftest);
- bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest");
-
- r = efi_setup_loaded_image(bootefi_device_path,
- bootefi_image_path, &image_handle,
- &loaded_image_info);
- if (r != EFI_SUCCESS)
+ if (bootefi_test_prepare(&image_obj, &loaded_image_info,
+ "\\selftest", (uintptr_t)&efi_selftest,
+ "efi_selftest"))
return CMD_RET_FAILURE;
- efi_save_gd();
- /* Transfer environment variable efi_selftest as load options */
- set_load_options(loaded_image_info, "efi_selftest");
/* Execute the test */
- r = efi_selftest(image_handle, &systab);
- efi_restore_gd();
- free(loaded_image_info->load_options);
- efi_delete_handle(&image_handle->parent);
+ r = efi_selftest(&image_obj->header, &systab);
+ bootefi_run_finish(image_obj, loaded_image_info);
return r != EFI_SUCCESS;
} else
#endif
@@ -608,45 +662,19 @@ U_BOOT_CMD(
void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
{
- char filename[32] = { 0 }; /* dp->str is u16[32] long */
- char *s;
+ struct efi_device_path *device, *image;
+ efi_status_t ret;
/* efi_set_bootdev is typically called repeatedly, recover memory */
efi_free_pool(bootefi_device_path);
efi_free_pool(bootefi_image_path);
- /* If blk_get_device_part_str fails, avoid duplicate free. */
- bootefi_device_path = NULL;
- bootefi_image_path = NULL;
-
- if (strcmp(dev, "Net")) {
- struct blk_desc *desc;
- disk_partition_t fs_partition;
- int part;
-
- part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
- 1);
- if (part < 0)
- return;
-
- bootefi_device_path = efi_dp_from_part(desc, part);
- } else {
-#ifdef CONFIG_NET
- bootefi_device_path = efi_dp_from_eth();
-#endif
- }
-
- if (!path)
- return;
- if (strcmp(dev, "Net")) {
- /* Add leading / to fs paths, because they're absolute */
- snprintf(filename, sizeof(filename), "/%s", path);
+ ret = efi_dp_from_name(dev, devnr, path, &device, &image);
+ if (ret == EFI_SUCCESS) {
+ bootefi_device_path = device;
+ bootefi_image_path = image;
} else {
- snprintf(filename, sizeof(filename), "%s", path);
+ bootefi_device_path = NULL;
+ bootefi_image_path = NULL;
}
- /* DOS style file path: */
- s = filename;
- while ((s = strchr(s, '/')))
- *s++ = '\\';
- bootefi_image_path = efi_dp_from_file(NULL, 0, filename);
}
diff --git a/common/board_r.c b/common/board_r.c
index 0c2129b..21d3b3c 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -453,7 +453,8 @@ static int initr_env(void)
else
set_default_env(NULL, 0);
#ifdef CONFIG_OF_CONTROL
- env_set_addr("fdtcontroladdr", gd->fdt_blob);
+ env_set_hex("fdtcontroladdr",
+ (unsigned long)map_to_sysmem(gd->fdt_blob));
#endif
/* Initialize from environment */
diff --git a/common/fdt_support.c b/common/fdt_support.c
index e6daa67..3440e42 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -7,6 +7,7 @@
*/
#include <common.h>
+#include <mapmem.h>
#include <stdio_dev.h>
#include <linux/ctype.h>
#include <linux/types.h>
@@ -633,7 +634,7 @@ int fdt_shrink_to_minimum(void *blob, uint extrasize)
fdt_set_totalsize(blob, actualsize);
/* Add the new reservation */
- ret = fdt_add_mem_rsv(blob, (uintptr_t)blob, actualsize);
+ ret = fdt_add_mem_rsv(blob, map_to_sysmem(blob), actualsize);
if (ret < 0)
return ret;
diff --git a/configs/vf610twr_defconfig b/configs/vf610twr_defconfig
index a928cd4..504eebb 100644
--- a/configs/vf610twr_defconfig
+++ b/configs/vf610twr_defconfig
@@ -41,4 +41,4 @@ CONFIG_PHY_MICREL=y
CONFIG_MII=y
CONFIG_DM_SERIAL=y
CONFIG_FSL_LPUART=y
-# CONFIG_EFI_UNICODE_CAPITALIZATION is not set
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/vf610twr_nand_defconfig b/configs/vf610twr_nand_defconfig
index 560776f..0a1e28e 100644
--- a/configs/vf610twr_nand_defconfig
+++ b/configs/vf610twr_nand_defconfig
@@ -41,4 +41,4 @@ CONFIG_PHY_MICREL=y
CONFIG_MII=y
CONFIG_DM_SERIAL=y
CONFIG_FSL_LPUART=y
-# CONFIG_EFI_UNICODE_CAPITALIZATION is not set
+# CONFIG_EFI_LOADER is not set
diff --git a/doc/README.iscsi b/doc/README.iscsi
index faee636..3a12438 100644
--- a/doc/README.iscsi
+++ b/doc/README.iscsi
@@ -1,8 +1,6 @@
-iSCSI booting with U-Boot and iPXE
-==================================
+# iSCSI booting with U-Boot and iPXE
-Motivation
-----------
+## Motivation
U-Boot has only a reduced set of supported network protocols. The focus for
network booting has been on UDP based protocols. A TCP stack and HTTP support
@@ -41,8 +39,7 @@ fine grained control of the boot process and can provide a command shell.
iPXE can be built as an EFI application (named snp.efi) which can be loaded and
run by U-Boot.
-Boot sequence
--------------
+## Boot sequence
U-Boot loads the EFI application iPXE snp.efi using the bootefi command. This
application has network access via the simple network protocol offered by
@@ -106,19 +103,16 @@ the EFI stub Linux is called as an EFI application::
| |
| ~ ~ ~ ~|
-Security
---------
+## Security
The iSCSI protocol is not encrypted. The traffic could be secured using IPsec
but neither U-Boot nor iPXE does support this. So we should at least separate
the iSCSI traffic from all other network traffic. This can be achieved using a
virtual local area network (VLAN).
-Configuration
--------------
+## Configuration
-iPXE
-^^^^
+### iPXE
For running iPXE on arm64 the bin-arm64-efi/snp.efi build target is needed::
@@ -157,9 +151,20 @@ following into src/config/local/general.h is sufficient for most use cases::
#define DOWNLOAD_PROTO_NFS /* Network File System Protocol */
#define DOWNLOAD_PROTO_FILE /* Local file system access */
-Links
------
+### Open-iSCSI
+
+When the root file system is on an iSCSI drive you should disable pings and set
+the replacement timer to a high value [3]:
+
+ node.conn[0].timeo.noop_out_interval = 0
+ node.conn[0].timeo.noop_out_timeout = 0
+ node.session.timeo.replacement_timeout = 86400
+
+## Links
* [1](https://ipxe.org) https://ipxe.org - iPXE open source boot firmware
* [2](https://www.gnu.org/software/grub/) https://www.gnu.org/software/grub/ -
- GNU GRUB (Grand Unified Bootloader)
+ GNU GRUB (Grand Unified Bootloader)
+* [3](https://github.com/open-iscsi/open-iscsi/blob/master/README)
+ https://github.com/open-iscsi/open-iscsi/blob/master/README -
+ Open-iSCSI README
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 2cb35f3..c8c47ac 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -9,31 +9,38 @@
#include <common.h>
#include <dm.h>
#include <dm/lists.h>
+#include <efi_loader.h>
#include <linux/libfdt.h>
#include <linux/arm-smccc.h>
#include <linux/errno.h>
#include <linux/printk.h>
#include <linux/psci.h>
-psci_fn *invoke_psci_fn;
+#define DRIVER_NAME "psci"
-static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
- unsigned long arg0, unsigned long arg1,
- unsigned long arg2)
-{
- struct arm_smccc_res res;
+#define PSCI_METHOD_HVC 1
+#define PSCI_METHOD_SMC 2
- arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
- return res.a0;
-}
+int __efi_runtime_data psci_method;
-static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
- unsigned long arg0, unsigned long arg1,
- unsigned long arg2)
+unsigned long __efi_runtime invoke_psci_fn
+ (unsigned long function_id, unsigned long arg0,
+ unsigned long arg1, unsigned long arg2)
{
struct arm_smccc_res res;
- arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+ /*
+ * In the __efi_runtime we need to avoid the switch statement. In some
+ * cases the compiler creates lookup tables to implement switch. These
+ * tables are not correctly relocated when SetVirtualAddressMap is
+ * called.
+ */
+ if (psci_method == PSCI_METHOD_SMC)
+ arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+ else if (psci_method == PSCI_METHOD_HVC)
+ arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+ else
+ res.a0 = PSCI_RET_DISABLED;
return res.a0;
}
@@ -67,9 +74,9 @@ static int psci_probe(struct udevice *dev)
}
if (!strcmp("hvc", method)) {
- invoke_psci_fn = __invoke_psci_fn_hvc;
+ psci_method = PSCI_METHOD_HVC;
} else if (!strcmp("smc", method)) {
- invoke_psci_fn = __invoke_psci_fn_smc;
+ psci_method = PSCI_METHOD_SMC;
} else {
pr_warn("invalid \"method\" property: %s\n", method);
return -EINVAL;
@@ -78,6 +85,67 @@ static int psci_probe(struct udevice *dev)
return 0;
}
+/**
+ * void do_psci_probe() - probe PSCI firmware driver
+ *
+ * Ensure that psci_method is initialized.
+ */
+static void __maybe_unused do_psci_probe(void)
+{
+ struct udevice *dev;
+
+ uclass_get_device_by_name(UCLASS_FIRMWARE, DRIVER_NAME, &dev);
+}
+
+#if IS_ENABLED(CONFIG_EFI_LOADER) && IS_ENABLED(CONFIG_PSCI_RESET)
+efi_status_t efi_reset_system_init(void)
+{
+ do_psci_probe();
+ return EFI_SUCCESS;
+}
+
+void __efi_runtime EFIAPI efi_reset_system(enum efi_reset_type reset_type,
+ efi_status_t reset_status,
+ unsigned long data_size,
+ void *reset_data)
+{
+ if (reset_type == EFI_RESET_COLD ||
+ reset_type == EFI_RESET_WARM ||
+ reset_type == EFI_RESET_PLATFORM_SPECIFIC) {
+ invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
+ } else if (reset_type == EFI_RESET_SHUTDOWN) {
+ invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
+ }
+ while (1)
+ ;
+}
+#endif /* IS_ENABLED(CONFIG_EFI_LOADER) && IS_ENABLED(CONFIG_PSCI_RESET) */
+
+#ifdef CONFIG_PSCI_RESET
+void reset_misc(void)
+{
+ do_psci_probe();
+ invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
+}
+#endif /* CONFIG_PSCI_RESET */
+
+#ifdef CONFIG_CMD_POWEROFF
+int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ do_psci_probe();
+
+ puts("poweroff ...\n");
+ udelay(50000); /* wait 50 ms */
+
+ disable_interrupts();
+ invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
+ enable_interrupts();
+
+ log_err("Power off not supported on this platform\n");
+ return CMD_RET_FAILURE;
+}
+#endif
+
static const struct udevice_id psci_of_match[] = {
{ .compatible = "arm,psci" },
{ .compatible = "arm,psci-0.2" },
@@ -86,7 +154,7 @@ static const struct udevice_id psci_of_match[] = {
};
U_BOOT_DRIVER(psci) = {
- .name = "psci",
+ .name = DRIVER_NAME,
.id = UCLASS_FIRMWARE,
.of_match = psci_of_match,
.bind = psci_bind,
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 03746dd..d456beb 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -70,6 +70,7 @@ comment "USB peripherals"
config USB_STORAGE
bool "USB Mass Storage support"
+ depends on !(BLK && !DM_USB)
---help---
Say Y here if you want to connect USB mass storage devices to your
board's USB port.
diff --git a/fs/fs.c b/fs/fs.c
index adae98d..cb26517 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -365,6 +365,7 @@ int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
if (!info->probe(fs_dev_desc, &fs_partition)) {
fs_type = info->fstype;
+ fs_dev_part = part;
return 0;
}
}
diff --git a/include/asm-generic/pe.h b/include/asm-generic/pe.h
index 9a8b5e8..faae534 100644
--- a/include/asm-generic/pe.h
+++ b/include/asm-generic/pe.h
@@ -11,6 +11,24 @@
#ifndef _ASM_PE_H
#define _ASM_PE_H
+/* Characteristics */
+#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
+#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
+#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
+#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
+#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
+/* Reserved 0x0040 */
+#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
+#define IMAGE_FILE_32BIT_MACHINE 0x0100
+#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
+#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
+#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
+#define IMAGE_FILE_SYSTEM 0x1000
+#define IMAGE_FILE_DLL 0x2000
+#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
+#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
+
/* Subsystem type */
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
diff --git a/include/common.h b/include/common.h
index 8b56137..a8e879e 100644
--- a/include/common.h
+++ b/include/common.h
@@ -106,6 +106,17 @@ int mdm_init(void);
void board_show_dram(phys_size_t size);
/**
+ * Get the uppermost pointer that is valid to access
+ *
+ * Some systems may not map all of their address space. This function allows
+ * boards to indicate what their highest support pointer value is for DRAM
+ * access.
+ *
+ * @param total_size Size of U-Boot (unused?)
+ */
+ulong board_get_usable_ram_top(ulong total_size);
+
+/**
* arch_fixup_fdt() - Write arch-specific information to fdt
*
* Defined in arch/$(ARCH)/lib/bootm-fdt.c
diff --git a/include/efi.h b/include/efi.h
index b1deb60..b5e2c64 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -96,7 +96,7 @@ typedef struct {
typedef unsigned long efi_status_t;
typedef u64 efi_physical_addr_t;
typedef u64 efi_virtual_addr_t;
-typedef void *efi_handle_t;
+typedef struct efi_object *efi_handle_t;
#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \
diff --git a/include/efi_api.h b/include/efi_api.h
index e850b95..aef77b6 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -85,10 +85,10 @@ struct efi_boot_services {
efi_status_t (EFIAPI *check_event)(struct efi_event *event);
#define EFI_NATIVE_INTERFACE 0x00000000
efi_status_t (EFIAPI *install_protocol_interface)(
- void **handle, const efi_guid_t *protocol,
+ efi_handle_t *handle, const efi_guid_t *protocol,
int protocol_interface_type, void *protocol_interface);
efi_status_t (EFIAPI *reinstall_protocol_interface)(
- void *handle, const efi_guid_t *protocol,
+ efi_handle_t handle, const efi_guid_t *protocol,
void *old_interface, void *new_interface);
efi_status_t (EFIAPI *uninstall_protocol_interface)(
efi_handle_t handle, const efi_guid_t *protocol,
@@ -164,9 +164,9 @@ struct efi_boot_services {
efi_status_t (EFIAPI *locate_protocol)(const efi_guid_t *protocol,
void *registration, void **protocol_interface);
efi_status_t (EFIAPI *install_multiple_protocol_interfaces)(
- void **handle, ...);
+ efi_handle_t *handle, ...);
efi_status_t (EFIAPI *uninstall_multiple_protocol_interfaces)(
- void *handle, ...);
+ efi_handle_t handle, ...);
efi_status_t (EFIAPI *calculate_crc32)(const void *data,
efi_uintn_t data_size,
u32 *crc32);
@@ -241,8 +241,8 @@ struct efi_runtime_services {
efi_status_t (EFIAPI *query_capsule_caps)(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
- u64 maximum_capsule_size,
- u32 reset_type);
+ u64 *maximum_capsule_size,
+ u32 *reset_type);
efi_status_t (EFIAPI *query_variable_info)(
u32 attributes,
u64 *maximum_variable_storage_size,
@@ -965,7 +965,7 @@ struct efi_file_info {
struct efi_time last_access_time;
struct efi_time modification_time;
u64 attribute;
- s16 file_name[0];
+ u16 file_name[0];
};
struct efi_file_system_info {
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 1417c35..53f0816 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -167,28 +167,41 @@ struct efi_handler {
struct list_head open_infos;
};
-/*
- * UEFI has a poor man's OO model where one "object" can be polymorphic and have
- * multiple different protocols (classes) attached to it.
+/**
+ * struct efi_object - dereferenced EFI handle
+ *
+ * @link: pointers to put the handle into a linked list
+ * @protocols: linked list with the protocol interfaces installed on this
+ * handle
+ *
+ * UEFI offers a flexible and expandable object model. The objects in the UEFI
+ * API are devices, drivers, and loaded images. struct efi_object is our storage
+ * structure for these objects.
*
- * This struct is the parent struct for all of our actual implementation objects
- * that can include it to make themselves an EFI object
+ * When including this structure into a larger structure always put it first so
+ * that when deleting a handle the whole encompassing structure can be freed.
+ *
+ * A pointer to this structure is referred to as a handle. Typedef efi_handle_t
+ * has been created for such pointers.
*/
struct efi_object {
/* Every UEFI object is part of a global object list */
struct list_head link;
/* The list of protocols */
struct list_head protocols;
- /* The object spawner can either use this for data or as identifier */
- void *handle;
};
/**
* struct efi_loaded_image_obj - handle of a loaded image
+ *
+ * @header: EFI object header
+ * @reloc_base: base address for the relocated image
+ * @reloc_size: size of the relocated image
+ * @exit_jmp: long jump buffer for returning form started image
+ * @entry: entry address of the relocated image
*/
struct efi_loaded_image_obj {
- /* Generic EFI object parent class data */
- struct efi_object parent;
+ struct efi_object header;
void *reloc_base;
aligned_u64 reloc_size;
efi_status_t exit_status;
@@ -290,11 +303,11 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
/* Call this to set the current device name */
void efi_set_bootdev(const char *dev, const char *devnr, const char *path);
/* Add a new object to the object list. */
-void efi_add_handle(struct efi_object *obj);
+void efi_add_handle(efi_handle_t obj);
/* Create handle */
efi_status_t efi_create_handle(efi_handle_t *handle);
/* Delete handle */
-void efi_delete_handle(struct efi_object *obj);
+void efi_delete_handle(efi_handle_t obj);
/* Call this to validate a handle and find the EFI object for it */
struct efi_object *efi_search_obj(const efi_handle_t handle);
/* Find a protocol on a handle */
@@ -331,7 +344,16 @@ struct efi_simple_file_system_protocol *efi_simple_file_system(
/* open file from device-path: */
struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);
-
+/**
+ * efi_size_in_pages() - convert size in bytes to size in pages
+ *
+ * This macro returns the number of EFI memory pages required to hold 'size'
+ * bytes.
+ *
+ * @size: size in bytes
+ * Return: size in pages
+ */
+#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
/* Generic EFI memory allocator, call this to get memory */
void *efi_alloc(uint64_t len, int memory_type);
/* More specific EFI memory allocator, called by EFI payloads */
@@ -419,6 +441,10 @@ const struct efi_device_path *efi_dp_last_node(
efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
struct efi_device_path **device_path,
struct efi_device_path **file_path);
+efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
+ const char *path,
+ struct efi_device_path **device,
+ struct efi_device_path **file);
#define EFI_DP_TYPE(_dp, _type, _subtype) \
(((_dp)->type == DEVICE_PATH_TYPE_##_type) && \
@@ -492,6 +518,29 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
void *data);
+/*
+ * See section 3.1.3 in the v2.7 UEFI spec for more details on
+ * the layout of EFI_LOAD_OPTION. In short it is:
+ *
+ * typedef struct _EFI_LOAD_OPTION {
+ * UINT32 Attributes;
+ * UINT16 FilePathListLength;
+ * // CHAR16 Description[]; <-- variable length, NULL terminated
+ * // EFI_DEVICE_PATH_PROTOCOL FilePathList[];
+ * <-- FilePathListLength bytes
+ * // UINT8 OptionalData[];
+ * } EFI_LOAD_OPTION;
+ */
+struct efi_load_option {
+ u32 attributes;
+ u16 file_path_length;
+ u16 *label;
+ struct efi_device_path *file_path;
+ u8 *optional_data;
+};
+
+void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
+unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
void *efi_bootmgr_load(struct efi_device_path **device_path,
struct efi_device_path **file_path);
diff --git a/include/efi_selftest.h b/include/efi_selftest.h
index 56beac3..49d3d6d 100644
--- a/include/efi_selftest.h
+++ b/include/efi_selftest.h
@@ -129,7 +129,6 @@ u16 efi_st_get_key(void);
* @setup: set up the unit test
* @teardown: tear down the unit test
* @execute: execute the unit test
- * @setup_ok: setup was successful (set at runtime)
* @on_request: test is only executed on request
*/
struct efi_unit_test {
@@ -139,7 +138,6 @@ struct efi_unit_test {
const struct efi_system_table *systable);
int (*execute)(void);
int (*teardown)(void);
- int setup_ok;
bool on_request;
};
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 8d13bd2..9433df8 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -88,10 +88,8 @@
#define PSCI_RET_DISABLED -8
#ifdef CONFIG_ARM_PSCI_FW
-typedef unsigned long (psci_fn)(unsigned long, unsigned long,
- unsigned long, unsigned long);
-
-extern psci_fn *invoke_psci_fn;
+unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3);
#else
unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3)
diff --git a/lib/Makefile b/lib/Makefile
index 4d2e220..8321355 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,7 +8,7 @@ ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_EFI) += efi/
obj-$(CONFIG_EFI_LOADER) += efi_driver/
obj-$(CONFIG_EFI_LOADER) += efi_loader/
-obj-$(CONFIG_EFI_LOADER) += efi_selftest/
+obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/
obj-$(CONFIG_LZMA) += lzma/
obj-$(CONFIG_BZIP2) += bzip2/
obj-$(CONFIG_TIZEN) += tizen/
diff --git a/lib/efi/efi.c b/lib/efi/efi.c
index c6639f9..2c6a508 100644
--- a/lib/efi/efi.c
+++ b/lib/efi/efi.c
@@ -69,7 +69,7 @@ int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image,
efi_putc(priv, ' ');
ret = boot->open_protocol(priv->parent_image, &loaded_image_guid,
- (void **)&loaded_image, &priv->parent_image,
+ (void **)&loaded_image, priv->parent_image,
NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret) {
efi_puts(priv, "Failed to get loaded image protocol\n");
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 0c5764d..a095df3 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * EFI utils
+ * EFI boot manager
*
* Copyright (c) 2017 Rob Clark
*/
@@ -9,6 +9,7 @@
#include <charset.h>
#include <malloc.h>
#include <efi_loader.h>
+#include <asm/unaligned.h>
static const struct efi_boot_services *bs;
static const struct efi_runtime_services *rs;
@@ -30,42 +31,68 @@ static const struct efi_runtime_services *rs;
*/
-/*
- * See section 3.1.3 in the v2.7 UEFI spec for more details on
- * the layout of EFI_LOAD_OPTION. In short it is:
- *
- * typedef struct _EFI_LOAD_OPTION {
- * UINT32 Attributes;
- * UINT16 FilePathListLength;
- * // CHAR16 Description[]; <-- variable length, NULL terminated
- * // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; <-- FilePathListLength bytes
- * // UINT8 OptionalData[];
- * } EFI_LOAD_OPTION;
- */
-struct load_option {
- u32 attributes;
- u16 file_path_length;
- u16 *label;
- struct efi_device_path *file_path;
- u8 *optional_data;
-};
-
-/* parse an EFI_LOAD_OPTION, as described above */
-static void parse_load_option(struct load_option *lo, void *ptr)
+/* Parse serialized data and transform it into efi_load_option structure */
+void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data)
{
- lo->attributes = *(u32 *)ptr;
- ptr += sizeof(u32);
+ lo->attributes = get_unaligned_le32(data);
+ data += sizeof(u32);
+
+ lo->file_path_length = get_unaligned_le16(data);
+ data += sizeof(u16);
- lo->file_path_length = *(u16 *)ptr;
- ptr += sizeof(u16);
+ /* FIXME */
+ lo->label = (u16 *)data;
+ data += (u16_strlen(lo->label) + 1) * sizeof(u16);
- lo->label = ptr;
- ptr += (u16_strlen(lo->label) + 1) * 2;
+ /* FIXME */
+ lo->file_path = (struct efi_device_path *)data;
+ data += lo->file_path_length;
- lo->file_path = ptr;
- ptr += lo->file_path_length;
+ lo->optional_data = data;
+}
- lo->optional_data = ptr;
+/*
+ * Serialize efi_load_option structure into byte stream for BootXXXX.
+ * Return a size of allocated data.
+ */
+unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
+{
+ unsigned long label_len, option_len;
+ unsigned long size;
+ u8 *p;
+
+ label_len = (u16_strlen(lo->label) + 1) * sizeof(u16);
+ option_len = strlen((char *)lo->optional_data);
+
+ /* total size */
+ size = sizeof(lo->attributes);
+ size += sizeof(lo->file_path_length);
+ size += label_len;
+ size += lo->file_path_length;
+ size += option_len + 1;
+ p = malloc(size);
+ if (!p)
+ return 0;
+
+ /* copy data */
+ *data = p;
+ memcpy(p, &lo->attributes, sizeof(lo->attributes));
+ p += sizeof(lo->attributes);
+
+ memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
+ p += sizeof(lo->file_path_length);
+
+ memcpy(p, lo->label, label_len);
+ p += label_len;
+
+ memcpy(p, lo->file_path, lo->file_path_length);
+ p += lo->file_path_length;
+
+ memcpy(p, lo->optional_data, option_len);
+ p += option_len;
+ *(char *)p = '\0';
+
+ return size;
}
/* free() the result */
@@ -100,7 +127,7 @@ static void *get_var(u16 *name, const efi_guid_t *vendor,
static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
struct efi_device_path **file_path)
{
- struct load_option lo;
+ struct efi_load_option lo;
u16 varname[] = L"Boot0000";
u16 hexmap[] = L"0123456789ABCDEF";
void *load_option, *image = NULL;
@@ -115,7 +142,7 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
if (!load_option)
return NULL;
- parse_load_option(&lo, load_option);
+ efi_deserialize_load_option(&lo, load_option);
if (lo.attributes & LOAD_OPTION_ACTIVE) {
efi_status_t ret;
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index da978d2..cc9efbb 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -26,6 +26,14 @@ LIST_HEAD(efi_obj_list);
/* List of all events */
LIST_HEAD(efi_events);
+/*
+ * If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
+ * we need to do trickery with caches. Since we don't want to break the EFI
+ * aware boot path, only apply hacks when loading exiting directly (breaking
+ * direct Linux EFI booting along the way - oh well).
+ */
+static bool efi_is_direct_boot = true;
+
#ifdef CONFIG_ARM
/*
* The "gd" pointer lives in a register on ARM and AArch64 that we declare
@@ -416,13 +424,12 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer)
*
* The protocols list is initialized. The object handle is set.
*/
-void efi_add_handle(struct efi_object *obj)
+void efi_add_handle(efi_handle_t handle)
{
- if (!obj)
+ if (!handle)
return;
- INIT_LIST_HEAD(&obj->protocols);
- obj->handle = obj;
- list_add_tail(&obj->link, &efi_obj_list);
+ INIT_LIST_HEAD(&handle->protocols);
+ list_add_tail(&handle->link, &efi_obj_list);
}
/**
@@ -440,7 +447,7 @@ efi_status_t efi_create_handle(efi_handle_t *handle)
return EFI_OUT_OF_RESOURCES;
efi_add_handle(obj);
- *handle = obj->handle;
+ *handle = obj;
return EFI_SUCCESS;
}
@@ -536,13 +543,13 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
*
* @obj: handle to delete
*/
-void efi_delete_handle(struct efi_object *obj)
+void efi_delete_handle(efi_handle_t handle)
{
- if (!obj)
+ if (!handle)
return;
- efi_remove_all_protocols(obj->handle);
- list_del(&obj->link);
- free(obj);
+ efi_remove_all_protocols(handle);
+ list_del(&handle->link);
+ free(handle);
}
/**
@@ -927,7 +934,7 @@ struct efi_object *efi_search_obj(const efi_handle_t handle)
struct efi_object *efiobj;
list_for_each_entry(efiobj, &efi_obj_list, link) {
- if (efiobj->handle == handle)
+ if (efiobj == handle)
return efiobj;
}
@@ -1019,7 +1026,7 @@ efi_status_t efi_add_protocol(const efi_handle_t handle,
* Return: status code
*/
static efi_status_t EFIAPI efi_install_protocol_interface(
- void **handle, const efi_guid_t *protocol,
+ efi_handle_t *handle, const efi_guid_t *protocol,
int protocol_interface_type, void *protocol_interface)
{
efi_status_t r;
@@ -1052,7 +1059,7 @@ out:
/**
* efi_get_drivers() - get all drivers associated to a controller
- * @efiobj: handle of the controller
+ * @handle: handle of the controller
* @protocol: protocol GUID (optional)
* @number_of_drivers: number of child controllers
* @driver_handle_buffer: handles of the the drivers
@@ -1061,7 +1068,7 @@ out:
*
* Return: status code
*/
-static efi_status_t efi_get_drivers(struct efi_object *efiobj,
+static efi_status_t efi_get_drivers(efi_handle_t handle,
const efi_guid_t *protocol,
efi_uintn_t *number_of_drivers,
efi_handle_t **driver_handle_buffer)
@@ -1072,7 +1079,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
bool duplicate;
/* Count all driver associations */
- list_for_each_entry(handler, &efiobj->protocols, link) {
+ list_for_each_entry(handler, &handle->protocols, link) {
if (protocol && guidcmp(handler->guid, protocol))
continue;
list_for_each_entry(item, &handler->open_infos, link) {
@@ -1090,7 +1097,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
if (!*driver_handle_buffer)
return EFI_OUT_OF_RESOURCES;
/* Collect unique driver handles */
- list_for_each_entry(handler, &efiobj->protocols, link) {
+ list_for_each_entry(handler, &handle->protocols, link) {
if (protocol && guidcmp(handler->guid, protocol))
continue;
list_for_each_entry(item, &handler->open_infos, link) {
@@ -1117,7 +1124,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
/**
* efi_disconnect_all_drivers() - disconnect all drivers from a controller
- * @efiobj: handle of the controller
+ * @handle: handle of the controller
* @protocol: protocol GUID (optional)
* @child_handle: handle of the child to destroy
*
@@ -1128,16 +1135,16 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
*
* Return: status code
*/
-static efi_status_t efi_disconnect_all_drivers(
- struct efi_object *efiobj,
- const efi_guid_t *protocol,
- efi_handle_t child_handle)
+static efi_status_t efi_disconnect_all_drivers
+ (efi_handle_t handle,
+ const efi_guid_t *protocol,
+ efi_handle_t child_handle)
{
efi_uintn_t number_of_drivers;
efi_handle_t *driver_handle_buffer;
efi_status_t r, ret;
- ret = efi_get_drivers(efiobj, protocol, &number_of_drivers,
+ ret = efi_get_drivers(handle, protocol, &number_of_drivers,
&driver_handle_buffer);
if (ret != EFI_SUCCESS)
return ret;
@@ -1145,7 +1152,7 @@ static efi_status_t efi_disconnect_all_drivers(
ret = EFI_NOT_FOUND;
while (number_of_drivers) {
r = EFI_CALL(efi_disconnect_controller(
- efiobj->handle,
+ handle,
driver_handle_buffer[--number_of_drivers],
child_handle));
if (r == EFI_SUCCESS)
@@ -1156,21 +1163,19 @@ static efi_status_t efi_disconnect_all_drivers(
}
/**
- * efi_uninstall_protocol_interface() - uninstall protocol interface
+ * efi_uninstall_protocol() - uninstall protocol interface
+ *
* @handle: handle from which the protocol shall be removed
* @protocol: GUID of the protocol to be removed
* @protocol_interface: interface to be removed
*
- * This function implements the UninstallProtocolInterface service.
- *
- * See the Unified Extensible Firmware Interface (UEFI) specification for
- * details.
+ * This function DOES NOT delete a handle without installed protocol.
*
* Return: status code
*/
-static efi_status_t EFIAPI efi_uninstall_protocol_interface(
- efi_handle_t handle, const efi_guid_t *protocol,
- void *protocol_interface)
+static efi_status_t efi_uninstall_protocol
+ (efi_handle_t handle, const efi_guid_t *protocol,
+ void *protocol_interface)
{
struct efi_object *efiobj;
struct efi_handler *handler;
@@ -1178,8 +1183,6 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(
struct efi_open_protocol_info_item *pos;
efi_status_t r;
- EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface);
-
/* Check handle */
efiobj = efi_search_obj(handle);
if (!efiobj) {
@@ -1210,7 +1213,41 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(
}
r = efi_remove_protocol(handle, protocol, protocol_interface);
out:
- return EFI_EXIT(r);
+ return r;
+}
+
+/**
+ * efi_uninstall_protocol_interface() - uninstall protocol interface
+ * @handle: handle from which the protocol shall be removed
+ * @protocol: GUID of the protocol to be removed
+ * @protocol_interface: interface to be removed
+ *
+ * This function implements the UninstallProtocolInterface service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_uninstall_protocol_interface
+ (efi_handle_t handle, const efi_guid_t *protocol,
+ void *protocol_interface)
+{
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface);
+
+ ret = efi_uninstall_protocol(handle, protocol, protocol_interface);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ /* If the last protocol has been removed, delete the handle. */
+ if (list_empty(&handle->protocols)) {
+ list_del(&handle->link);
+ free(handle);
+ }
+out:
+ return EFI_EXIT(ret);
}
/**
@@ -1240,7 +1277,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify(
* @search_type: selection criterion
* @protocol: GUID of the protocol
* @search_key: registration key
- * @efiobj: handle
+ * @handle: handle
*
* See the documentation of the LocateHandle service in the UEFI specification.
*
@@ -1248,7 +1285,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify(
*/
static int efi_search(enum efi_locate_search_type search_type,
const efi_guid_t *protocol, void *search_key,
- struct efi_object *efiobj)
+ efi_handle_t handle)
{
efi_status_t ret;
@@ -1259,7 +1296,7 @@ static int efi_search(enum efi_locate_search_type search_type,
/* TODO: RegisterProtocolNotify is not implemented yet */
return -1;
case BY_PROTOCOL:
- ret = efi_search_protocol(efiobj->handle, protocol, NULL);
+ ret = efi_search_protocol(handle, protocol, NULL);
return (ret != EFI_SUCCESS);
default:
/* Invalid search type */
@@ -1331,7 +1368,7 @@ static efi_status_t efi_locate_handle(
/* Then fill the array */
list_for_each_entry(efiobj, &efi_obj_list, link) {
if (!efi_search(search_type, protocol, search_key, efiobj))
- *buffer++ = efiobj->handle;
+ *buffer++ = efiobj;
}
return EFI_SUCCESS;
@@ -1489,7 +1526,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
}
/* Add internal object to object list */
- efi_add_handle(&obj->parent);
+ efi_add_handle(&obj->header);
if (info_ptr)
*info_ptr = info;
@@ -1506,7 +1543,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
* When asking for the device path interface, return
* bootefi_device_path
*/
- ret = efi_add_protocol(obj->parent.handle,
+ ret = efi_add_protocol(&obj->header,
&efi_guid_device_path, device_path);
if (ret != EFI_SUCCESS)
goto failure;
@@ -1516,7 +1553,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
* When asking for the loaded_image interface, just
* return handle which points to loaded_image_info
*/
- ret = efi_add_protocol(obj->parent.handle,
+ ret = efi_add_protocol(&obj->header,
&efi_guid_loaded_image, info);
if (ret != EFI_SUCCESS)
goto failure;
@@ -1678,6 +1715,8 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
+ efi_is_direct_boot = false;
+
/* call the image! */
if (setjmp(&image_obj->exit_jmp)) {
/*
@@ -1786,6 +1825,21 @@ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
}
/**
+ * efi_exit_caches() - fix up caches for EFI payloads if necessary
+ */
+static void efi_exit_caches(void)
+{
+#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
+ /*
+ * Grub on 32bit ARM needs to have caches disabled before jumping into
+ * a zImage, but does not know of all cache layers. Give it a hand.
+ */
+ if (efi_is_direct_boot)
+ cleanup_before_linux();
+#endif
+}
+
+/**
* efi_exit_boot_services() - stop all boot services
* @image_handle: handle of the loaded image
* @map_key: key of the memory map
@@ -1838,6 +1892,9 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
board_quiesce_devices();
+ /* Fix up caches for EFI payloads if necessary */
+ efi_exit_caches();
+
/* This stops all lingering devices */
bootm_disable_interrupts();
@@ -2176,7 +2233,7 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol,
efiobj = list_entry(lhandle, struct efi_object, link);
- ret = efi_search_protocol(efiobj->handle, protocol, &handler);
+ ret = efi_search_protocol(efiobj, protocol, &handler);
if (ret == EFI_SUCCESS) {
*protocol_interface = handler->protocol_interface;
return EFI_EXIT(EFI_SUCCESS);
@@ -2279,8 +2336,8 @@ out:
*
* Return: status code
*/
-static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
- void **handle, ...)
+static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces
+ (efi_handle_t *handle, ...)
{
EFI_ENTRY("%p", handle);
@@ -2316,7 +2373,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
for (; i; --i) {
protocol = efi_va_arg(argptr, efi_guid_t*);
protocol_interface = efi_va_arg(argptr, void*);
- EFI_CALL(efi_uninstall_protocol_interface(handle, protocol,
+ EFI_CALL(efi_uninstall_protocol_interface(*handle, protocol,
protocol_interface));
}
efi_va_end(argptr);
@@ -2339,7 +2396,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
* Return: status code
*/
static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
- void *handle, ...)
+ efi_handle_t handle, ...)
{
EFI_ENTRY("%p", handle);
@@ -2358,16 +2415,21 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
if (!protocol)
break;
protocol_interface = efi_va_arg(argptr, void*);
- r = EFI_CALL(efi_uninstall_protocol_interface(
- handle, protocol,
- protocol_interface));
+ r = efi_uninstall_protocol(handle, protocol,
+ protocol_interface);
if (r != EFI_SUCCESS)
break;
i++;
}
efi_va_end(argptr);
- if (r == EFI_SUCCESS)
+ if (r == EFI_SUCCESS) {
+ /* If the last protocol has been removed, delete the handle. */
+ if (list_empty(&handle->protocols)) {
+ list_del(&handle->link);
+ free(handle);
+ }
return EFI_EXIT(r);
+ }
/* If an error occurred undo all changes. */
efi_va_start(argptr, handle);
@@ -2380,7 +2442,8 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
}
efi_va_end(argptr);
- return EFI_EXIT(r);
+ /* In case of an error always return EFI_INVALID_PARAMETER */
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
}
/**
@@ -2553,10 +2616,10 @@ out:
*
* Return: status code
*/
-static efi_status_t EFIAPI efi_open_protocol(
- void *handle, const efi_guid_t *protocol,
- void **protocol_interface, void *agent_handle,
- void *controller_handle, uint32_t attributes)
+static efi_status_t EFIAPI efi_open_protocol
+ (efi_handle_t handle, const efi_guid_t *protocol,
+ void **protocol_interface, efi_handle_t agent_handle,
+ efi_handle_t controller_handle, uint32_t attributes)
{
struct efi_handler *handler;
efi_status_t r = EFI_INVALID_PARAMETER;
@@ -2828,13 +2891,19 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(
EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface,
new_interface);
- ret = EFI_CALL(efi_uninstall_protocol_interface(handle, protocol,
- old_interface));
+
+ /* Uninstall protocol but do not delete handle */
+ ret = efi_uninstall_protocol(handle, protocol, old_interface);
if (ret != EFI_SUCCESS)
goto out;
- ret = EFI_CALL(efi_install_protocol_interface(&handle, protocol,
- EFI_NATIVE_INTERFACE,
- new_interface));
+
+ /* Install the new protocol */
+ ret = efi_add_protocol(handle, protocol, new_interface);
+ /*
+ * The UEFI spec does not specify what should happen to the handle
+ * if in case of an error no protocol interface remains on the handle.
+ * So let's do nothing here.
+ */
if (ret != EFI_SUCCESS)
goto out;
/*
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 0225222..66c33a5 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -205,7 +205,7 @@ static int query_console_serial(int *rows, int *cols)
/*
* Not all terminals understand CSI [18t for querying the console size.
* We should adhere to escape sequences documented in the console_codes
- * manpage and the ECMA-48 standard.
+ * man page and the ECMA-48 standard.
*
* So here we follow a different approach. We position the cursor to the
* bottom right and query its position. Before leaving the function we
@@ -480,7 +480,7 @@ void set_shift_mask(int mod, struct efi_key_state *key_state)
*
* This gets called when we have already parsed CSI.
*
- * @modifiers: bitmask (shift, alt, ctrl)
+ * @modifiers: bit mask (shift, alt, ctrl)
* @return: the unmodified code
*/
static int analyze_modifiers(struct efi_key_state *key_state)
@@ -1051,34 +1051,34 @@ static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
efi_status_t efi_console_register(void)
{
efi_status_t r;
- struct efi_object *efi_console_output_obj;
- struct efi_object *efi_console_input_obj;
+ efi_handle_t console_output_handle;
+ efi_handle_t console_input_handle;
/* Set up mode information */
query_console_size();
/* Create handles */
- r = efi_create_handle((efi_handle_t *)&efi_console_output_obj);
+ r = efi_create_handle(&console_output_handle);
if (r != EFI_SUCCESS)
goto out_of_memory;
- r = efi_add_protocol(efi_console_output_obj->handle,
+ r = efi_add_protocol(console_output_handle,
&efi_guid_text_output_protocol, &efi_con_out);
if (r != EFI_SUCCESS)
goto out_of_memory;
- systab.con_out_handle = efi_console_output_obj->handle;
- systab.stderr_handle = efi_console_output_obj->handle;
+ systab.con_out_handle = console_output_handle;
+ systab.stderr_handle = console_output_handle;
- r = efi_create_handle((efi_handle_t *)&efi_console_input_obj);
+ r = efi_create_handle(&console_input_handle);
if (r != EFI_SUCCESS)
goto out_of_memory;
- r = efi_add_protocol(efi_console_input_obj->handle,
+ r = efi_add_protocol(console_input_handle,
&efi_guid_text_input_protocol, &efi_con_in);
if (r != EFI_SUCCESS)
goto out_of_memory;
- systab.con_in_handle = efi_console_input_obj->handle;
- r = efi_add_protocol(efi_console_input_obj->handle,
+ systab.con_in_handle = console_input_handle;
+ r = efi_add_protocol(console_input_handle,
&efi_guid_text_input_ex_protocol, &efi_con_in_ex);
if (r != EFI_SUCCESS)
goto out_of_memory;
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 46a24f7..d949823 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -82,7 +82,7 @@ struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
/*
* Compare two device-paths, stopping when the shorter of the two hits
- * an End* node. This is useful to, for example, compare a device-path
+ * an End* node. This is useful to, for example, compare a device-path
* representing a device with one representing a file on the device, or
* a device with a parent device.
*/
@@ -109,16 +109,17 @@ int efi_dp_match(const struct efi_device_path *a,
}
/*
- * See UEFI spec (section 3.1.2, about short-form device-paths..
- * tl;dr: we can have a device-path that starts with a USB WWID
- * or USB Class node, and a few other cases which don't encode
- * the full device path with bus hierarchy:
+ * We can have device paths that start with a USB WWID or a USB Class node,
+ * and a few other cases which don't encode the full device path with bus
+ * hierarchy:
*
* - MESSAGING:USB_WWID
* - MESSAGING:USB_CLASS
* - MEDIA:FILE_PATH
* - MEDIA:HARD_DRIVE
* - MESSAGING:URI
+ *
+ * See UEFI spec (section 3.1.2, about short-form device-paths)
*/
static struct efi_device_path *shorten_path(struct efi_device_path *dp)
{
@@ -150,7 +151,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
struct efi_device_path *obj_dp;
efi_status_t ret;
- ret = efi_search_protocol(efiobj->handle,
+ ret = efi_search_protocol(efiobj,
&efi_guid_device_path, &handler);
if (ret != EFI_SUCCESS)
continue;
@@ -644,7 +645,7 @@ static unsigned dp_part_size(struct blk_desc *desc, int part)
/*
* Create a device node for a block device partition.
*
- * @buf buffer to which the device path is wirtten
+ * @buf buffer to which the device path is written
* @desc block device descriptor
* @part partition number, 0 identifies a block device
*/
@@ -709,7 +710,7 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
/*
* Create a device path for a block device or one of its partitions.
*
- * @buf buffer to which the device path is wirtten
+ * @buf buffer to which the device path is written
* @desc block device descriptor
* @part partition number, 0 identifies a block device
*/
@@ -728,7 +729,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
/*
* We *could* make a more accurate path, by looking at if_type
* and handling all the different cases like we do for non-
- * legacy (ie CONFIG_BLK=y) case. But most important thing
+ * legacy (i.e. CONFIG_BLK=y) case. But most important thing
* is just to have a unique device-path for if_type+devnum.
* So map things to a fictitious USB device.
*/
@@ -752,7 +753,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
return dp_part_node(buf, desc, part);
}
-/* Construct a device-path from a partition on a blk device: */
+/* Construct a device-path from a partition on a block device: */
struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
{
void *buf, *start;
@@ -771,7 +772,7 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
/*
* Create a device node for a block device partition.
*
- * @buf buffer to which the device path is wirtten
+ * @buf buffer to which the device path is written
* @desc block device descriptor
* @part partition number, 0 identifies a block device
*/
@@ -791,7 +792,7 @@ struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
return buf;
}
-/* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */
+/* convert path to an UEFI style path (i.e. DOS style backslashes and UTF-16) */
static void path_to_uefi(u16 *uefi, const char *path)
{
while (*path) {
@@ -941,3 +942,53 @@ efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
*file_path = fp;
return EFI_SUCCESS;
}
+
+efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
+ const char *path,
+ struct efi_device_path **device,
+ struct efi_device_path **file)
+{
+ int is_net;
+ struct blk_desc *desc = NULL;
+ disk_partition_t fs_partition;
+ int part = 0;
+ char filename[32] = { 0 }; /* dp->str is u16[32] long */
+ char *s;
+
+ if (path && !file)
+ return EFI_INVALID_PARAMETER;
+
+ is_net = !strcmp(dev, "Net");
+ if (!is_net) {
+ part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
+ 1);
+ if (part < 0)
+ return EFI_INVALID_PARAMETER;
+
+ if (device)
+ *device = efi_dp_from_part(desc, part);
+ } else {
+#ifdef CONFIG_NET
+ if (device)
+ *device = efi_dp_from_eth();
+#endif
+ }
+
+ if (!path)
+ return EFI_SUCCESS;
+
+ if (!is_net) {
+ /* Add leading / to fs paths, because they're absolute */
+ snprintf(filename, sizeof(filename), "/%s", path);
+ } else {
+ snprintf(filename, sizeof(filename), "%s", path);
+ }
+ /* DOS style file path: */
+ s = filename;
+ while ((s = strchr(s, '/')))
+ *s++ = '\\';
+ *file = efi_dp_from_file(((!is_net && device) ? desc : NULL),
+ part, filename);
+
+ return EFI_SUCCESS;
+}
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
index 0082236..e219f84 100644
--- a/lib/efi_loader/efi_device_path_to_text.c
+++ b/lib/efi_loader/efi_device_path_to_text.c
@@ -269,9 +269,9 @@ static char *efi_convert_single_device_node_to_text(
* for details.
*
* device_node device node to be converted
- * display_only true if the shorter text represenation shall be used
+ * display_only true if the shorter text representation shall be used
* allow_shortcuts true if shortcut forms may be used
- * @return text represenation of the device path
+ * @return text representation of the device path
* NULL if out of memory of device_path is NULL
*/
static uint16_t EFIAPI *efi_convert_device_node_to_text(
@@ -302,9 +302,9 @@ out:
* for details.
*
* device_path device path to be converted
- * display_only true if the shorter text represenation shall be used
+ * display_only true if the shorter text representation shall be used
* allow_shortcuts true if shortcut forms may be used
- * @return text represenation of the device path
+ * @return text representation of the device path
* NULL if out of memory of device_path is NULL
*/
static uint16_t EFIAPI *efi_convert_device_path_to_text(
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 13fcc1b..c037526 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -14,26 +14,30 @@
const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID;
+/**
+ * struct efi_disk_obj - EFI disk object
+ *
+ * @header: EFI object header
+ * @ops: EFI disk I/O protocol interface
+ * @ifname: interface name for block device
+ * @dev_index: device index of block device
+ * @media: block I/O media information
+ * @dp: device path to the block device
+ * @part: partition
+ * @volume: simple file system protocol of the partition
+ * @offset: offset into disk for simple partition
+ * @desc: internal block device descriptor
+ */
struct efi_disk_obj {
- /* Generic EFI object parent class data */
- struct efi_object parent;
- /* EFI Interface callback struct for block I/O */
+ struct efi_object header;
struct efi_block_io ops;
- /* U-Boot ifname for block device */
const char *ifname;
- /* U-Boot dev_index for block device */
int dev_index;
- /* EFI Interface Media descriptor struct, referenced by ops */
struct efi_block_io_media media;
- /* EFI device path to this block device */
struct efi_device_path *dp;
- /* partition # */
unsigned int part;
- /* handle to filesys proto (for partition objects) */
struct efi_simple_file_system_protocol *volume;
- /* Offset into disk for simple partitions */
lbaint_t offset;
- /* Internal block device */
struct blk_desc *desc;
};
@@ -246,7 +250,7 @@ static efi_status_t efi_disk_add_dev(
return EFI_OUT_OF_RESOURCES;
/* Hook up to the device list */
- efi_add_handle(&diskobj->parent);
+ efi_add_handle(&diskobj->header);
/* Fill in object data */
if (part) {
@@ -258,18 +262,18 @@ static efi_status_t efi_disk_add_dev(
diskobj->dp = efi_dp_from_part(desc, part);
}
diskobj->part = part;
- ret = efi_add_protocol(diskobj->parent.handle, &efi_block_io_guid,
+ ret = efi_add_protocol(&diskobj->header, &efi_block_io_guid,
&diskobj->ops);
if (ret != EFI_SUCCESS)
return ret;
- ret = efi_add_protocol(diskobj->parent.handle, &efi_guid_device_path,
+ ret = efi_add_protocol(&diskobj->header, &efi_guid_device_path,
diskobj->dp);
if (ret != EFI_SUCCESS)
return ret;
if (part >= 1) {
diskobj->volume = efi_simple_file_system(desc, part,
diskobj->dp);
- ret = efi_add_protocol(diskobj->parent.handle,
+ ret = efi_add_protocol(&diskobj->header,
&efi_simple_file_system_protocol_guid,
diskobj->volume);
if (ret != EFI_SUCCESS)
@@ -381,7 +385,7 @@ efi_status_t efi_disk_register(void)
/* Partitions show up as block devices in EFI */
disks += efi_disk_create_partitions(
- disk->parent.handle, desc, if_typename,
+ &disk->header, desc, if_typename,
desc->devnum, dev->name);
}
#else
@@ -426,9 +430,9 @@ efi_status_t efi_disk_register(void)
disks++;
/* Partitions show up as block devices in EFI */
- disks += efi_disk_create_partitions(
- disk->parent.handle, desc,
- if_typename, i, devname);
+ disks += efi_disk_create_partitions
+ (&disk->header, desc,
+ if_typename, i, devname);
}
}
#endif
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index beb4fba..128cb0a 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -563,7 +563,7 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
if (fh->isdir)
info->attribute |= EFI_FILE_DIRECTORY;
- ascii2unicode((u16 *)info->file_name, filename);
+ ascii2unicode(info->file_name, filename);
} else if (!guidcmp(info_type, &efi_file_system_info_guid)) {
struct efi_file_system_info *info = buffer;
disk_partition_t part;
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c
index a4aa9bc..d62ce45 100644
--- a/lib/efi_loader/efi_gop.c
+++ b/lib/efi_loader/efi_gop.c
@@ -16,15 +16,22 @@ DECLARE_GLOBAL_DATA_PTR;
static const efi_guid_t efi_gop_guid = EFI_GOP_GUID;
+/**
+ * struct efi_gop_obj - graphical output protocol object
+ *
+ * @header: EFI object header
+ * @ops: graphical output protocol interface
+ * @info: graphical output mode information
+ * @mode: graphical output mode
+ * @bpix: bits per pixel
+ * @fb: frame buffer
+ */
struct efi_gop_obj {
- /* Generic EFI object parent class data */
- struct efi_object parent;
- /* EFI Interface callback struct for gop */
+ struct efi_object header;
struct efi_gop ops;
- /* The only mode we support */
struct efi_gop_mode_info info;
struct efi_gop_mode mode;
- /* Fields we only have acces to during init */
+ /* Fields we only have access to during init */
u32 bpix;
void *fb;
};
@@ -236,12 +243,12 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
}
/*
- * Gcc can't optimize our BLT function well, but we need to make sure that
+ * GCC can't optimize our BLT function well, but we need to make sure that
* our 2-dimensional loop gets executed very quickly, otherwise the system
* will feel slow.
*
* By manually putting all obvious branch targets into functions which call
- * our generic blt function with constants, the compiler can successfully
+ * our generic BLT function with constants, the compiler can successfully
* optimize for speed.
*/
static efi_status_t gop_blt_video_fill(struct efi_gop *this,
@@ -439,13 +446,13 @@ efi_status_t efi_gop_register(void)
}
/* Hook up to the device list */
- efi_add_handle(&gopobj->parent);
+ efi_add_handle(&gopobj->header);
/* Fill in object data */
- ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid,
+ ret = efi_add_protocol(&gopobj->header, &efi_gop_guid,
&gopobj->ops);
if (ret != EFI_SUCCESS) {
- printf("ERROR: Failure adding gop protocol\n");
+ printf("ERROR: Failure adding GOP protocol\n");
return ret;
}
gopobj->ops.query_mode = gop_query_mode;
@@ -463,7 +470,10 @@ efi_status_t efi_gop_register(void)
if (bpix == LCD_COLOR32)
#endif
{
- /* With 32bit color space we can directly expose the fb */
+ /*
+ * With 32bit color space we can directly expose the frame
+ * buffer
+ */
gopobj->mode.fb_base = fb_base;
gopobj->mode.fb_size = fb_size;
}
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 5bd4f4d..4bb5174 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -11,6 +11,7 @@
#include <mapmem.h>
#include <watchdog.h>
#include <linux/list_sort.h>
+#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -294,6 +295,12 @@ static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr)
{
struct list_head *lhandle;
+ /*
+ * Prealign input max address, so we simplify our matching
+ * logic below and can just reuse it as return pointer.
+ */
+ max_addr &= ~EFI_PAGE_MASK;
+
list_for_each(lhandle, &efi_mem) {
struct efi_mem_list *lmem = list_entry(lhandle,
struct efi_mem_list, link);
@@ -378,7 +385,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
/* Reserve that map in our memory maps */
ret = efi_add_memory_map(addr, pages, memory_type, true);
if (ret == addr) {
- *memory = (uintptr_t)map_sysmem(addr, len);
+ *memory = addr;
} else {
/* Map would overlap, bail out */
r = EFI_OUT_OF_RESOURCES;
@@ -391,7 +398,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
void *efi_alloc(uint64_t len, int memory_type)
{
uint64_t ret = 0;
- uint64_t pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+ uint64_t pages = efi_size_in_pages(len);
efi_status_t r;
r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type, pages,
@@ -412,12 +419,11 @@ void *efi_alloc(uint64_t len, int memory_type)
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
{
uint64_t r = 0;
- uint64_t addr = map_to_sysmem((void *)(uintptr_t)memory);
- r = efi_add_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY, false);
+ r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
/* Merging of adjacent free regions is missing */
- if (r == addr)
+ if (r == memory)
return EFI_SUCCESS;
return EFI_NOT_FOUND;
@@ -435,8 +441,8 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer)
{
efi_status_t r;
struct efi_pool_allocation *alloc;
- u64 num_pages = (size + sizeof(struct efi_pool_allocation) +
- EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+ u64 num_pages = efi_size_in_pages(size +
+ sizeof(struct efi_pool_allocation));
if (!buffer)
return EFI_INVALID_PARAMETER;
@@ -545,17 +551,51 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
__weak void efi_add_known_memory(void)
{
+ u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK;
int i;
+ /* Fix for 32bit targets with ram_top at 4G */
+ if (!ram_top)
+ ram_top = 0x100000000ULL;
+
/* Add RAM */
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
- u64 ram_start = gd->bd->bi_dram[i].start;
- u64 ram_size = gd->bd->bi_dram[i].size;
- u64 start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
- u64 pages = (ram_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+ u64 ram_end, ram_start, pages;
+
+ ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0);
+ ram_end = ram_start + gd->bd->bi_dram[i].size;
+
+ /* Remove partial pages */
+ ram_end &= ~EFI_PAGE_MASK;
+ ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+
+ if (ram_end <= ram_start) {
+ /* Invalid mapping, keep going. */
+ continue;
+ }
+
+ pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
+
+ efi_add_memory_map(ram_start, pages,
+ EFI_CONVENTIONAL_MEMORY, false);
- efi_add_memory_map(start, pages, EFI_CONVENTIONAL_MEMORY,
- false);
+ /*
+ * Boards may indicate to the U-Boot memory core that they
+ * can not support memory above ram_top. Let's honor this
+ * in the efi_loader subsystem too by declaring any memory
+ * above ram_top as "already occupied by firmware".
+ */
+ if (ram_top < ram_start) {
+ /* ram_top is before this region, reserve all */
+ efi_add_memory_map(ram_start, pages,
+ EFI_BOOT_SERVICES_DATA, true);
+ } else if ((ram_top >= ram_start) && (ram_top < ram_end)) {
+ /* ram_top is inside this region, reserve parts */
+ pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT;
+
+ efi_add_memory_map(ram_top, pages,
+ EFI_BOOT_SERVICES_DATA, true);
+ }
}
}
@@ -563,6 +603,7 @@ __weak void efi_add_known_memory(void)
static void add_u_boot_and_runtime(void)
{
unsigned long runtime_start, runtime_end, runtime_pages;
+ unsigned long runtime_mask = EFI_PAGE_MASK;
unsigned long uboot_start, uboot_pages;
unsigned long uboot_stack_size = 16 * 1024 * 1024;
@@ -571,10 +612,22 @@ static void add_u_boot_and_runtime(void)
uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT;
efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false);
- /* Add Runtime Services */
- runtime_start = (ulong)&__efi_runtime_start & ~EFI_PAGE_MASK;
+#if defined(__aarch64__)
+ /*
+ * Runtime Services must be 64KiB aligned according to the
+ * "AArch64 Platforms" section in the UEFI spec (2.7+).
+ */
+
+ runtime_mask = SZ_64K - 1;
+#endif
+
+ /*
+ * Add Runtime Services. We mark surrounding boottime code as runtime as
+ * well to fulfill the runtime alignment constraints but avoid padding.
+ */
+ runtime_start = (ulong)&__efi_runtime_start & ~runtime_mask;
runtime_end = (ulong)&__efi_runtime_stop;
- runtime_end = (runtime_end + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+ runtime_end = (runtime_end + runtime_mask) & ~runtime_mask;
runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT;
efi_add_memory_map(runtime_start, runtime_pages,
EFI_RUNTIME_SERVICES_CODE, false);
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 4e8b2d5..c7d9da8 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -14,6 +14,8 @@ static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
static struct efi_pxe_packet *dhcp_ack;
static bool new_rx_packet;
static void *new_tx_packet;
+static void *transmit_buffer;
+
/*
* The notification function of this event is called in every timer cycle
* to check if a new network packet has been received.
@@ -24,33 +26,85 @@ static struct efi_event *network_timer_event;
*/
static struct efi_event *wait_for_packet;
+/**
+ * struct efi_net_obj - EFI object representing a network interface
+ *
+ * @header: EFI object header
+ * @net: simple network protocol interface
+ * @net_mode: status of the network interface
+ * @pxe: PXE base code protocol interface
+ * @pxe_mode: status of the PXE base code protocol
+ */
struct efi_net_obj {
- /* Generic EFI object parent class data */
- struct efi_object parent;
- /* EFI Interface callback struct for network */
+ struct efi_object header;
struct efi_simple_network net;
struct efi_simple_network_mode net_mode;
- /* PXE struct to transmit dhcp data */
struct efi_pxe pxe;
struct efi_pxe_mode pxe_mode;
};
+/*
+ * efi_net_start() - start the network interface
+ *
+ * This function implements the Start service of the
+ * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * Return: status code
+ */
static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
{
+ efi_status_t ret = EFI_SUCCESS;
+
EFI_ENTRY("%p", this);
- return EFI_EXIT(EFI_SUCCESS);
+ /* Check parameters */
+ if (!this) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (this->mode->state != EFI_NETWORK_STOPPED)
+ ret = EFI_ALREADY_STARTED;
+ else
+ this->mode->state = EFI_NETWORK_STARTED;
+out:
+ return EFI_EXIT(ret);
}
+/*
+ * efi_net_stop() - stop the network interface
+ *
+ * This function implements the Stop service of the
+ * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * Return: status code
+ */
static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
{
+ efi_status_t ret = EFI_SUCCESS;
+
EFI_ENTRY("%p", this);
- return EFI_EXIT(EFI_SUCCESS);
+ /* Check parameters */
+ if (!this) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (this->mode->state == EFI_NETWORK_STOPPED)
+ ret = EFI_NOT_STARTED;
+ else
+ this->mode->state = EFI_NETWORK_STOPPED;
+out:
+ return EFI_EXIT(ret);
}
/*
- * Initialize network adapter and allocate transmit and receive buffers.
+ * efi_net_initialize() - initialize the network interface
*
* This function implements the Initialize service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
@@ -59,7 +113,7 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
* @this: pointer to the protocol instance
* @extra_rx: extra receive buffer to be allocated
* @extra_tx: extra transmit buffer to be allocated
- * @return: status code
+ * Return: status code
*/
static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
ulong extra_rx, ulong extra_tx)
@@ -69,9 +123,10 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
+ /* Check parameters */
if (!this) {
r = EFI_INVALID_PARAMETER;
- goto error;
+ goto out;
}
/* Setup packet buffers */
@@ -84,32 +139,83 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
ret = eth_init();
if (ret < 0) {
eth_halt();
+ this->mode->state = EFI_NETWORK_STOPPED;
r = EFI_DEVICE_ERROR;
+ goto out;
+ } else {
+ this->mode->state = EFI_NETWORK_INITIALIZED;
}
-
-error:
+out:
return EFI_EXIT(r);
}
+/*
+ * efi_net_reset() - reinitialize the network interface
+ *
+ * This function implements the Reset service of the
+ * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @extended_verification: execute exhaustive verification
+ * Return: status code
+ */
static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
int extended_verification)
{
EFI_ENTRY("%p, %x", this, extended_verification);
- return EFI_EXIT(EFI_SUCCESS);
+ return EFI_EXIT(EFI_CALL(efi_net_initialize(this, 0, 0)));
}
+/*
+ * efi_net_shutdown() - shut down the network interface
+ *
+ * This function implements the Shutdown service of the
+ * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * Return: status code
+ */
static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
{
+ efi_status_t ret = EFI_SUCCESS;
+
EFI_ENTRY("%p", this);
- return EFI_EXIT(EFI_SUCCESS);
+ /* Check parameters */
+ if (!this) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ eth_halt();
+ this->mode->state = EFI_NETWORK_STOPPED;
+
+out:
+ return EFI_EXIT(ret);
}
-static efi_status_t EFIAPI efi_net_receive_filters(
- struct efi_simple_network *this, u32 enable, u32 disable,
- int reset_mcast_filter, ulong mcast_filter_count,
- struct efi_mac_address *mcast_filter)
+/*
+ * efi_net_receive_filters() - mange multicast receive filters
+ *
+ * This function implements the ReceiveFilters service of the
+ * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @enable: bit mask of receive filters to enable
+ * @disable: bit mask of receive filters to disable
+ * @reset_mcast_filter: true resets contents of the filters
+ * @mcast_filter_count: number of hardware MAC addresses in the new filters list
+ * @mcast_filter: list of new filters
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_net_receive_filters
+ (struct efi_simple_network *this, u32 enable, u32 disable,
+ int reset_mcast_filter, ulong mcast_filter_count,
+ struct efi_mac_address *mcast_filter)
{
EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
reset_mcast_filter, mcast_filter_count, mcast_filter);
@@ -117,15 +223,40 @@ static efi_status_t EFIAPI efi_net_receive_filters(
return EFI_EXIT(EFI_UNSUPPORTED);
}
-static efi_status_t EFIAPI efi_net_station_address(
- struct efi_simple_network *this, int reset,
- struct efi_mac_address *new_mac)
+/*
+ * efi_net_station_address() - set the hardware MAC address
+ *
+ * This function implements the StationAddress service of the
+ * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @reset: if true reset the address to default
+ * @new_mac: new MAC address
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_net_station_address
+ (struct efi_simple_network *this, int reset,
+ struct efi_mac_address *new_mac)
{
EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
return EFI_EXIT(EFI_UNSUPPORTED);
}
+/*
+ * efi_net_statistics() - reset or collect statistics of the network interface
+ *
+ * This function implements the Statistics service of the
+ * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @reset: if true, the statistics are reset
+ * @stat_size: size of the statistics table
+ * @stat_table: table to receive the statistics
+ * Return: status code
+ */
static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
int reset, ulong *stat_size,
void *stat_table)
@@ -135,6 +266,19 @@ static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
return EFI_EXIT(EFI_UNSUPPORTED);
}
+/*
+ * efi_net_mcastiptomac() - translate multicast IP address to MAC address
+ *
+ * This function implements the Statistics service of the
+ * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @ipv6: true if the IP address is an IPv6 address
+ * @ip: IP address
+ * @mac: MAC address
+ * Return: status code
+ */
static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
int ipv6,
struct efi_ip_address *ip,
@@ -145,6 +289,19 @@ static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
return EFI_EXIT(EFI_INVALID_PARAMETER);
}
+/**
+ * efi_net_nvdata() - read or write NVRAM
+ *
+ * This function implements the GetStatus service of the Simple Network
+ * Protocol. See the UEFI spec for details.
+ *
+ * @this: the instance of the Simple Network Protocol
+ * @readwrite: true for read, false for write
+ * @offset: offset in NVRAM
+ * @buffer_size: size of buffer
+ * @buffer: buffer
+ * Return: status code
+ */
static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
int read_write, ulong offset,
ulong buffer_size, char *buffer)
@@ -155,13 +312,42 @@ static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
return EFI_EXIT(EFI_UNSUPPORTED);
}
+/**
+ * efi_net_get_status() - get interrupt status
+ *
+ * This function implements the GetStatus service of the Simple Network
+ * Protocol. See the UEFI spec for details.
+ *
+ * @this: the instance of the Simple Network Protocol
+ * @int_status: interface status
+ * @txbuf: transmission buffer
+ */
static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
u32 *int_status, void **txbuf)
{
+ efi_status_t ret = EFI_SUCCESS;
+
EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
efi_timer_check();
+ /* Check parameters */
+ if (!this) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ switch (this->mode->state) {
+ case EFI_NETWORK_STOPPED:
+ ret = EFI_NOT_STARTED;
+ goto out;
+ case EFI_NETWORK_STARTED:
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ default:
+ break;
+ }
+
if (int_status) {
/* We send packets synchronously, so nothing is outstanding */
*int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
@@ -172,65 +358,103 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
*txbuf = new_tx_packet;
new_tx_packet = NULL;
-
- return EFI_EXIT(EFI_SUCCESS);
+out:
+ return EFI_EXIT(ret);
}
-static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
- size_t header_size, size_t buffer_size, void *buffer,
- struct efi_mac_address *src_addr,
- struct efi_mac_address *dest_addr, u16 *protocol)
+/**
+ * efi_net_transmit() - transmit a packet
+ *
+ * This function implements the Transmit service of the Simple Network Protocol.
+ * See the UEFI spec for details.
+ *
+ * @this: the instance of the Simple Network Protocol
+ * @header_size: size of the media header
+ * @buffer_size: size of the buffer to receive the packet
+ * @buffer: buffer to receive the packet
+ * @src_addr: source hardware MAC address
+ * @dest_addr: destination hardware MAC address
+ * @protocol: type of header to build
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_net_transmit
+ (struct efi_simple_network *this, size_t header_size,
+ size_t buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol)
{
+ efi_status_t ret = EFI_SUCCESS;
+
EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this,
(unsigned long)header_size, (unsigned long)buffer_size,
buffer, src_addr, dest_addr, protocol);
efi_timer_check();
+ /* Check parameters */
+ if (!this) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /* We do not support jumbo packets */
+ if (buffer_size > PKTSIZE_ALIGN) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
if (header_size) {
- /* We would need to create the header if header_size != 0 */
- return EFI_EXIT(EFI_INVALID_PARAMETER);
+ /*
+ * TODO: We would need to create the header
+ * if header_size != 0
+ */
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ switch (this->mode->state) {
+ case EFI_NETWORK_STOPPED:
+ ret = EFI_NOT_STARTED;
+ goto out;
+ case EFI_NETWORK_STARTED:
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ default:
+ break;
}
-#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
/* Ethernet packets always fit, just bounce */
- memcpy(efi_bounce_buffer, buffer, buffer_size);
- net_send_packet(efi_bounce_buffer, buffer_size);
-#else
- net_send_packet(buffer, buffer_size);
-#endif
+ memcpy(transmit_buffer, buffer, buffer_size);
+ net_send_packet(transmit_buffer, buffer_size);
new_tx_packet = buffer;
- return EFI_EXIT(EFI_SUCCESS);
-}
-
-static void efi_net_push(void *pkt, int len)
-{
- new_rx_packet = true;
- wait_for_packet->is_signaled = true;
+out:
+ return EFI_EXIT(ret);
}
-/*
- * Receive a packet from a network interface.
+/**
+ * efi_net_receive() - receive a packet from a network interface
*
* This function implements the Receive service of the Simple Network Protocol.
* See the UEFI spec for details.
*
- * @this the instance of the Simple Network Protocol
- * @header_size size of the media header
- * @buffer_size size of the buffer to receive the packet
- * @buffer buffer to receive the packet
- * @src_addr source MAC address
- * @dest_addr destination MAC address
- * @protocol protocol
- * @return status code
+ * @this: the instance of the Simple Network Protocol
+ * @header_size: size of the media header
+ * @buffer_size: size of the buffer to receive the packet
+ * @buffer: buffer to receive the packet
+ * @src_addr: source MAC address
+ * @dest_addr: destination MAC address
+ * @protocol: protocol
+ * Return: status code
*/
-static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
- size_t *header_size, size_t *buffer_size, void *buffer,
- struct efi_mac_address *src_addr,
- struct efi_mac_address *dest_addr, u16 *protocol)
+static efi_status_t EFIAPI efi_net_receive
+ (struct efi_simple_network *this, size_t *header_size,
+ size_t *buffer_size, void *buffer,
+ struct efi_mac_address *src_addr,
+ struct efi_mac_address *dest_addr, u16 *protocol)
{
+ efi_status_t ret = EFI_SUCCESS;
struct ethernet_hdr *eth_hdr;
size_t hdr_size = sizeof(struct ethernet_hdr);
u16 protlen;
@@ -238,14 +462,35 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
buffer_size, buffer, src_addr, dest_addr, protocol);
+ /* Execute events */
efi_timer_check();
- if (!new_rx_packet)
- return EFI_EXIT(EFI_NOT_READY);
+ /* Check parameters */
+ if (!this) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ switch (this->mode->state) {
+ case EFI_NETWORK_STOPPED:
+ ret = EFI_NOT_STARTED;
+ goto out;
+ case EFI_NETWORK_STARTED:
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ default:
+ break;
+ }
+
+ if (!new_rx_packet) {
+ ret = EFI_NOT_READY;
+ goto out;
+ }
/* Check that we at least received an Ethernet header */
if (net_rx_packet_len < sizeof(struct ethernet_hdr)) {
new_rx_packet = false;
- return EFI_EXIT(EFI_NOT_READY);
+ ret = EFI_NOT_READY;
+ goto out;
}
/* Fill export parameters */
eth_hdr = (struct ethernet_hdr *)net_rx_packet;
@@ -263,18 +508,24 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
if (protocol)
*protocol = protlen;
if (*buffer_size < net_rx_packet_len) {
- /* Packet doesn't fit, try again with bigger buf */
+ /* Packet doesn't fit, try again with bigger buffer */
*buffer_size = net_rx_packet_len;
- return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+ ret = EFI_BUFFER_TOO_SMALL;
+ goto out;
}
/* Copy packet */
memcpy(buffer, net_rx_packet, net_rx_packet_len);
*buffer_size = net_rx_packet_len;
new_rx_packet = false;
-
- return EFI_EXIT(EFI_SUCCESS);
+out:
+ return EFI_EXIT(ret);
}
+/**
+ * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
+ *
+ * This function is called by dhcp_handler().
+ */
void efi_net_set_dhcp_ack(void *pkt, int len)
{
int maxsize = sizeof(*dhcp_ack);
@@ -285,8 +536,22 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
memcpy(dhcp_ack, pkt, min(len, maxsize));
}
-/*
- * Check if a new network packet has been received.
+/**
+ * efi_net_push() - callback for received network packet
+ *
+ * This function is called when a network packet is received by eth_rx().
+ *
+ * @pkt: network packet
+ * @len: length
+ */
+static void efi_net_push(void *pkt, int len)
+{
+ new_rx_packet = true;
+ wait_for_packet->is_signaled = true;
+}
+
+/**
+ * efi_network_timer_notify() - check if a new network packet has been received
*
* This notification function is called in every timer cycle.
*
@@ -296,47 +561,65 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
static void EFIAPI efi_network_timer_notify(struct efi_event *event,
void *context)
{
+ struct efi_simple_network *this = (struct efi_simple_network *)context;
+
EFI_ENTRY("%p, %p", event, context);
+ /*
+ * Some network drivers do not support calling eth_rx() before
+ * initialization.
+ */
+ if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
+ goto out;
+
if (!new_rx_packet) {
push_packet = efi_net_push;
eth_rx();
push_packet = NULL;
}
+out:
EFI_EXIT(EFI_SUCCESS);
}
-/* This gets called from do_bootefi_exec(). */
+/**
+ * efi_net_register() - register the simple network protocol
+ *
+ * This gets called from do_bootefi_exec().
+ */
efi_status_t efi_net_register(void)
{
- struct efi_net_obj *netobj;
+ struct efi_net_obj *netobj = NULL;
efi_status_t r;
if (!eth_get_dev()) {
- /* No eth device active, don't expose any */
+ /* No network device active, don't expose any */
return EFI_SUCCESS;
}
- /* We only expose the "active" eth device, so one is enough */
+ /* We only expose the "active" network device, so one is enough */
netobj = calloc(1, sizeof(*netobj));
- if (!netobj) {
- printf("ERROR: Out of memory\n");
- return EFI_OUT_OF_RESOURCES;
- }
+ if (!netobj)
+ goto out_of_resources;
+
+ /* Allocate an aligned transmit buffer */
+ transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
+ if (!transmit_buffer)
+ goto out_of_resources;
+ transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
/* Hook net up to the device list */
- efi_add_handle(&netobj->parent);
+ efi_add_handle(&netobj->header);
/* Fill in object data */
- r = efi_add_protocol(netobj->parent.handle, &efi_net_guid,
+ r = efi_add_protocol(&netobj->header, &efi_net_guid,
&netobj->net);
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
- r = efi_add_protocol(netobj->parent.handle, &efi_guid_device_path,
+ r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
efi_dp_from_eth());
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
- r = efi_add_protocol(netobj->parent.handle, &efi_pxe_guid,
+ r = efi_add_protocol(&netobj->header, &efi_pxe_guid,
&netobj->pxe);
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
@@ -385,13 +668,13 @@ efi_status_t efi_net_register(void)
* iPXE is running at TPL_CALLBACK most of the time. Use a higher TPL.
*/
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
- efi_network_timer_notify, NULL, NULL,
+ efi_network_timer_notify, &netobj->net, NULL,
&network_timer_event);
if (r != EFI_SUCCESS) {
printf("ERROR: Failed to register network event\n");
return r;
}
- /* Network is time critical, create event in every timer cyle */
+ /* Network is time critical, create event in every timer cycle */
r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
if (r != EFI_SUCCESS) {
printf("ERROR: Failed to set network timer\n");
@@ -402,4 +685,9 @@ efi_status_t efi_net_register(void)
failure_to_add_protocol:
printf("ERROR: Failure to add protocol\n");
return r;
+out_of_resources:
+ free(netobj);
+ /* free(transmit_buffer) not needed yet */
+ printf("ERROR: Out of memory\n");
+ return EFI_OUT_OF_RESOURCES;
}
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index f059dc9..95844ef 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -141,7 +141,9 @@ static void EFIAPI efi_reset_system_boottime(
do_reset(NULL, 0, 0, NULL);
break;
case EFI_RESET_SHUTDOWN:
- /* We don't have anything to map this to */
+#ifdef CONFIG_CMD_POWEROFF
+ do_poweroff(NULL, 0, 0, NULL);
+#endif
break;
}
@@ -282,7 +284,7 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
}, {
/* invalidate_*cache_all are gone */
.ptr = &efi_runtime_services.set_virtual_address_map,
- .patchto = &efi_invalid_parameter,
+ .patchto = &efi_unimplemented,
}, {
/* RTC accessors are gone */
.ptr = &efi_runtime_services.get_time,
@@ -378,6 +380,9 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
ulong symidx = rel->info >> SYM_INDEX;
extern struct dyn_sym __dyn_sym_start[];
newaddr = __dyn_sym_start[symidx].addr + offset;
+#ifdef IS_RELA
+ newaddr -= CONFIG_SYS_TEXT_BASE;
+#endif
break;
}
#endif
@@ -623,8 +628,8 @@ efi_status_t __efi_runtime EFIAPI efi_update_capsule(
efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
- u64 maximum_capsule_size,
- u32 reset_type)
+ u64 *maximum_capsule_size,
+ u32 *reset_type)
{
return EFI_UNSUPPORTED;
}
diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c
index 38e42fa..a814884 100644
--- a/lib/efi_loader/efi_smbios.c
+++ b/lib/efi_loader/efi_smbios.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <efi_loader.h>
+#include <mapmem.h>
#include <smbios.h>
static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
@@ -19,17 +20,19 @@ static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
efi_status_t efi_smbios_register(void)
{
/* Map within the low 32 bits, to allow for 32bit SMBIOS tables */
- u64 dmi = U32_MAX;
+ u64 dmi_addr = U32_MAX;
efi_status_t ret;
+ void *dmi;
/* Reserve 4kiB page for SMBIOS */
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
- EFI_RUNTIME_SERVICES_DATA, 1, &dmi);
+ EFI_RUNTIME_SERVICES_DATA, 1, &dmi_addr);
if (ret != EFI_SUCCESS) {
/* Could not find space in lowmem, use highmem instead */
ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
- EFI_RUNTIME_SERVICES_DATA, 1, &dmi);
+ EFI_RUNTIME_SERVICES_DATA, 1,
+ &dmi_addr);
if (ret != EFI_SUCCESS)
return ret;
@@ -39,11 +42,14 @@ efi_status_t efi_smbios_register(void)
* Generate SMBIOS tables - we know that efi_allocate_pages() returns
* a 4k-aligned address, so it is safe to assume that
* write_smbios_table() will write the table at that address.
+ *
+ * Note that on sandbox, efi_allocate_pages() unfortunately returns a
+ * pointer even though it uses a uint64_t type. Convert it.
*/
- assert(!(dmi & 0xf));
- write_smbios_table(dmi);
+ assert(!(dmi_addr & 0xf));
+ dmi = (void *)(uintptr_t)dmi_addr;
+ write_smbios_table(map_to_sysmem(dmi));
/* And expose them to our EFI payload */
- return efi_install_configuration_table(&smbios_guid,
- (void *)(uintptr_t)dmi);
+ return efi_install_configuration_table(&smbios_guid, dmi);
}
diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c
index 3b8de5b..2905479 100644
--- a/lib/efi_loader/helloworld.c
+++ b/lib/efi_loader/helloworld.c
@@ -17,6 +17,16 @@ static const efi_guid_t fdt_guid = EFI_FDT_GUID;
static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
+/**
+ * hw_memcmp() - compare memory areas
+ *
+ * @buf1: pointer to first area
+ * @buf2: pointer to second area
+ * @length: number of bytes to compare
+ * Return: 0 if both memory areas are the same, otherwise the sign of the
+ * result value is the same as the sign of ghe difference between
+ * the first differing pair of bytes taken as u8.
+ */
static int hw_memcmp(const void *buf1, const void *buf2, size_t length)
{
const u8 *pos1 = buf1;
@@ -31,12 +41,12 @@ static int hw_memcmp(const void *buf1, const void *buf2, size_t length)
return 0;
}
-/*
- * Entry point of the EFI application.
+/**
+ * efi_main() - entry point of the EFI application.
*
- * @handle handle of the loaded image
- * @systable system table
- * @return status code
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: status code
*/
efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
@@ -48,7 +58,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
efi_uintn_t i;
u16 rev[] = L"0.0.0";
- con_out->output_string(con_out, L"Hello, world!\n");
+ /* UEFI requires CR LF */
+ con_out->output_string(con_out, L"Hello, world!\r\n");
/* Print the revision number */
rev[0] = (systable->hdr.revision >> 16) + '0';
@@ -65,27 +76,30 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
con_out->output_string(con_out, L"Running on UEFI ");
con_out->output_string(con_out, rev);
- con_out->output_string(con_out, L"\n");
+ con_out->output_string(con_out, L"\r\n");
/* Get the loaded image protocol */
ret = boottime->handle_protocol(handle, &loaded_image_guid,
(void **)&loaded_image);
if (ret != EFI_SUCCESS) {
- con_out->output_string(con_out,
- L"Cannot open loaded image protocol\n");
+ con_out->output_string
+ (con_out, L"Cannot open loaded image protocol\r\n");
goto out;
}
/* Find configuration tables */
for (i = 0; i < systable->nr_tables; ++i) {
if (!hw_memcmp(&systable->tables[i].guid, &fdt_guid,
sizeof(efi_guid_t)))
- con_out->output_string(con_out, L"Have device tree\n");
+ con_out->output_string
+ (con_out, L"Have device tree\r\n");
if (!hw_memcmp(&systable->tables[i].guid, &acpi_guid,
sizeof(efi_guid_t)))
- con_out->output_string(con_out, L"Have ACPI 2.0 table\n");
+ con_out->output_string
+ (con_out, L"Have ACPI 2.0 table\r\n");
if (!hw_memcmp(&systable->tables[i].guid, &smbios_guid,
sizeof(efi_guid_t)))
- con_out->output_string(con_out, L"Have SMBIOS table\n");
+ con_out->output_string
+ (con_out, L"Have SMBIOS table\r\n");
}
/* Output the load options */
con_out->output_string(con_out, L"Load options: ");
@@ -94,7 +108,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
(u16 *)loaded_image->load_options);
else
con_out->output_string(con_out, L"<none>");
- con_out->output_string(con_out, L"\n");
+ con_out->output_string(con_out, L"\r\n");
out:
boottime->exit(handle, ret, 0, NULL);
diff --git a/lib/efi_selftest/Kconfig b/lib/efi_selftest/Kconfig
index b526967..59f9f36 100644
--- a/lib/efi_selftest/Kconfig
+++ b/lib/efi_selftest/Kconfig
@@ -1,6 +1,6 @@
config CMD_BOOTEFI_SELFTEST
bool "Allow booting an EFI efi_selftest"
- depends on CMD_BOOTEFI && !SANDBOX
+ depends on CMD_BOOTEFI
imply FAT
imply FAT_WRITE
help
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 2f55d9d..743b482 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -10,7 +10,7 @@ CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) -Os
CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding
CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os
-obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \
+obj-y += \
efi_selftest.o \
efi_selftest_bitblt.o \
efi_selftest_config_table.o \
@@ -21,11 +21,13 @@ efi_selftest_devicepath.o \
efi_selftest_devicepath_util.o \
efi_selftest_events.o \
efi_selftest_event_groups.o \
+efi_selftest_exception.o \
efi_selftest_exitbootservices.o \
efi_selftest_fdt.o \
efi_selftest_gop.o \
efi_selftest_loaded_image.o \
efi_selftest_manageprotocols.o \
+efi_selftest_memory.o \
efi_selftest_rtc.o \
efi_selftest_snp.o \
efi_selftest_textinput.o \
@@ -37,20 +39,16 @@ efi_selftest_util.o \
efi_selftest_variables.o \
efi_selftest_watchdog.o
-ifeq ($(CONFIG_CMD_BOOTEFI_SELFTEST),y)
obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o
-endif
ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy)
-obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest_block_device.o
+obj-y += efi_selftest_block_device.o
endif
# TODO: As of v2018.01 the relocation code for the EFI application cannot
# be built on x86_64.
ifeq ($(CONFIG_X86_64)$(CONFIG_SANDBOX),)
-ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST),)
-
obj-y += \
efi_selftest_startimage_exit.o \
efi_selftest_startimage_return.o
@@ -74,5 +72,3 @@ $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h
endif
-
-endif
diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c
index dd338db..5b01610 100644
--- a/lib/efi_selftest/efi_selftest.c
+++ b/lib/efi_selftest/efi_selftest.c
@@ -18,6 +18,7 @@ static const struct efi_boot_services *boottime;
static const struct efi_runtime_services *runtime;
static efi_handle_t handle;
static u16 reset_message[] = L"Selftest completed";
+static int *setup_status;
/*
* Exit the boot services.
@@ -74,20 +75,20 @@ void efi_st_exit_boot_services(void)
*/
static int setup(struct efi_unit_test *test, unsigned int *failures)
{
- if (!test->setup) {
- test->setup_ok = EFI_ST_SUCCESS;
+ int ret;
+
+ if (!test->setup)
return EFI_ST_SUCCESS;
- }
efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name);
- test->setup_ok = test->setup(handle, systable);
- if (test->setup_ok != EFI_ST_SUCCESS) {
+ ret = test->setup(handle, systable);
+ if (ret != EFI_ST_SUCCESS) {
efi_st_error("Setting up '%s' failed\n", test->name);
++*failures;
} else {
efi_st_printc(EFI_LIGHTGREEN,
"Setting up '%s' succeeded\n", test->name);
}
- return test->setup_ok;
+ return ret;
}
/*
@@ -186,18 +187,20 @@ static void list_all_tests(void)
void efi_st_do_tests(const u16 *testname, unsigned int phase,
unsigned int steps, unsigned int *failures)
{
+ int i = 0;
struct efi_unit_test *test;
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
- test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
+ test < ll_entry_end(struct efi_unit_test, efi_unit_test);
+ ++test, ++i) {
if (testname ?
efi_st_strcmp_16_8(testname, test->name) : test->on_request)
continue;
if (test->phase != phase)
continue;
if (steps & EFI_ST_SETUP)
- setup(test, failures);
- if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS)
+ setup_status[i] = setup(test, failures);
+ if (steps & EFI_ST_EXECUTE && setup_status[i] == EFI_ST_SUCCESS)
execute(test, failures);
if (steps & EFI_ST_TEARDOWN)
teardown(test, failures);
@@ -271,6 +274,16 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
ll_entry_count(struct efi_unit_test,
efi_unit_test));
+ /* Allocate buffer for setup results */
+ ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) *
+ ll_entry_count(struct efi_unit_test,
+ efi_unit_test),
+ (void **)&setup_status);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Allocate pool failed\n");
+ return ret;
+ }
+
/* Execute boottime tests */
efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
diff --git a/lib/efi_selftest/efi_selftest_config_table.c b/lib/efi_selftest/efi_selftest_config_table.c
index 2aa3fc7..0bc5da6 100644
--- a/lib/efi_selftest/efi_selftest_config_table.c
+++ b/lib/efi_selftest/efi_selftest_config_table.c
@@ -18,7 +18,7 @@ static efi_guid_t table_guid =
0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75);
/*
- * Notification function, increments the notfication count if parameter
+ * Notification function, increments the notification count if parameter
* context is provided.
*
* @event notified event
@@ -33,23 +33,23 @@ static void EFIAPI notify(struct efi_event *event, void *context)
}
/*
- * Check crc32 of a table.
+ * Check CRC32 of a table.
*/
static int check_table(const void *table)
{
efi_status_t ret;
u32 crc32, res;
- /* Casting from const to not const */
+ /* Casting from constant to not constant */
struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
crc32 = hdr->crc32;
/*
- * Setting the crc32 of the 'const' table to zero is easier than
+ * Setting the CRC32 of the 'const' table to zero is easier than
* copying
*/
hdr->crc32 = 0;
ret = boottime->calculate_crc32(table, hdr->headersize, &res);
- /* Reset table crc32 so it stays constant */
+ /* Reset table CRC32 so it stays constant */
hdr->crc32 = crc32;
if (ret != EFI_ST_SUCCESS) {
efi_st_error("CalculateCrc32 failed\n");
@@ -203,7 +203,7 @@ static int execute(void)
return EFI_ST_FAILURE;
}
if (tabcnt > 1) {
- efi_st_error("Duplicate table guid\n");
+ efi_st_error("Duplicate table GUID\n");
return EFI_ST_FAILURE;
}
if (table != &tables[1]) {
diff --git a/lib/efi_selftest/efi_selftest_controllers.c b/lib/efi_selftest/efi_selftest_controllers.c
index d08c377..38720bb 100644
--- a/lib/efi_selftest/efi_selftest_controllers.c
+++ b/lib/efi_selftest/efi_selftest_controllers.c
@@ -33,7 +33,7 @@ static efi_handle_t handle_driver;
* Count child controllers
*
* @handle handle on which child controllers are installed
- * @protocol protocol for which the child controlles where installed
+ * @protocol protocol for which the child controllers were installed
* @count number of child controllers
* @return status code
*/
diff --git a/lib/efi_selftest/efi_selftest_crc32.c b/lib/efi_selftest/efi_selftest_crc32.c
index 8555b8f..4881e8a 100644
--- a/lib/efi_selftest/efi_selftest_crc32.c
+++ b/lib/efi_selftest/efi_selftest_crc32.c
@@ -5,7 +5,7 @@
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* This unit test checks the CalculateCrc32 bootservice and checks the
- * headers of the system table, the boot services tablle, and the runtime
+ * headers of the system table, the boot services table, and the runtime
* services table before and after ExitBootServices().
*/
@@ -19,7 +19,7 @@ static int check_table(const void *table)
{
efi_status_t ret;
u32 crc32, res;
- /* Casting from const to not const */
+ /* Casting from constant to not constant */
struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
if (!hdr->signature) {
diff --git a/lib/efi_selftest/efi_selftest_devicepath.c b/lib/efi_selftest/efi_selftest_devicepath.c
index adcf531..105ce2c 100644
--- a/lib/efi_selftest/efi_selftest_devicepath.c
+++ b/lib/efi_selftest/efi_selftest_devicepath.c
@@ -257,7 +257,7 @@ static int teardown(void)
static int execute(void)
{
struct efi_device_path *remaining_dp;
- void *handle;
+ efi_handle_t handle;
/*
* This device path node ends with the letter 't' of 'u-boot'.
* The following '.bin' does not belong to the node but is
diff --git a/lib/efi_selftest/efi_selftest_event_groups.c b/lib/efi_selftest/efi_selftest_event_groups.c
index 9b3c513..5a7980c 100644
--- a/lib/efi_selftest/efi_selftest_event_groups.c
+++ b/lib/efi_selftest/efi_selftest_event_groups.c
@@ -19,7 +19,7 @@ static efi_guid_t event_group =
0x0e, 0x5b, 0x45, 0xc0, 0x56, 0x91);
/*
- * Notification function, increments the notfication count if parameter
+ * Notification function, increments the notification count if parameter
* context is provided.
*
* @event notified event
@@ -114,7 +114,7 @@ static int execute(void)
(unsigned int)i, (unsigned int)j,
(unsigned int)counter[j]);
efi_st_error(
- "Nofification function not called\n");
+ "Notification function not called\n");
return EFI_ST_FAILURE;
}
}
diff --git a/lib/efi_selftest/efi_selftest_events.c b/lib/efi_selftest/efi_selftest_events.c
index 47f9f99..ed99a53 100644
--- a/lib/efi_selftest/efi_selftest_events.c
+++ b/lib/efi_selftest/efi_selftest_events.c
@@ -17,7 +17,7 @@ static unsigned int timer_ticks;
static struct efi_boot_services *boottime;
/*
- * Notification function, increments the notfication count if parameter
+ * Notification function, increments the notification count if parameter
* context is provided.
*
* @event notified event
diff --git a/lib/efi_selftest/efi_selftest_exception.c b/lib/efi_selftest/efi_selftest_exception.c
new file mode 100644
index 0000000..76cfb88
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_exception.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_exception
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Test the handling of exceptions by trying to execute an undefined
+ * instruction.
+ */
+
+#include <efi_selftest.h>
+
+/**
+ * undefined_instruction() - try to executed an undefined instruction
+ */
+static void undefined_instruction(void)
+{
+#if defined(CONFIG_ARM)
+ /*
+ * 0xe7f...f. is undefined in ARM mode
+ * 0xde.. is undefined in Thumb mode
+ */
+ asm volatile (".word 0xe7f7defb\n");
+#elif defined(CONFIG_RISCV)
+ asm volatile (".word 0xffffffff\n");
+#elif defined(CONFIG_X86)
+ asm volatile (".word 0xffff\n");
+#endif
+}
+
+/**
+ * execute() - execute unit test
+ *
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ undefined_instruction();
+
+ efi_st_error("An undefined instruction exception was not raised\n");
+
+ return EFI_ST_FAILURE;
+}
+
+EFI_UNIT_TEST(exception) = {
+ .name = "exception",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .execute = execute,
+ .on_request = true,
+};
diff --git a/lib/efi_selftest/efi_selftest_fdt.c b/lib/efi_selftest/efi_selftest_fdt.c
index c7bc242..d545d51 100644
--- a/lib/efi_selftest/efi_selftest_fdt.c
+++ b/lib/efi_selftest/efi_selftest_fdt.c
@@ -16,7 +16,7 @@
static struct efi_boot_services *boottime;
static const char *fdt;
-/* This should be sufficent for */
+/* This should be sufficient for */
#define BUFFERSIZE 0x100000
static efi_guid_t fdt_guid = EFI_FDT_GUID;
diff --git a/lib/efi_selftest/efi_selftest_loaded_image.c b/lib/efi_selftest/efi_selftest_loaded_image.c
index f9b54ae..ea2b380 100644
--- a/lib/efi_selftest/efi_selftest_loaded_image.c
+++ b/lib/efi_selftest/efi_selftest_loaded_image.c
@@ -53,7 +53,7 @@ static int execute(void)
efi_st_error("ProtocolsPerHandle failed\n");
return EFI_ST_FAILURE;
}
- if (!protocol_buffer_count | !protocol_buffer) {
+ if (!protocol_buffer_count || !protocol_buffer) {
efi_st_error("ProtocolsPerHandle returned no protocol\n");
return EFI_ST_FAILURE;
}
diff --git a/lib/efi_selftest/efi_selftest_manageprotocols.c b/lib/efi_selftest/efi_selftest_manageprotocols.c
index b09e4cd..0ff35ce 100644
--- a/lib/efi_selftest/efi_selftest_manageprotocols.c
+++ b/lib/efi_selftest/efi_selftest_manageprotocols.c
@@ -189,7 +189,14 @@ static int execute(void)
/*
* Test error handling in UninstallMultipleProtocols
*
- * Try to uninstall more protocols than there are installed.
+ * These are the installed protocol interfaces on handle 2:
+ *
+ * guid1 interface4
+ * guid2 interface2
+ *
+ * Try to uninstall more protocols than there are installed. This
+ * should return an error EFI_INVALID_PARAMETER. All deleted protocols
+ * should be reinstalled.
*/
ret = boottime->uninstall_multiple_protocol_interfaces(
handle2,
@@ -197,13 +204,18 @@ static int execute(void)
&guid2, &interface2,
&guid3, &interface3,
NULL);
- if (ret == EFI_SUCCESS) {
+ if (ret != EFI_INVALID_PARAMETER) {
+ printf("%lx", ret);
efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n");
return EFI_ST_FAILURE;
}
/*
* Test LocateHandleBuffer with ByProtocol
+ *
+ * These are the handles with a guid1 protocol interface installed:
+ *
+ * handle1, handle2
*/
count = buffer_size;
ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL,
@@ -213,7 +225,7 @@ static int execute(void)
return EFI_ST_FAILURE;
}
if (count != 2) {
- efi_st_error("LocateHandleBuffer failed to locate new handles\n");
+ efi_st_error("UninstallMultipleProtocolInterfaces deleted handle\n");
return EFI_ST_FAILURE;
}
ret = find_in_buffer(handle1, count, buffer);
diff --git a/lib/efi_selftest/efi_selftest_memory.c b/lib/efi_selftest/efi_selftest_memory.c
new file mode 100644
index 0000000..24b4438
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_memory.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_memory
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This unit test checks the following runtime services:
+ * AllocatePages, FreePages, GetMemoryMap
+ *
+ * The memory type used for the device tree is checked.
+ */
+
+#include <efi_selftest.h>
+
+#define EFI_ST_NUM_PAGES 8
+
+static const efi_guid_t fdt_guid = EFI_FDT_GUID;
+static struct efi_boot_services *boottime;
+static u64 fdt_addr;
+
+/**
+ * setup() - setup unit test
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ size_t i;
+
+ boottime = systable->boottime;
+
+ for (i = 0; i < systable->nr_tables; ++i) {
+ if (!efi_st_memcmp(&systable->tables[i].guid, &fdt_guid,
+ sizeof(efi_guid_t))) {
+ if (fdt_addr) {
+ efi_st_error("Duplicate device tree\n");
+ return EFI_ST_FAILURE;
+ }
+ fdt_addr = (uintptr_t)systable->tables[i].table;
+ }
+ }
+ return EFI_ST_SUCCESS;
+}
+
+/**
+ * find_in_memory_map() - check matching memory map entry exists
+ *
+ * @memory_map: memory map
+ * @desc_size: number of memory map entries
+ * @addr: physical address to find in the map
+ * @type: expected memory type
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int find_in_memory_map(efi_uintn_t map_size,
+ struct efi_mem_desc *memory_map,
+ efi_uintn_t desc_size,
+ u64 addr, int memory_type)
+{
+ efi_uintn_t i;
+ bool found = false;
+
+ for (i = 0; map_size; ++i, map_size -= desc_size) {
+ struct efi_mem_desc *entry = &memory_map[i];
+
+ if (addr >= entry->physical_start &&
+ addr < entry->physical_start +
+ (entry->num_pages << EFI_PAGE_SHIFT)) {
+ if (found) {
+ efi_st_error("Duplicate memory map entry\n");
+ return EFI_ST_FAILURE;
+ }
+ found = true;
+ if (memory_type != entry->type) {
+ efi_st_error
+ ("Wrong memory type %d, expected %d\n",
+ entry->type, memory_type);
+ return EFI_ST_FAILURE;
+ }
+ }
+ }
+ if (!found) {
+ efi_st_error("Missing memory map entry\n");
+ return EFI_ST_FAILURE;
+ }
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * execute() - execute unit test
+ *
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ u64 p1;
+ u64 p2;
+ efi_uintn_t map_size = 0;
+ efi_uintn_t map_key;
+ efi_uintn_t desc_size;
+ u32 desc_version;
+ struct efi_mem_desc *memory_map;
+ efi_status_t ret;
+
+ /* Allocate two page ranges with different memory type */
+ ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_RUNTIME_SERVICES_CODE,
+ EFI_ST_NUM_PAGES, &p1);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_RUNTIME_SERVICES_DATA,
+ EFI_ST_NUM_PAGES, &p2);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Load memory map */
+ ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
+ &desc_version);
+ if (ret != EFI_BUFFER_TOO_SMALL) {
+ efi_st_error
+ ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
+ return EFI_ST_FAILURE;
+ }
+ /* Allocate extra space for newly allocated memory */
+ map_size += sizeof(struct efi_mem_desc);
+ ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
+ (void **)&memory_map);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
+ &desc_size, &desc_version);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Check memory map entries */
+ if (find_in_memory_map(map_size, memory_map, desc_size, p1,
+ EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS)
+ return EFI_ST_FAILURE;
+ if (find_in_memory_map(map_size, memory_map, desc_size, p2,
+ EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS)
+ return EFI_ST_FAILURE;
+
+ /* Free memory */
+ ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("FreePages did not return EFI_SUCCESS\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->free_pages(p2, EFI_ST_NUM_PAGES);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("FreePages did not return EFI_SUCCESS\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->free_pool(memory_map);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("FreePool did not return EFI_SUCCESS\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Check memory reservation for the device tree */
+ if (fdt_addr &&
+ find_in_memory_map(map_size, memory_map, desc_size, fdt_addr,
+ EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) {
+ efi_st_error
+ ("Device tree not marked as runtime services data\n");
+ return EFI_ST_FAILURE;
+ }
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(memory) = {
+ .name = "memory",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+};
diff --git a/lib/efi_selftest/efi_selftest_snp.c b/lib/efi_selftest/efi_selftest_snp.c
index 09bd53d..e10a34b 100644
--- a/lib/efi_selftest/efi_selftest_snp.c
+++ b/lib/efi_selftest/efi_selftest_snp.c
@@ -103,7 +103,7 @@ static efi_status_t send_dhcp_discover(void)
struct dhcp p = {};
/*
- * Fill ethernet header
+ * Fill Ethernet header
*/
boottime->copy_mem(p.eth_hdr.et_dest, (void *)BROADCAST_MAC, ARP_HLEN);
boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address,
@@ -229,19 +229,19 @@ static int setup(const efi_handle_t handle,
return EFI_ST_FAILURE;
}
/*
- * Initialize network adapter.
+ * Start network adapter.
*/
- ret = net->initialize(net, 0, 0);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Failed to initialize network adapter\n");
+ ret = net->start(net);
+ if (ret != EFI_SUCCESS && ret != EFI_ALREADY_STARTED) {
+ efi_st_error("Failed to start network adapter\n");
return EFI_ST_FAILURE;
}
/*
- * Start network adapter.
+ * Initialize network adapter.
*/
- ret = net->start(net);
+ ret = net->initialize(net, 0, 0);
if (ret != EFI_SUCCESS) {
- efi_st_error("Failed to start network adapter\n");
+ efi_st_error("Failed to initialize network adapter\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
diff --git a/lib/efi_selftest/efi_selftest_textinput.c b/lib/efi_selftest/efi_selftest_textinput.c
index 164fbff..b90671c 100644
--- a/lib/efi_selftest/efi_selftest_textinput.c
+++ b/lib/efi_selftest/efi_selftest_textinput.c
@@ -5,7 +5,7 @@
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
- * The unicode character and the scan code are printed for text
+ * The Unicode character and the scan code are printed for text
* input. To run the test:
*
* setenv efi_selftest text input
diff --git a/lib/efi_selftest/efi_selftest_tpl.c b/lib/efi_selftest/efi_selftest_tpl.c
index 61ae46b..97d256a 100644
--- a/lib/efi_selftest/efi_selftest_tpl.c
+++ b/lib/efi_selftest/efi_selftest_tpl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * efi_selftest_events
+ * efi_selftest_tpl
*
* Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
diff --git a/lib/efi_selftest/efi_selftest_unicode_collation.c b/lib/efi_selftest/efi_selftest_unicode_collation.c
index 9765bd3..7529430 100644
--- a/lib/efi_selftest/efi_selftest_unicode_collation.c
+++ b/lib/efi_selftest/efi_selftest_unicode_collation.c
@@ -52,7 +52,7 @@ static int test_stri_coll(void)
c1, c2);
if (ret) {
efi_st_error(
- "stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c2, ret);
+ "stri_coll(\"%ps\", \"%ps\") = %d\n", c1, c2, (int)ret);
return EFI_ST_FAILURE;
}
@@ -60,7 +60,7 @@ static int test_stri_coll(void)
c1, c3);
if (ret >= 0) {
efi_st_error(
- "stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c3, ret);
+ "stri_coll(\"%ps\", \"%ps\") = %d\n", c1, c3, (int)ret);
return EFI_ST_FAILURE;
}
@@ -68,7 +68,7 @@ static int test_stri_coll(void)
c3, c1);
if (ret <= 0) {
efi_st_error(
- "stri_coll(\"%ps\", \"%ps\") = %zu\n", c3, c1, ret);
+ "stri_coll(\"%ps\", \"%ps\") = %d\n", c3, c1, (int)ret);
return EFI_ST_FAILURE;
}
diff --git a/lib/efi_selftest/efi_selftest_variables.c b/lib/efi_selftest/efi_selftest_variables.c
index 146378f..e4c389a 100644
--- a/lib/efi_selftest/efi_selftest_variables.c
+++ b/lib/efi_selftest/efi_selftest_variables.c
@@ -4,10 +4,8 @@
*
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
- * This unit test checks the following protocol services:
- * ConnectController, DisconnectController,
- * InstallProtocol, ReinstallProtocol, UninstallProtocol,
- * OpenProtocol, CloseProtcol, OpenProtocolInformation
+ * This unit test checks the runtime services for variables:
+ * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
*/
#include <efi_selftest.h>
diff --git a/lib/efi_selftest/efi_selftest_watchdog.c b/lib/efi_selftest/efi_selftest_watchdog.c
index bff2330..cbc6761 100644
--- a/lib/efi_selftest/efi_selftest_watchdog.c
+++ b/lib/efi_selftest/efi_selftest_watchdog.c
@@ -35,7 +35,7 @@ static struct notify_context notification_context;
static bool watchdog_reset;
/*
- * Notification function, increments the notfication count if parameter
+ * Notification function, increments the notification count if parameter
* context is provided.
*
* @event notified event
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index d28f2cb..cbdc077 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -11,6 +11,7 @@
#include <errno.h>
#include <fdtdec.h>
#include <fdt_support.h>
+#include <mapmem.h>
#include <linux/libfdt.h>
#include <serial.h>
#include <asm/sections.h>
@@ -1253,8 +1254,9 @@ int fdtdec_setup(void)
# if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
gd->fdt_blob = (void *)prior_stage_fdt_address;
# else
- gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16,
- (uintptr_t)gd->fdt_blob);
+ gd->fdt_blob = map_sysmem
+ (env_get_ulong("fdtcontroladdr", 16,
+ (unsigned long)map_to_sysmem(gd->fdt_blob)), 0);
# endif
# endif
diff --git a/lib/smbios.c b/lib/smbios.c
index 326eb00..e8ee55c 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -6,6 +6,7 @@
*/
#include <common.h>
+#include <mapmem.h>
#include <smbios.h>
#include <tables_csum.h>
#include <version.h>
@@ -72,9 +73,10 @@ static int smbios_string_table_len(char *start)
static int smbios_write_type0(ulong *current, int handle)
{
- struct smbios_type0 *t = (struct smbios_type0 *)*current;
+ struct smbios_type0 *t;
int len = sizeof(struct smbios_type0);
+ t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type0));
fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle);
t->vendor = smbios_add_string(t->eos, "U-Boot");
@@ -101,16 +103,18 @@ static int smbios_write_type0(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
+ unmap_sysmem(t);
return len;
}
static int smbios_write_type1(ulong *current, int handle)
{
- struct smbios_type1 *t = (struct smbios_type1 *)*current;
+ struct smbios_type1 *t;
int len = sizeof(struct smbios_type1);
char *serial_str = env_get("serial#");
+ t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type1));
fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
@@ -122,15 +126,17 @@ static int smbios_write_type1(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
+ unmap_sysmem(t);
return len;
}
static int smbios_write_type2(ulong *current, int handle)
{
- struct smbios_type2 *t = (struct smbios_type2 *)*current;
+ struct smbios_type2 *t;
int len = sizeof(struct smbios_type2);
+ t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type2));
fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
@@ -140,15 +146,17 @@ static int smbios_write_type2(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
+ unmap_sysmem(t);
return len;
}
static int smbios_write_type3(ulong *current, int handle)
{
- struct smbios_type3 *t = (struct smbios_type3 *)*current;
+ struct smbios_type3 *t;
int len = sizeof(struct smbios_type3);
+ t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type3));
fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
@@ -160,6 +168,7 @@ static int smbios_write_type3(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
+ unmap_sysmem(t);
return len;
}
@@ -198,9 +207,10 @@ static void smbios_write_type4_dm(struct smbios_type4 *t)
static int smbios_write_type4(ulong *current, int handle)
{
- struct smbios_type4 *t = (struct smbios_type4 *)*current;
+ struct smbios_type4 *t;
int len = sizeof(struct smbios_type4);
+ t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type4));
fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle);
t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL;
@@ -214,32 +224,37 @@ static int smbios_write_type4(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
+ unmap_sysmem(t);
return len;
}
static int smbios_write_type32(ulong *current, int handle)
{
- struct smbios_type32 *t = (struct smbios_type32 *)*current;
+ struct smbios_type32 *t;
int len = sizeof(struct smbios_type32);
+ t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type32));
fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle);
*current += len;
+ unmap_sysmem(t);
return len;
}
static int smbios_write_type127(ulong *current, int handle)
{
- struct smbios_type127 *t = (struct smbios_type127 *)*current;
+ struct smbios_type127 *t;
int len = sizeof(struct smbios_type127);
+ t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type127));
fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle);
*current += len;
+ unmap_sysmem(t);
return len;
}
@@ -257,6 +272,7 @@ static smbios_write_type smbios_write_funcs[] = {
ulong write_smbios_table(ulong addr)
{
struct smbios_entry *se;
+ ulong table_addr;
ulong tables;
int len = 0;
int max_struct_size = 0;
@@ -268,7 +284,7 @@ ulong write_smbios_table(ulong addr)
/* 16 byte align the table address */
addr = ALIGN(addr, 16);
- se = (struct smbios_entry *)(uintptr_t)addr;
+ se = map_sysmem(addr, sizeof(struct smbios_entry));
memset(se, 0, sizeof(struct smbios_entry));
addr += sizeof(struct smbios_entry);
@@ -290,7 +306,24 @@ ulong write_smbios_table(ulong addr)
se->max_struct_size = max_struct_size;
memcpy(se->intermediate_anchor, "_DMI_", 5);
se->struct_table_length = len;
- se->struct_table_address = tables;
+
+ /*
+ * We must use a pointer here so things work correctly on sandbox. The
+ * user of this table is not aware of the mapping of addresses to
+ * sandbox's DRAM buffer.
+ */
+ table_addr = (ulong)map_sysmem(tables, 0);
+ if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) {
+ /*
+ * We need to put this >32-bit pointer into the table but the
+ * field is only 32 bits wide.
+ */
+ printf("WARNING: SMBIOS table_address overflow %llx\n",
+ (unsigned long long)table_addr);
+ table_addr = 0;
+ }
+ se->struct_table_address = table_addr;
+
se->struct_count = handle;
/* calculate checksums */
@@ -298,6 +331,7 @@ ulong write_smbios_table(ulong addr)
isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET;
se->intermediate_checksum = table_compute_checksum(istart, isize);
se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry));
+ unmap_sysmem(se);
return addr;
}
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 4dceb6d..a4f16bb 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -381,7 +381,7 @@ $(obj)/%.efi: $(obj)/%_efi.so
quiet_cmd_efi_ld = LD $@
cmd_efi_ld = $(LD) -nostdlib -znocombreloc -T $(EFI_LDS_PATH) -shared \
- -Bsymbolic $^ -o $@
+ -Bsymbolic -s $^ -o $@
EFI_LDS_PATH = $(srctree)/arch/$(ARCH)/lib/$(EFI_LDS)
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index e0833ff..36b35ee 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -8,12 +8,14 @@ import u_boot_utils
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
def test_efi_selftest(u_boot_console):
- """
- Run bootefi selftest
- """
+ """Test the UEFI implementation
+
+ :param u_boot_console: U-Boot console
+ This function executes all selftests that are not marked as on request.
+ """
u_boot_console.run_command(cmd='setenv efi_selftest')
- u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
+ u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0:
raise Exception('Failures occurred during the EFI selftest')