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
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABAgAGBQJcBYKAAAoJECszeR4D/txgBgwQALmYioI67R5/Iizpv7bg+rIQ
 0TyPKZHmfHtVjGHd5X4X+9NBsoaSKqGnoI12bJ+V9hIMuiu5qFKyM3icTOOJ6LI6
 wggnvMWZl5nfZmdEgETHTmaZkQZzKwhzbftGlGf2j19FdDk1OOI7hRNLeaIZUTv0
 VHiUV68PP/1Of1y7iqB5jij1wTUHWlCufKjGXELP0bAXx86/tecgCuvjBihXizz/
 sMsCxEF8++pb5l/l4yFEkKd5rr5D/ZkKMLR4KniZVq2qP1S4calolP14ykHN+a/l
 uKP4e4GDuYyrgXXTNRFhVTlaAn18bmvxH4ialnpYVZKRtfsdHPHQXfqmgf8ZgJPE
 JK3mmG6eLCbBPeND2Yz3b7G/Ec04z+RJXx0hriyLdejLgp5jM9SBtygiz6FmQLpQ
 VfDJNEWV7ot6Ejou55O0d9u5ATF0jAd4tikmsrStWWZOVHvie6nG0wFYiRxnWCKP
 sid0p7lWSUKEl0sAvA0LglNMzd4tCAq7vtkfLj/BVrDc9Jpir9CVJ13ppXIGk1HC
 YIGWLo0uXAGC9wgRE7ZgGCKtQ6VFZRbSiJQOowi4MrHzHXH218oSNz2w25tAVTBw
 le2WbxlGNYhV1xnoWMks1GTdWGQDCXdfBAhfzRIvQq2kz4z9V8hzpnVDIk2ZL3L1
 o3nqUatR0ZVXPcinf+Ke
 =6o9t
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Tom Rini 2018-12-03 17:52:40 -05:00
commit f388e3bed7
65 changed files with 1558 additions and 591 deletions

View file

@ -86,6 +86,7 @@ config DISTRO_DEFAULTS
select SUPPORT_RAW_INITRD select SUPPORT_RAW_INITRD
select SYS_LONGHELP select SYS_LONGHELP
imply CMD_MII if NET imply CMD_MII if NET
imply USB_STORAGE
imply USE_BOOTCOMMAND imply USE_BOOTCOMMAND
help help
Select this to enable various options and commands which are suitable Select this to enable various options and commands which are suitable

View file

@ -2,6 +2,8 @@ Descriptions of section entries:
P: Person (obsolete) P: Person (obsolete)
M: Mail patches to: FullName <address@domain> 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 L: Mailing list that is relevant to this area
W: Web-page with status/info W: Web-page with status/info
Q: Patchwork web based patch tracking system site Q: Patchwork web based patch tracking system site
@ -414,6 +416,7 @@ F: test/dm/
EFI PAYLOAD EFI PAYLOAD
M: Alexander Graf <agraf@suse.de> M: Alexander Graf <agraf@suse.de>
R: Heinrich Schuchardt <xypron.glpk@gmx.de>
S: Maintained S: Maintained
T: git git://github.com/agraf/u-boot.git T: git git://github.com/agraf/u-boot.git
F: doc/README.uefi F: doc/README.uefi

View file

@ -7,6 +7,8 @@
#include <asm/opcodes-sec.h> #include <asm/opcodes-sec.h>
#include <asm/opcodes-virt.h> #include <asm/opcodes-virt.h>
.section .text.efi_runtime
#define UNWIND(x...) #define UNWIND(x...)
/* /*
* Wrap c macros in asm macros to delay expansion until after the * Wrap c macros in asm macros to delay expansion until after the

View file

@ -96,6 +96,7 @@ endmenu
config PSCI_RESET config PSCI_RESET
bool "Use PSCI for reset and shutdown" bool "Use PSCI for reset and shutdown"
default y default y
select ARM_SMCCC if OF_CONTROL
depends on !ARCH_EXYNOS7 && !ARCH_BCM283X && \ depends on !ARCH_EXYNOS7 && !ARCH_BCM283X && \
!TARGET_LS2080A_SIMU && !TARGET_LS2080AQDS && \ !TARGET_LS2080A_SIMU && !TARGET_LS2080AQDS && \
!TARGET_LS2080ARDB && !TARGET_LS2080A_EMU && \ !TARGET_LS2080ARDB && !TARGET_LS2080A_EMU && \

View file

@ -7,7 +7,6 @@
#include <asm-offsets.h> #include <asm-offsets.h>
#include <config.h> #include <config.h>
#include <efi_loader.h>
#include <version.h> #include <version.h>
#include <asm/macro.h> #include <asm/macro.h>
#include <asm/psci.h> #include <asm/psci.h>
@ -19,7 +18,7 @@
* x0~x7: input arguments * x0~x7: input arguments
* x0~x3: output 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( asm volatile(
"ldr x0, %0\n" "ldr x0, %0\n"
@ -53,7 +52,7 @@ static void __efi_runtime hvc_call(struct pt_regs *args)
* x0~x3: output arguments * x0~x3: output arguments
*/ */
void __efi_runtime smc_call(struct pt_regs *args) void smc_call(struct pt_regs *args)
{ {
asm volatile( asm volatile(
"ldr x0, %0\n" "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 * use PSCI on U-Boot running below a hypervisor, please detect
* this and set the flag accordingly. * 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; 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; struct pt_regs regs;
@ -114,44 +113,3 @@ void __noreturn __efi_runtime psci_system_off(void)
while (1) 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 */

View file

@ -6,6 +6,8 @@
#include <linux/arm-smccc.h> #include <linux/arm-smccc.h>
#include <generated/asm-offsets.h> #include <generated/asm-offsets.h>
.section .text.efi_runtime
.macro SMCCC instr .macro SMCCC instr
.cfi_startproc .cfi_startproc
\instr #0 \instr #0

View file

@ -28,13 +28,13 @@ coff_header:
.short 2 /* nr_sections */ .short 2 /* nr_sections */
.long 0 /* TimeDateStamp */ .long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */ .long 0 /* PointerToSymbolTable */
.long 1 /* NumberOfSymbols */ .long 0 /* NumberOfSymbols */
.short section_table - optional_header /* SizeOfOptionalHeader */ .short section_table - optional_header /* SizeOfOptionalHeader */
/* /* Characteristics */
* Characteristics: IMAGE_FILE_DEBUG_STRIPPED | .short (IMAGE_FILE_EXECUTABLE_IMAGE | \
* IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED IMAGE_FILE_LINE_NUMS_STRIPPED | \
*/ IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
.short 0x206 IMAGE_FILE_DEBUG_STRIPPED)
optional_header: optional_header:
.short 0x20b /* PE32+ format */ .short 0x20b /* PE32+ format */
.byte 0x02 /* MajorLinkerVersion */ .byte 0x02 /* MajorLinkerVersion */

View file

@ -27,16 +27,16 @@ coff_header:
.short 2 /* nr_sections */ .short 2 /* nr_sections */
.long 0 /* TimeDateStamp */ .long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */ .long 0 /* PointerToSymbolTable */
.long 1 /* NumberOfSymbols */ .long 0 /* NumberOfSymbols */
.short section_table - optional_header /* SizeOfOptionalHeader */ .short section_table - optional_header /* SizeOfOptionalHeader */
/* /* Characteristics */
* Characteristics: IMAGE_FILE_32BIT_MACHINE | .short (IMAGE_FILE_EXECUTABLE_IMAGE | \
* IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED | \
* IMAGE_FILE_LINE_NUMS_STRIPPED IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
*/ IMAGE_FILE_32BIT_MACHINE | \
.short 0x306 IMAGE_FILE_DEBUG_STRIPPED)
optional_header: optional_header:
.short 0x10b /* PE32+ format */ .short 0x10b /* PE32 format */
.byte 0x02 /* MajorLinkerVersion */ .byte 0x02 /* MajorLinkerVersion */
.byte 0x14 /* MinorLinkerVersion */ .byte 0x14 /* MinorLinkerVersion */
.long _edata - _start /* SizeOfCode */ .long _edata - _start /* SizeOfCode */

View file

@ -41,13 +41,13 @@ coff_header:
.short 2 /* nr_sections */ .short 2 /* nr_sections */
.long 0 /* TimeDateStamp */ .long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */ .long 0 /* PointerToSymbolTable */
.long 1 /* NumberOfSymbols */ .long 0 /* NumberOfSymbols */
.short section_table - optional_header /* SizeOfOptionalHeader */ .short section_table - optional_header /* SizeOfOptionalHeader */
/* /* Characteristics */
* Characteristics: IMAGE_FILE_DEBUG_STRIPPED | .short (IMAGE_FILE_EXECUTABLE_IMAGE | \
* IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED IMAGE_FILE_LINE_NUMS_STRIPPED | \
*/ IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
.short 0x206 IMAGE_FILE_DEBUG_STRIPPED)
optional_header: optional_header:
.short 0x20b /* PE32+ format */ .short 0x20b /* PE32+ format */
.byte 0x02 /* MajorLinkerVersion */ .byte 0x02 /* MajorLinkerVersion */

View file

@ -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 # This is used in the top-level Makefile which does not include
# PLATFORM_LDFLAGS # 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 \ OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
-j .rel -j .rela -j .reloc -j .rel -j .rela -j .reloc
@ -65,7 +65,7 @@ CPPFLAGS_crt0-efi-$(EFIARCH).o += $(CFLAGS_EFI)
ifeq ($(CONFIG_EFI_APP),y) ifeq ($(CONFIG_EFI_APP),y)
PLATFORM_CPPFLAGS += $(CFLAGS_EFI) PLATFORM_CPPFLAGS += $(CFLAGS_EFI)
LDFLAGS_FINAL += -znocombreloc -shared LDFLAGS_FINAL += -znocombreloc -shared -s
LDSCRIPT := $(LDSCRIPT_EFI) LDSCRIPT := $(LDSCRIPT_EFI)
else else

View file

@ -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 * 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. * The FDT is copied to a suitable location within the EFI memory map.
* An additional 12KB is added to the space in case the device tree needs to be * Additional 12 KiB are added to the space in case the device tree needs to be
* expanded later with fdt_open_into(). * expanded later with fdt_open_into().
* *
* @fdt_addr: On entry, address of start of FDT. On exit, address of relocated * @fdtp: On entry a pointer to the flattened device tree.
* FDT start * On exit a pointer to the copy of the flattened device tree.
* @fdt_sizep: Returns new size of FDT, including * FDT start
* @return new relocated address of FDT * 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; unsigned long fdt_ram_start = -1L, fdt_pages;
efi_status_t ret = 0; 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 * Give us at least 12 KiB of breathing room in case the device tree
* to be expanded later. Round up to the nearest EFI page boundary. * needs to be expanded later.
*/ */
fdt = map_sysmem(*fdt_addrp, 0); fdt = *fdtp;
fdt_size = fdt_totalsize(fdt); fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
fdt_size += 4096 * 3; fdt_size = fdt_pages << EFI_PAGE_SHIFT;
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; * 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, ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
EFI_RUNTIME_SERVICES_DATA, fdt_pages, EFI_RUNTIME_SERVICES_DATA, fdt_pages,
&new_fdt_addr); &new_fdt_addr);
@ -203,13 +205,11 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
goto done; goto done;
} }
} }
new_fdt = (void *)(uintptr_t)new_fdt_addr;
new_fdt = map_sysmem(new_fdt_addr, fdt_size);
memcpy(new_fdt, fdt, fdt_totalsize(fdt)); memcpy(new_fdt, fdt, fdt_totalsize(fdt));
fdt_set_totalsize(new_fdt, fdt_size); fdt_set_totalsize(new_fdt, fdt_size);
*fdt_addrp = new_fdt_addr; *fdtp = (void *)(uintptr_t)new_fdt_addr;
*fdt_sizep = fdt_size;
done: done:
return ret; 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) if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
continue; 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, if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
false)) false))
printf("FDT memrsv map %d: Failed to add to map\n", i); 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) static efi_status_t efi_install_fdt(ulong fdt_addr)
{ {
bootm_headers_t img = { 0 }; bootm_headers_t img = { 0 };
ulong fdt_pages, fdt_size, fdt_start;
efi_status_t ret; efi_status_t ret;
void *fdt; void *fdt;
@ -297,36 +300,60 @@ static efi_status_t efi_install_fdt(ulong fdt_addr)
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
/* Create memory reservation as indicated by the device tree */
efi_carve_out_dt_rsv(fdt);
/* Prepare fdt for payload */ /* Prepare fdt for payload */
ret = copy_fdt(&fdt_addr, &fdt_size); ret = copy_fdt(&fdt);
if (ret) if (ret)
return 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)) { if (image_setup_libfdt(&img, fdt, 0, NULL)) {
printf("ERROR: failed to process device tree\n"); printf("ERROR: failed to process device tree\n");
return EFI_LOAD_ERROR; return EFI_LOAD_ERROR;
} }
efi_carve_out_dt_rsv(fdt);
/* Link to it in the efi tables */ /* Link to it in the efi tables */
ret = efi_install_configuration_table(&efi_guid_fdt, fdt); ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
/* And reserve the space in the memory map */
fdt_start = fdt_addr;
fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
ret = efi_add_memory_map(fdt_start, fdt_pages,
EFI_BOOT_SERVICES_DATA, true);
return ret; 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_setup_loaded_image(device_path, image_path, image_objp,
loaded_image_infop);
if (ret != EFI_SUCCESS)
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);
}
/** /**
* do_bootefi_exec() - execute EFI binary * do_bootefi_exec() - execute EFI binary
* *
@ -345,7 +372,7 @@ static efi_status_t do_bootefi_exec(void *efi,
efi_handle_t mem_handle = NULL; efi_handle_t mem_handle = NULL;
struct efi_device_path *memdp = NULL; struct efi_device_path *memdp = NULL;
efi_status_t ret; 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; struct efi_loaded_image *loaded_image_info = NULL;
EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, 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 * Special case for efi payload not loaded from disk, such as
* 'bootefi hello' or for example payload loaded directly into * 'bootefi hello' or for example payload loaded directly into
* memory via jtag, etc: * memory via JTAG, etc:
*/ */
if (!device_path && !image_path) { if (!device_path && !image_path) {
printf("WARNING: using memory device/image path, this may confuse some payloads!\n"); 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); ret = efi_create_handle(&mem_handle);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
goto exit; return ret; /* TODO: leaks device_path */
ret = efi_add_protocol(mem_handle, &efi_guid_device_path, ret = efi_add_protocol(mem_handle, &efi_guid_device_path,
device_path); device_path);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
goto exit; goto err_add_protocol;
} else { } else {
assert(device_path && image_path); assert(device_path && image_path);
} }
ret = efi_setup_loaded_image(device_path, image_path, &image_handle, ret = bootefi_run_prepare("bootargs", device_path, image_path,
&loaded_image_info); &image_obj, &loaded_image_info);
if (ret != EFI_SUCCESS) if (ret)
goto exit; goto err_prepare;
/* Transfer environment variable bootargs as load options */
set_load_options(loaded_image_info, "bootargs");
/* Load the EFI payload */ /* 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) { if (!entry) {
ret = EFI_LOAD_ERROR; ret = EFI_LOAD_ERROR;
goto exit; goto err_prepare;
} }
if (memdp) { if (memdp) {
@ -405,9 +430,9 @@ static efi_status_t do_bootefi_exec(void *efi,
/* Call our payload! */ /* Call our payload! */
debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
if (setjmp(&image_handle->exit_jmp)) { if (setjmp(&image_obj->exit_jmp)) {
ret = image_handle->exit_status; ret = image_obj->exit_status;
goto exit; goto err_prepare;
} }
#ifdef CONFIG_ARM64 #ifdef CONFIG_ARM64
@ -418,7 +443,7 @@ static efi_status_t do_bootefi_exec(void *efi,
/* Move into EL2 and keep running there */ /* Move into EL2 and keep running there */
armv8_switch_to_el2((ulong)entry, armv8_switch_to_el2((ulong)entry,
(ulong)image_handle, (ulong)&image_obj->header,
(ulong)&systab, 0, (ulong)efi_run_in_el2, (ulong)&systab, 0, (ulong)efi_run_in_el2,
ES_TO_AARCH64); ES_TO_AARCH64);
@ -435,7 +460,7 @@ static efi_status_t do_bootefi_exec(void *efi,
secure_ram_addr(_do_nonsec_entry)( secure_ram_addr(_do_nonsec_entry)(
efi_run_in_hyp, efi_run_in_hyp,
(uintptr_t)entry, (uintptr_t)entry,
(uintptr_t)image_handle, (uintptr_t)&image_obj->header,
(uintptr_t)&systab); (uintptr_t)&systab);
/* Should never reach here, efi exits with longjmp */ /* Should never reach here, efi exits with longjmp */
@ -443,18 +468,59 @@ static efi_status_t do_bootefi_exec(void *efi,
} }
#endif #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*: */ /* image has returned, loaded-image obj goes *poof*: */
if (image_handle) bootefi_run_finish(image_obj, loaded_image_info);
efi_delete_handle(&image_handle->parent);
err_add_protocol:
if (mem_handle) if (mem_handle)
efi_delete_handle(mem_handle); efi_delete_handle(mem_handle);
return ret; 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) static int do_bootefi_bootmgr_exec(void)
{ {
struct efi_device_path *device_path, *file_path; 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 #endif
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
if (!strcmp(argv[1], "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; struct efi_loaded_image *loaded_image_info;
/* Construct a dummy device path. */ if (bootefi_test_prepare(&image_obj, &loaded_image_info,
bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, "\\selftest", (uintptr_t)&efi_selftest,
(uintptr_t)&efi_selftest, "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)
return CMD_RET_FAILURE; 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 */ /* Execute the test */
r = efi_selftest(image_handle, &systab); r = efi_selftest(&image_obj->header, &systab);
efi_restore_gd(); bootefi_run_finish(image_obj, loaded_image_info);
free(loaded_image_info->load_options);
efi_delete_handle(&image_handle->parent);
return r != EFI_SUCCESS; return r != EFI_SUCCESS;
} else } else
#endif #endif
@ -608,45 +662,19 @@ U_BOOT_CMD(
void efi_set_bootdev(const char *dev, const char *devnr, const char *path) void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
{ {
char filename[32] = { 0 }; /* dp->str is u16[32] long */ struct efi_device_path *device, *image;
char *s; efi_status_t ret;
/* efi_set_bootdev is typically called repeatedly, recover memory */ /* efi_set_bootdev is typically called repeatedly, recover memory */
efi_free_pool(bootefi_device_path); efi_free_pool(bootefi_device_path);
efi_free_pool(bootefi_image_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")) { ret = efi_dp_from_name(dev, devnr, path, &device, &image);
struct blk_desc *desc; if (ret == EFI_SUCCESS) {
disk_partition_t fs_partition; bootefi_device_path = device;
int part; bootefi_image_path = image;
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 { } else {
#ifdef CONFIG_NET bootefi_device_path = NULL;
bootefi_device_path = efi_dp_from_eth(); bootefi_image_path = NULL;
#endif
} }
if (!path)
return;
if (strcmp(dev, "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++ = '\\';
bootefi_image_path = efi_dp_from_file(NULL, 0, filename);
} }

View file

@ -453,7 +453,8 @@ static int initr_env(void)
else else
set_default_env(NULL, 0); set_default_env(NULL, 0);
#ifdef CONFIG_OF_CONTROL #ifdef CONFIG_OF_CONTROL
env_set_addr("fdtcontroladdr", gd->fdt_blob); env_set_hex("fdtcontroladdr",
(unsigned long)map_to_sysmem(gd->fdt_blob));
#endif #endif
/* Initialize from environment */ /* Initialize from environment */

View file

@ -7,6 +7,7 @@
*/ */
#include <common.h> #include <common.h>
#include <mapmem.h>
#include <stdio_dev.h> #include <stdio_dev.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/types.h> #include <linux/types.h>
@ -633,7 +634,7 @@ int fdt_shrink_to_minimum(void *blob, uint extrasize)
fdt_set_totalsize(blob, actualsize); fdt_set_totalsize(blob, actualsize);
/* Add the new reservation */ /* 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) if (ret < 0)
return ret; return ret;

View file

@ -41,4 +41,4 @@ CONFIG_PHY_MICREL=y
CONFIG_MII=y CONFIG_MII=y
CONFIG_DM_SERIAL=y CONFIG_DM_SERIAL=y
CONFIG_FSL_LPUART=y CONFIG_FSL_LPUART=y
# CONFIG_EFI_UNICODE_CAPITALIZATION is not set # CONFIG_EFI_LOADER is not set

View file

@ -41,4 +41,4 @@ CONFIG_PHY_MICREL=y
CONFIG_MII=y CONFIG_MII=y
CONFIG_DM_SERIAL=y CONFIG_DM_SERIAL=y
CONFIG_FSL_LPUART=y CONFIG_FSL_LPUART=y
# CONFIG_EFI_UNICODE_CAPITALIZATION is not set # CONFIG_EFI_LOADER is not set

View file

@ -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 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 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 iPXE can be built as an EFI application (named snp.efi) which can be loaded and
run by U-Boot. run by U-Boot.
Boot sequence ## Boot sequence
-------------
U-Boot loads the EFI application iPXE snp.efi using the bootefi command. This 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 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 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 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 the iSCSI traffic from all other network traffic. This can be achieved using a
virtual local area network (VLAN). virtual local area network (VLAN).
Configuration ## Configuration
-------------
iPXE ### iPXE
^^^^
For running iPXE on arm64 the bin-arm64-efi/snp.efi build target is needed:: 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_NFS /* Network File System Protocol */
#define DOWNLOAD_PROTO_FILE /* Local file system access */ #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 * [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/ - * [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

View file

@ -9,31 +9,38 @@
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <dm/lists.h> #include <dm/lists.h>
#include <efi_loader.h>
#include <linux/libfdt.h> #include <linux/libfdt.h>
#include <linux/arm-smccc.h> #include <linux/arm-smccc.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/psci.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, #define PSCI_METHOD_HVC 1
unsigned long arg0, unsigned long arg1, #define PSCI_METHOD_SMC 2
unsigned long arg2)
int __efi_runtime_data psci_method;
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; struct arm_smccc_res res;
arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); /*
return res.a0; * 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
static unsigned long __invoke_psci_fn_smc(unsigned long function_id, * called.
unsigned long arg0, unsigned long arg1, */
unsigned long arg2) if (psci_method == PSCI_METHOD_SMC)
{ arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
struct arm_smccc_res res; else if (psci_method == PSCI_METHOD_HVC)
arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); else
res.a0 = PSCI_RET_DISABLED;
return res.a0; return res.a0;
} }
@ -67,9 +74,9 @@ static int psci_probe(struct udevice *dev)
} }
if (!strcmp("hvc", method)) { if (!strcmp("hvc", method)) {
invoke_psci_fn = __invoke_psci_fn_hvc; psci_method = PSCI_METHOD_HVC;
} else if (!strcmp("smc", method)) { } else if (!strcmp("smc", method)) {
invoke_psci_fn = __invoke_psci_fn_smc; psci_method = PSCI_METHOD_SMC;
} else { } else {
pr_warn("invalid \"method\" property: %s\n", method); pr_warn("invalid \"method\" property: %s\n", method);
return -EINVAL; return -EINVAL;
@ -78,6 +85,67 @@ static int psci_probe(struct udevice *dev)
return 0; 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[] = { static const struct udevice_id psci_of_match[] = {
{ .compatible = "arm,psci" }, { .compatible = "arm,psci" },
{ .compatible = "arm,psci-0.2" }, { .compatible = "arm,psci-0.2" },
@ -86,7 +154,7 @@ static const struct udevice_id psci_of_match[] = {
}; };
U_BOOT_DRIVER(psci) = { U_BOOT_DRIVER(psci) = {
.name = "psci", .name = DRIVER_NAME,
.id = UCLASS_FIRMWARE, .id = UCLASS_FIRMWARE,
.of_match = psci_of_match, .of_match = psci_of_match,
.bind = psci_bind, .bind = psci_bind,

View file

@ -70,6 +70,7 @@ comment "USB peripherals"
config USB_STORAGE config USB_STORAGE
bool "USB Mass Storage support" bool "USB Mass Storage support"
depends on !(BLK && !DM_USB)
---help--- ---help---
Say Y here if you want to connect USB mass storage devices to your Say Y here if you want to connect USB mass storage devices to your
board's USB port. board's USB port.

View file

@ -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++) { for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
if (!info->probe(fs_dev_desc, &fs_partition)) { if (!info->probe(fs_dev_desc, &fs_partition)) {
fs_type = info->fstype; fs_type = info->fstype;
fs_dev_part = part;
return 0; return 0;
} }
} }

View file

@ -11,6 +11,24 @@
#ifndef _ASM_PE_H #ifndef _ASM_PE_H
#define _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 */ /* Subsystem type */
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11

View file

@ -105,6 +105,17 @@ int mdm_init(void);
*/ */
void board_show_dram(phys_size_t size); 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 * arch_fixup_fdt() - Write arch-specific information to fdt
* *

View file

@ -96,7 +96,7 @@ typedef struct {
typedef unsigned long efi_status_t; typedef unsigned long efi_status_t;
typedef u64 efi_physical_addr_t; typedef u64 efi_physical_addr_t;
typedef u64 efi_virtual_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) \ #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \ {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \

View file

@ -85,10 +85,10 @@ struct efi_boot_services {
efi_status_t (EFIAPI *check_event)(struct efi_event *event); efi_status_t (EFIAPI *check_event)(struct efi_event *event);
#define EFI_NATIVE_INTERFACE 0x00000000 #define EFI_NATIVE_INTERFACE 0x00000000
efi_status_t (EFIAPI *install_protocol_interface)( 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); int protocol_interface_type, void *protocol_interface);
efi_status_t (EFIAPI *reinstall_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); void *old_interface, void *new_interface);
efi_status_t (EFIAPI *uninstall_protocol_interface)( efi_status_t (EFIAPI *uninstall_protocol_interface)(
efi_handle_t handle, const efi_guid_t *protocol, 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, efi_status_t (EFIAPI *locate_protocol)(const efi_guid_t *protocol,
void *registration, void **protocol_interface); void *registration, void **protocol_interface);
efi_status_t (EFIAPI *install_multiple_protocol_interfaces)( efi_status_t (EFIAPI *install_multiple_protocol_interfaces)(
void **handle, ...); efi_handle_t *handle, ...);
efi_status_t (EFIAPI *uninstall_multiple_protocol_interfaces)( efi_status_t (EFIAPI *uninstall_multiple_protocol_interfaces)(
void *handle, ...); efi_handle_t handle, ...);
efi_status_t (EFIAPI *calculate_crc32)(const void *data, efi_status_t (EFIAPI *calculate_crc32)(const void *data,
efi_uintn_t data_size, efi_uintn_t data_size,
u32 *crc32); u32 *crc32);
@ -241,8 +241,8 @@ struct efi_runtime_services {
efi_status_t (EFIAPI *query_capsule_caps)( efi_status_t (EFIAPI *query_capsule_caps)(
struct efi_capsule_header **capsule_header_array, struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count, efi_uintn_t capsule_count,
u64 maximum_capsule_size, u64 *maximum_capsule_size,
u32 reset_type); u32 *reset_type);
efi_status_t (EFIAPI *query_variable_info)( efi_status_t (EFIAPI *query_variable_info)(
u32 attributes, u32 attributes,
u64 *maximum_variable_storage_size, u64 *maximum_variable_storage_size,
@ -965,7 +965,7 @@ struct efi_file_info {
struct efi_time last_access_time; struct efi_time last_access_time;
struct efi_time modification_time; struct efi_time modification_time;
u64 attribute; u64 attribute;
s16 file_name[0]; u16 file_name[0];
}; };
struct efi_file_system_info { struct efi_file_system_info {

View file

@ -167,28 +167,41 @@ struct efi_handler {
struct list_head open_infos; struct list_head open_infos;
}; };
/* /**
* UEFI has a poor man's OO model where one "object" can be polymorphic and have * struct efi_object - dereferenced EFI handle
* multiple different protocols (classes) attached to it.
* *
* This struct is the parent struct for all of our actual implementation objects * @link: pointers to put the handle into a linked list
* that can include it to make themselves an EFI object * @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.
*
* 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 { struct efi_object {
/* Every UEFI object is part of a global object list */ /* Every UEFI object is part of a global object list */
struct list_head link; struct list_head link;
/* The list of protocols */ /* The list of protocols */
struct list_head 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 * 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 { struct efi_loaded_image_obj {
/* Generic EFI object parent class data */ struct efi_object header;
struct efi_object parent;
void *reloc_base; void *reloc_base;
aligned_u64 reloc_size; aligned_u64 reloc_size;
efi_status_t exit_status; 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 */ /* Call this to set the current device name */
void efi_set_bootdev(const char *dev, const char *devnr, const char *path); void efi_set_bootdev(const char *dev, const char *devnr, const char *path);
/* Add a new object to the object list. */ /* 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 */ /* Create handle */
efi_status_t efi_create_handle(efi_handle_t *handle); efi_status_t efi_create_handle(efi_handle_t *handle);
/* Delete 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 */ /* Call this to validate a handle and find the EFI object for it */
struct efi_object *efi_search_obj(const efi_handle_t handle); struct efi_object *efi_search_obj(const efi_handle_t handle);
/* Find a protocol on a 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: */ /* open file from device-path: */
struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp); 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 */ /* Generic EFI memory allocator, call this to get memory */
void *efi_alloc(uint64_t len, int memory_type); void *efi_alloc(uint64_t len, int memory_type);
/* More specific EFI memory allocator, called by EFI payloads */ /* 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, efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
struct efi_device_path **device_path, struct efi_device_path **device_path,
struct efi_device_path **file_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) \ #define EFI_DP_TYPE(_dp, _type, _subtype) \
(((_dp)->type == DEVICE_PATH_TYPE_##_type) && \ (((_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, u32 attributes, efi_uintn_t data_size,
void *data); 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, void *efi_bootmgr_load(struct efi_device_path **device_path,
struct efi_device_path **file_path); struct efi_device_path **file_path);

View file

@ -129,7 +129,6 @@ u16 efi_st_get_key(void);
* @setup: set up the unit test * @setup: set up the unit test
* @teardown: tear down the unit test * @teardown: tear down the unit test
* @execute: execute the unit test * @execute: execute the unit test
* @setup_ok: setup was successful (set at runtime)
* @on_request: test is only executed on request * @on_request: test is only executed on request
*/ */
struct efi_unit_test { struct efi_unit_test {
@ -139,7 +138,6 @@ struct efi_unit_test {
const struct efi_system_table *systable); const struct efi_system_table *systable);
int (*execute)(void); int (*execute)(void);
int (*teardown)(void); int (*teardown)(void);
int setup_ok;
bool on_request; bool on_request;
}; };

View file

@ -88,10 +88,8 @@
#define PSCI_RET_DISABLED -8 #define PSCI_RET_DISABLED -8
#ifdef CONFIG_ARM_PSCI_FW #ifdef CONFIG_ARM_PSCI_FW
typedef unsigned long (psci_fn)(unsigned long, unsigned long, unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1,
unsigned long, unsigned long); unsigned long a2, unsigned long a3);
extern psci_fn *invoke_psci_fn;
#else #else
unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1, unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3) unsigned long a2, unsigned long a3)

View file

@ -8,7 +8,7 @@ ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_EFI) += efi/
obj-$(CONFIG_EFI_LOADER) += efi_driver/ obj-$(CONFIG_EFI_LOADER) += efi_driver/
obj-$(CONFIG_EFI_LOADER) += efi_loader/ 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_LZMA) += lzma/
obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_BZIP2) += bzip2/
obj-$(CONFIG_TIZEN) += tizen/ obj-$(CONFIG_TIZEN) += tizen/

View file

@ -69,7 +69,7 @@ int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image,
efi_putc(priv, ' '); efi_putc(priv, ' ');
ret = boot->open_protocol(priv->parent_image, &loaded_image_guid, 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); NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret) { if (ret) {
efi_puts(priv, "Failed to get loaded image protocol\n"); efi_puts(priv, "Failed to get loaded image protocol\n");

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: GPL-2.0+
/* /*
* EFI utils * EFI boot manager
* *
* Copyright (c) 2017 Rob Clark * Copyright (c) 2017 Rob Clark
*/ */
@ -9,6 +9,7 @@
#include <charset.h> #include <charset.h>
#include <malloc.h> #include <malloc.h>
#include <efi_loader.h> #include <efi_loader.h>
#include <asm/unaligned.h>
static const struct efi_boot_services *bs; static const struct efi_boot_services *bs;
static const struct efi_runtime_services *rs; static const struct efi_runtime_services *rs;
@ -30,42 +31,68 @@ static const struct efi_runtime_services *rs;
*/ */
/* /* Parse serialized data and transform it into efi_load_option structure */
* See section 3.1.3 in the v2.7 UEFI spec for more details on void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data)
* 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)
{ {
lo->attributes = *(u32 *)ptr; lo->attributes = get_unaligned_le32(data);
ptr += sizeof(u32); data += sizeof(u32);
lo->file_path_length = *(u16 *)ptr; lo->file_path_length = get_unaligned_le16(data);
ptr += sizeof(u16); data += sizeof(u16);
lo->label = ptr; /* FIXME */
ptr += (u16_strlen(lo->label) + 1) * 2; lo->label = (u16 *)data;
data += (u16_strlen(lo->label) + 1) * sizeof(u16);
lo->file_path = ptr; /* FIXME */
ptr += lo->file_path_length; lo->file_path = (struct efi_device_path *)data;
data += lo->file_path_length;
lo->optional_data = ptr; lo->optional_data = data;
}
/*
* 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 */ /* 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, static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
struct efi_device_path **file_path) struct efi_device_path **file_path)
{ {
struct load_option lo; struct efi_load_option lo;
u16 varname[] = L"Boot0000"; u16 varname[] = L"Boot0000";
u16 hexmap[] = L"0123456789ABCDEF"; u16 hexmap[] = L"0123456789ABCDEF";
void *load_option, *image = NULL; 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) if (!load_option)
return NULL; return NULL;
parse_load_option(&lo, load_option); efi_deserialize_load_option(&lo, load_option);
if (lo.attributes & LOAD_OPTION_ACTIVE) { if (lo.attributes & LOAD_OPTION_ACTIVE) {
efi_status_t ret; efi_status_t ret;

View file

@ -26,6 +26,14 @@ LIST_HEAD(efi_obj_list);
/* List of all events */ /* List of all events */
LIST_HEAD(efi_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 #ifdef CONFIG_ARM
/* /*
* The "gd" pointer lives in a register on ARM and AArch64 that we declare * 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. * 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; return;
INIT_LIST_HEAD(&obj->protocols); INIT_LIST_HEAD(&handle->protocols);
obj->handle = obj; list_add_tail(&handle->link, &efi_obj_list);
list_add_tail(&obj->link, &efi_obj_list);
} }
/** /**
@ -440,7 +447,7 @@ efi_status_t efi_create_handle(efi_handle_t *handle)
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
efi_add_handle(obj); efi_add_handle(obj);
*handle = obj->handle; *handle = obj;
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -536,13 +543,13 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
* *
* @obj: handle to delete * @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; return;
efi_remove_all_protocols(obj->handle); efi_remove_all_protocols(handle);
list_del(&obj->link); list_del(&handle->link);
free(obj); free(handle);
} }
/** /**
@ -927,7 +934,7 @@ struct efi_object *efi_search_obj(const efi_handle_t handle)
struct efi_object *efiobj; struct efi_object *efiobj;
list_for_each_entry(efiobj, &efi_obj_list, link) { list_for_each_entry(efiobj, &efi_obj_list, link) {
if (efiobj->handle == handle) if (efiobj == handle)
return efiobj; return efiobj;
} }
@ -1019,7 +1026,7 @@ efi_status_t efi_add_protocol(const efi_handle_t handle,
* Return: status code * Return: status code
*/ */
static efi_status_t EFIAPI efi_install_protocol_interface( 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) int protocol_interface_type, void *protocol_interface)
{ {
efi_status_t r; efi_status_t r;
@ -1052,7 +1059,7 @@ out:
/** /**
* efi_get_drivers() - get all drivers associated to a controller * efi_get_drivers() - get all drivers associated to a controller
* @efiobj: handle of the controller * @handle: handle of the controller
* @protocol: protocol GUID (optional) * @protocol: protocol GUID (optional)
* @number_of_drivers: number of child controllers * @number_of_drivers: number of child controllers
* @driver_handle_buffer: handles of the the drivers * @driver_handle_buffer: handles of the the drivers
@ -1061,7 +1068,7 @@ out:
* *
* Return: status code * 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, const efi_guid_t *protocol,
efi_uintn_t *number_of_drivers, efi_uintn_t *number_of_drivers,
efi_handle_t **driver_handle_buffer) efi_handle_t **driver_handle_buffer)
@ -1072,7 +1079,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
bool duplicate; bool duplicate;
/* Count all driver associations */ /* 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)) if (protocol && guidcmp(handler->guid, protocol))
continue; continue;
list_for_each_entry(item, &handler->open_infos, link) { 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) if (!*driver_handle_buffer)
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
/* Collect unique driver handles */ /* 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)) if (protocol && guidcmp(handler->guid, protocol))
continue; continue;
list_for_each_entry(item, &handler->open_infos, link) { 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 * efi_disconnect_all_drivers() - disconnect all drivers from a controller
* @efiobj: handle of the controller * @handle: handle of the controller
* @protocol: protocol GUID (optional) * @protocol: protocol GUID (optional)
* @child_handle: handle of the child to destroy * @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 * Return: status code
*/ */
static efi_status_t efi_disconnect_all_drivers( static efi_status_t efi_disconnect_all_drivers
struct efi_object *efiobj, (efi_handle_t handle,
const efi_guid_t *protocol, const efi_guid_t *protocol,
efi_handle_t child_handle) efi_handle_t child_handle)
{ {
efi_uintn_t number_of_drivers; efi_uintn_t number_of_drivers;
efi_handle_t *driver_handle_buffer; efi_handle_t *driver_handle_buffer;
efi_status_t r, ret; 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); &driver_handle_buffer);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
return ret; return ret;
@ -1145,7 +1152,7 @@ static efi_status_t efi_disconnect_all_drivers(
ret = EFI_NOT_FOUND; ret = EFI_NOT_FOUND;
while (number_of_drivers) { while (number_of_drivers) {
r = EFI_CALL(efi_disconnect_controller( r = EFI_CALL(efi_disconnect_controller(
efiobj->handle, handle,
driver_handle_buffer[--number_of_drivers], driver_handle_buffer[--number_of_drivers],
child_handle)); child_handle));
if (r == EFI_SUCCESS) 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 * @handle: handle from which the protocol shall be removed
* @protocol: GUID of the protocol to be removed * @protocol: GUID of the protocol to be removed
* @protocol_interface: interface to be removed * @protocol_interface: interface to be removed
* *
* This function implements the UninstallProtocolInterface service. * This function DOES NOT delete a handle without installed protocol.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
* *
* Return: status code * Return: status code
*/ */
static efi_status_t EFIAPI efi_uninstall_protocol_interface( static efi_status_t efi_uninstall_protocol
efi_handle_t handle, const efi_guid_t *protocol, (efi_handle_t handle, const efi_guid_t *protocol,
void *protocol_interface) void *protocol_interface)
{ {
struct efi_object *efiobj; struct efi_object *efiobj;
struct efi_handler *handler; struct efi_handler *handler;
@ -1178,8 +1183,6 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(
struct efi_open_protocol_info_item *pos; struct efi_open_protocol_info_item *pos;
efi_status_t r; efi_status_t r;
EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface);
/* Check handle */ /* Check handle */
efiobj = efi_search_obj(handle); efiobj = efi_search_obj(handle);
if (!efiobj) { if (!efiobj) {
@ -1210,7 +1213,41 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(
} }
r = efi_remove_protocol(handle, protocol, protocol_interface); r = efi_remove_protocol(handle, protocol, protocol_interface);
out: 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 * @search_type: selection criterion
* @protocol: GUID of the protocol * @protocol: GUID of the protocol
* @search_key: registration key * @search_key: registration key
* @efiobj: handle * @handle: handle
* *
* See the documentation of the LocateHandle service in the UEFI specification. * 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, static int efi_search(enum efi_locate_search_type search_type,
const efi_guid_t *protocol, void *search_key, const efi_guid_t *protocol, void *search_key,
struct efi_object *efiobj) efi_handle_t handle)
{ {
efi_status_t ret; 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 */ /* TODO: RegisterProtocolNotify is not implemented yet */
return -1; return -1;
case BY_PROTOCOL: case BY_PROTOCOL:
ret = efi_search_protocol(efiobj->handle, protocol, NULL); ret = efi_search_protocol(handle, protocol, NULL);
return (ret != EFI_SUCCESS); return (ret != EFI_SUCCESS);
default: default:
/* Invalid search type */ /* Invalid search type */
@ -1331,7 +1368,7 @@ static efi_status_t efi_locate_handle(
/* Then fill the array */ /* Then fill the array */
list_for_each_entry(efiobj, &efi_obj_list, link) { list_for_each_entry(efiobj, &efi_obj_list, link) {
if (!efi_search(search_type, protocol, search_key, efiobj)) if (!efi_search(search_type, protocol, search_key, efiobj))
*buffer++ = efiobj->handle; *buffer++ = efiobj;
} }
return EFI_SUCCESS; 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 */ /* Add internal object to object list */
efi_add_handle(&obj->parent); efi_add_handle(&obj->header);
if (info_ptr) if (info_ptr)
*info_ptr = info; *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 * When asking for the device path interface, return
* bootefi_device_path * bootefi_device_path
*/ */
ret = efi_add_protocol(obj->parent.handle, ret = efi_add_protocol(&obj->header,
&efi_guid_device_path, device_path); &efi_guid_device_path, device_path);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
goto failure; 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 * When asking for the loaded_image interface, just
* return handle which points to loaded_image_info * 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); &efi_guid_loaded_image, info);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
goto failure; 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_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
efi_is_direct_boot = false;
/* call the image! */ /* call the image! */
if (setjmp(&image_obj->exit_jmp)) { if (setjmp(&image_obj->exit_jmp)) {
/* /*
@ -1785,6 +1824,21 @@ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
return EFI_EXIT(EFI_SUCCESS); return EFI_EXIT(EFI_SUCCESS);
} }
/**
* 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 * efi_exit_boot_services() - stop all boot services
* @image_handle: handle of the loaded image * @image_handle: handle of the loaded image
@ -1838,6 +1892,9 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
board_quiesce_devices(); board_quiesce_devices();
/* Fix up caches for EFI payloads if necessary */
efi_exit_caches();
/* This stops all lingering devices */ /* This stops all lingering devices */
bootm_disable_interrupts(); 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); 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) { if (ret == EFI_SUCCESS) {
*protocol_interface = handler->protocol_interface; *protocol_interface = handler->protocol_interface;
return EFI_EXIT(EFI_SUCCESS); return EFI_EXIT(EFI_SUCCESS);
@ -2279,8 +2336,8 @@ out:
* *
* Return: status code * Return: status code
*/ */
static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces
void **handle, ...) (efi_handle_t *handle, ...)
{ {
EFI_ENTRY("%p", handle); EFI_ENTRY("%p", handle);
@ -2316,7 +2373,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
for (; i; --i) { for (; i; --i) {
protocol = efi_va_arg(argptr, efi_guid_t*); protocol = efi_va_arg(argptr, efi_guid_t*);
protocol_interface = efi_va_arg(argptr, void*); 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)); protocol_interface));
} }
efi_va_end(argptr); efi_va_end(argptr);
@ -2339,7 +2396,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
* Return: status code * Return: status code
*/ */
static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
void *handle, ...) efi_handle_t handle, ...)
{ {
EFI_ENTRY("%p", handle); EFI_ENTRY("%p", handle);
@ -2358,16 +2415,21 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
if (!protocol) if (!protocol)
break; break;
protocol_interface = efi_va_arg(argptr, void*); protocol_interface = efi_va_arg(argptr, void*);
r = EFI_CALL(efi_uninstall_protocol_interface( r = efi_uninstall_protocol(handle, protocol,
handle, protocol, protocol_interface);
protocol_interface));
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
break; break;
i++; i++;
} }
efi_va_end(argptr); 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); return EFI_EXIT(r);
}
/* If an error occurred undo all changes. */ /* If an error occurred undo all changes. */
efi_va_start(argptr, handle); efi_va_start(argptr, handle);
@ -2380,7 +2442,8 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
} }
efi_va_end(argptr); 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 * Return: status code
*/ */
static efi_status_t EFIAPI efi_open_protocol( static efi_status_t EFIAPI efi_open_protocol
void *handle, const efi_guid_t *protocol, (efi_handle_t handle, const efi_guid_t *protocol,
void **protocol_interface, void *agent_handle, void **protocol_interface, efi_handle_t agent_handle,
void *controller_handle, uint32_t attributes) efi_handle_t controller_handle, uint32_t attributes)
{ {
struct efi_handler *handler; struct efi_handler *handler;
efi_status_t r = EFI_INVALID_PARAMETER; 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, EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface,
new_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) if (ret != EFI_SUCCESS)
goto out; goto out;
ret = EFI_CALL(efi_install_protocol_interface(&handle, protocol,
EFI_NATIVE_INTERFACE, /* Install the new protocol */
new_interface)); 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) if (ret != EFI_SUCCESS)
goto out; goto out;
/* /*

View file

@ -205,7 +205,7 @@ static int query_console_serial(int *rows, int *cols)
/* /*
* Not all terminals understand CSI [18t for querying the console size. * Not all terminals understand CSI [18t for querying the console size.
* We should adhere to escape sequences documented in the console_codes * 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 * So here we follow a different approach. We position the cursor to the
* bottom right and query its position. Before leaving the function we * 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. * This gets called when we have already parsed CSI.
* *
* @modifiers: bitmask (shift, alt, ctrl) * @modifiers: bit mask (shift, alt, ctrl)
* @return: the unmodified code * @return: the unmodified code
*/ */
static int analyze_modifiers(struct efi_key_state *key_state) 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 efi_console_register(void)
{ {
efi_status_t r; efi_status_t r;
struct efi_object *efi_console_output_obj; efi_handle_t console_output_handle;
struct efi_object *efi_console_input_obj; efi_handle_t console_input_handle;
/* Set up mode information */ /* Set up mode information */
query_console_size(); query_console_size();
/* Create handles */ /* Create handles */
r = efi_create_handle((efi_handle_t *)&efi_console_output_obj); r = efi_create_handle(&console_output_handle);
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto out_of_memory; 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); &efi_guid_text_output_protocol, &efi_con_out);
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto out_of_memory; goto out_of_memory;
systab.con_out_handle = efi_console_output_obj->handle; systab.con_out_handle = console_output_handle;
systab.stderr_handle = efi_console_output_obj->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) if (r != EFI_SUCCESS)
goto out_of_memory; 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); &efi_guid_text_input_protocol, &efi_con_in);
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto out_of_memory; goto out_of_memory;
systab.con_in_handle = efi_console_input_obj->handle; systab.con_in_handle = console_input_handle;
r = efi_add_protocol(efi_console_input_obj->handle, r = efi_add_protocol(console_input_handle,
&efi_guid_text_input_ex_protocol, &efi_con_in_ex); &efi_guid_text_input_ex_protocol, &efi_con_in_ex);
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto out_of_memory; goto out_of_memory;

View file

@ -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 * 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 * representing a device with one representing a file on the device, or
* a device with a parent device. * 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.. * We can have device paths that start with a USB WWID or a USB Class node,
* tl;dr: we can have a device-path that starts with a USB WWID * and a few other cases which don't encode the full device path with bus
* or USB Class node, and a few other cases which don't encode * hierarchy:
* the full device path with bus hierarchy:
* *
* - MESSAGING:USB_WWID * - MESSAGING:USB_WWID
* - MESSAGING:USB_CLASS * - MESSAGING:USB_CLASS
* - MEDIA:FILE_PATH * - MEDIA:FILE_PATH
* - MEDIA:HARD_DRIVE * - MEDIA:HARD_DRIVE
* - MESSAGING:URI * - 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) 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; struct efi_device_path *obj_dp;
efi_status_t ret; efi_status_t ret;
ret = efi_search_protocol(efiobj->handle, ret = efi_search_protocol(efiobj,
&efi_guid_device_path, &handler); &efi_guid_device_path, &handler);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
continue; 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. * 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 * @desc block device descriptor
* @part partition number, 0 identifies a block device * @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. * 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 * @desc block device descriptor
* @part partition number, 0 identifies a block device * @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 * We *could* make a more accurate path, by looking at if_type
* and handling all the different cases like we do for non- * 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. * is just to have a unique device-path for if_type+devnum.
* So map things to a fictitious USB device. * 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); 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) struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
{ {
void *buf, *start; 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. * 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 * @desc block device descriptor
* @part partition number, 0 identifies a block device * @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; 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) static void path_to_uefi(u16 *uefi, const char *path)
{ {
while (*path) { while (*path) {
@ -941,3 +942,53 @@ efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
*file_path = fp; *file_path = fp;
return EFI_SUCCESS; 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;
}

View file

@ -269,9 +269,9 @@ static char *efi_convert_single_device_node_to_text(
* for details. * for details.
* *
* device_node device node to be converted * 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 * 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 * NULL if out of memory of device_path is NULL
*/ */
static uint16_t EFIAPI *efi_convert_device_node_to_text( static uint16_t EFIAPI *efi_convert_device_node_to_text(
@ -302,9 +302,9 @@ out:
* for details. * for details.
* *
* device_path device path to be converted * 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 * 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 * NULL if out of memory of device_path is NULL
*/ */
static uint16_t EFIAPI *efi_convert_device_path_to_text( static uint16_t EFIAPI *efi_convert_device_path_to_text(

View file

@ -14,26 +14,30 @@
const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID; 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 { struct efi_disk_obj {
/* Generic EFI object parent class data */ struct efi_object header;
struct efi_object parent;
/* EFI Interface callback struct for block I/O */
struct efi_block_io ops; struct efi_block_io ops;
/* U-Boot ifname for block device */
const char *ifname; const char *ifname;
/* U-Boot dev_index for block device */
int dev_index; int dev_index;
/* EFI Interface Media descriptor struct, referenced by ops */
struct efi_block_io_media media; struct efi_block_io_media media;
/* EFI device path to this block device */
struct efi_device_path *dp; struct efi_device_path *dp;
/* partition # */
unsigned int part; unsigned int part;
/* handle to filesys proto (for partition objects) */
struct efi_simple_file_system_protocol *volume; struct efi_simple_file_system_protocol *volume;
/* Offset into disk for simple partitions */
lbaint_t offset; lbaint_t offset;
/* Internal block device */
struct blk_desc *desc; struct blk_desc *desc;
}; };
@ -246,7 +250,7 @@ static efi_status_t efi_disk_add_dev(
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
/* Hook up to the device list */ /* Hook up to the device list */
efi_add_handle(&diskobj->parent); efi_add_handle(&diskobj->header);
/* Fill in object data */ /* Fill in object data */
if (part) { if (part) {
@ -258,18 +262,18 @@ static efi_status_t efi_disk_add_dev(
diskobj->dp = efi_dp_from_part(desc, part); diskobj->dp = efi_dp_from_part(desc, part);
} }
diskobj->part = 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); &diskobj->ops);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
return ret; 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); diskobj->dp);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
return ret; return ret;
if (part >= 1) { if (part >= 1) {
diskobj->volume = efi_simple_file_system(desc, part, diskobj->volume = efi_simple_file_system(desc, part,
diskobj->dp); diskobj->dp);
ret = efi_add_protocol(diskobj->parent.handle, ret = efi_add_protocol(&diskobj->header,
&efi_simple_file_system_protocol_guid, &efi_simple_file_system_protocol_guid,
diskobj->volume); diskobj->volume);
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
@ -381,7 +385,7 @@ efi_status_t efi_disk_register(void)
/* Partitions show up as block devices in EFI */ /* Partitions show up as block devices in EFI */
disks += efi_disk_create_partitions( disks += efi_disk_create_partitions(
disk->parent.handle, desc, if_typename, &disk->header, desc, if_typename,
desc->devnum, dev->name); desc->devnum, dev->name);
} }
#else #else
@ -426,9 +430,9 @@ efi_status_t efi_disk_register(void)
disks++; disks++;
/* Partitions show up as block devices in EFI */ /* Partitions show up as block devices in EFI */
disks += efi_disk_create_partitions( disks += efi_disk_create_partitions
disk->parent.handle, desc, (&disk->header, desc,
if_typename, i, devname); if_typename, i, devname);
} }
} }
#endif #endif

View file

@ -563,7 +563,7 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
if (fh->isdir) if (fh->isdir)
info->attribute |= EFI_FILE_DIRECTORY; 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)) { } else if (!guidcmp(info_type, &efi_file_system_info_guid)) {
struct efi_file_system_info *info = buffer; struct efi_file_system_info *info = buffer;
disk_partition_t part; disk_partition_t part;

View file

@ -16,15 +16,22 @@ DECLARE_GLOBAL_DATA_PTR;
static const efi_guid_t efi_gop_guid = EFI_GOP_GUID; 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 { struct efi_gop_obj {
/* Generic EFI object parent class data */ struct efi_object header;
struct efi_object parent;
/* EFI Interface callback struct for gop */
struct efi_gop ops; struct efi_gop ops;
/* The only mode we support */
struct efi_gop_mode_info info; struct efi_gop_mode_info info;
struct efi_gop_mode mode; struct efi_gop_mode mode;
/* Fields we only have acces to during init */ /* Fields we only have access to during init */
u32 bpix; u32 bpix;
void *fb; 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 * our 2-dimensional loop gets executed very quickly, otherwise the system
* will feel slow. * will feel slow.
* *
* By manually putting all obvious branch targets into functions which call * 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. * optimize for speed.
*/ */
static efi_status_t gop_blt_video_fill(struct efi_gop *this, 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 */ /* Hook up to the device list */
efi_add_handle(&gopobj->parent); efi_add_handle(&gopobj->header);
/* Fill in object data */ /* 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); &gopobj->ops);
if (ret != EFI_SUCCESS) { if (ret != EFI_SUCCESS) {
printf("ERROR: Failure adding gop protocol\n"); printf("ERROR: Failure adding GOP protocol\n");
return ret; return ret;
} }
gopobj->ops.query_mode = gop_query_mode; gopobj->ops.query_mode = gop_query_mode;
@ -463,7 +470,10 @@ efi_status_t efi_gop_register(void)
if (bpix == LCD_COLOR32) if (bpix == LCD_COLOR32)
#endif #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_base = fb_base;
gopobj->mode.fb_size = fb_size; gopobj->mode.fb_size = fb_size;
} }

View file

@ -11,6 +11,7 @@
#include <mapmem.h> #include <mapmem.h>
#include <watchdog.h> #include <watchdog.h>
#include <linux/list_sort.h> #include <linux/list_sort.h>
#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR; 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; 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) { list_for_each(lhandle, &efi_mem) {
struct efi_mem_list *lmem = list_entry(lhandle, struct efi_mem_list *lmem = list_entry(lhandle,
struct efi_mem_list, link); 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 */ /* Reserve that map in our memory maps */
ret = efi_add_memory_map(addr, pages, memory_type, true); ret = efi_add_memory_map(addr, pages, memory_type, true);
if (ret == addr) { if (ret == addr) {
*memory = (uintptr_t)map_sysmem(addr, len); *memory = addr;
} else { } else {
/* Map would overlap, bail out */ /* Map would overlap, bail out */
r = EFI_OUT_OF_RESOURCES; 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) void *efi_alloc(uint64_t len, int memory_type)
{ {
uint64_t ret = 0; 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; efi_status_t r;
r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type, pages, 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) efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
{ {
uint64_t r = 0; 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 */ /* Merging of adjacent free regions is missing */
if (r == addr) if (r == memory)
return EFI_SUCCESS; return EFI_SUCCESS;
return EFI_NOT_FOUND; 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; efi_status_t r;
struct efi_pool_allocation *alloc; struct efi_pool_allocation *alloc;
u64 num_pages = (size + sizeof(struct efi_pool_allocation) + u64 num_pages = efi_size_in_pages(size +
EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; sizeof(struct efi_pool_allocation));
if (!buffer) if (!buffer)
return EFI_INVALID_PARAMETER; 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) __weak void efi_add_known_memory(void)
{ {
u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK;
int i; int i;
/* Fix for 32bit targets with ram_top at 4G */
if (!ram_top)
ram_top = 0x100000000ULL;
/* Add RAM */ /* Add RAM */
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
u64 ram_start = gd->bd->bi_dram[i].start; u64 ram_end, ram_start, pages;
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;
efi_add_memory_map(start, pages, EFI_CONVENTIONAL_MEMORY, ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0);
false); 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);
/*
* 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) static void add_u_boot_and_runtime(void)
{ {
unsigned long runtime_start, runtime_end, runtime_pages; unsigned long runtime_start, runtime_end, runtime_pages;
unsigned long runtime_mask = EFI_PAGE_MASK;
unsigned long uboot_start, uboot_pages; unsigned long uboot_start, uboot_pages;
unsigned long uboot_stack_size = 16 * 1024 * 1024; 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; uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT;
efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false); efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false);
/* Add Runtime Services */ #if defined(__aarch64__)
runtime_start = (ulong)&__efi_runtime_start & ~EFI_PAGE_MASK; /*
* 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 = (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; runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT;
efi_add_memory_map(runtime_start, runtime_pages, efi_add_memory_map(runtime_start, runtime_pages,
EFI_RUNTIME_SERVICES_CODE, false); EFI_RUNTIME_SERVICES_CODE, false);

View file

@ -14,6 +14,8 @@ static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
static struct efi_pxe_packet *dhcp_ack; static struct efi_pxe_packet *dhcp_ack;
static bool new_rx_packet; static bool new_rx_packet;
static void *new_tx_packet; static void *new_tx_packet;
static void *transmit_buffer;
/* /*
* The notification function of this event is called in every timer cycle * The notification function of this event is called in every timer cycle
* to check if a new network packet has been received. * 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; 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 { struct efi_net_obj {
/* Generic EFI object parent class data */ struct efi_object header;
struct efi_object parent;
/* EFI Interface callback struct for network */
struct efi_simple_network net; struct efi_simple_network net;
struct efi_simple_network_mode net_mode; struct efi_simple_network_mode net_mode;
/* PXE struct to transmit dhcp data */
struct efi_pxe pxe; struct efi_pxe pxe;
struct efi_pxe_mode pxe_mode; 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) static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
{ {
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p", this); EFI_ENTRY("%p", this);
return EFI_EXIT(EFI_SUCCESS); /* Check parameters */
} if (!this) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) if (this->mode->state != EFI_NETWORK_STOPPED)
{ ret = EFI_ALREADY_STARTED;
EFI_ENTRY("%p", this); else
this->mode->state = EFI_NETWORK_STARTED;
return EFI_EXIT(EFI_SUCCESS); out:
return EFI_EXIT(ret);
} }
/* /*
* Initialize network adapter and allocate transmit and receive buffers. * 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);
/* 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);
}
/*
* efi_net_initialize() - initialize the network interface
* *
* This function implements the Initialize service of the * This function implements the Initialize service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface * 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 * @this: pointer to the protocol instance
* @extra_rx: extra receive buffer to be allocated * @extra_rx: extra receive buffer to be allocated
* @extra_tx: extra transmit 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, static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
ulong extra_rx, ulong extra_tx) 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); EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
/* Check parameters */
if (!this) { if (!this) {
r = EFI_INVALID_PARAMETER; r = EFI_INVALID_PARAMETER;
goto error; goto out;
} }
/* Setup packet buffers */ /* Setup packet buffers */
@ -84,32 +139,83 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
ret = eth_init(); ret = eth_init();
if (ret < 0) { if (ret < 0) {
eth_halt(); eth_halt();
this->mode->state = EFI_NETWORK_STOPPED;
r = EFI_DEVICE_ERROR; r = EFI_DEVICE_ERROR;
goto out;
} else {
this->mode->state = EFI_NETWORK_INITIALIZED;
} }
out:
error:
return EFI_EXIT(r); 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, static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
int extended_verification) int extended_verification)
{ {
EFI_ENTRY("%p, %x", this, 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) static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
{ {
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p", this); 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, * efi_net_receive_filters() - mange multicast receive filters
int reset_mcast_filter, ulong mcast_filter_count, *
struct efi_mac_address *mcast_filter) * 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, EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
reset_mcast_filter, mcast_filter_count, mcast_filter); 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); return EFI_EXIT(EFI_UNSUPPORTED);
} }
static efi_status_t EFIAPI efi_net_station_address( /*
struct efi_simple_network *this, int reset, * efi_net_station_address() - set the hardware MAC address
struct efi_mac_address *new_mac) *
* 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); EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
return EFI_EXIT(EFI_UNSUPPORTED); 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, static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
int reset, ulong *stat_size, int reset, ulong *stat_size,
void *stat_table) 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); 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, static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
int ipv6, int ipv6,
struct efi_ip_address *ip, 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); 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, static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
int read_write, ulong offset, int read_write, ulong offset,
ulong buffer_size, char *buffer) 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); 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, static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
u32 *int_status, void **txbuf) u32 *int_status, void **txbuf)
{ {
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %p, %p", this, int_status, txbuf); EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
efi_timer_check(); 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) { if (int_status) {
/* We send packets synchronously, so nothing is outstanding */ /* We send packets synchronously, so nothing is outstanding */
*int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; *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; *txbuf = new_tx_packet;
new_tx_packet = NULL; new_tx_packet = NULL;
out:
return EFI_EXIT(EFI_SUCCESS); 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, * efi_net_transmit() - transmit a packet
struct efi_mac_address *src_addr, *
struct efi_mac_address *dest_addr, u16 *protocol) * 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, EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this,
(unsigned long)header_size, (unsigned long)buffer_size, (unsigned long)header_size, (unsigned long)buffer_size,
buffer, src_addr, dest_addr, protocol); buffer, src_addr, dest_addr, protocol);
efi_timer_check(); efi_timer_check();
if (header_size) { /* Check parameters */
/* We would need to create the header if header_size != 0 */ if (!this) {
return EFI_EXIT(EFI_INVALID_PARAMETER); 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) {
/*
* 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 */ /* Ethernet packets always fit, just bounce */
memcpy(efi_bounce_buffer, buffer, buffer_size); memcpy(transmit_buffer, buffer, buffer_size);
net_send_packet(efi_bounce_buffer, buffer_size); net_send_packet(transmit_buffer, buffer_size);
#else
net_send_packet(buffer, buffer_size);
#endif
new_tx_packet = buffer; new_tx_packet = buffer;
return EFI_EXIT(EFI_SUCCESS); out:
return EFI_EXIT(ret);
} }
static void efi_net_push(void *pkt, int len) /**
{ * efi_net_receive() - receive a packet from a network interface
new_rx_packet = true;
wait_for_packet->is_signaled = true;
}
/*
* Receive a packet from a network interface.
* *
* This function implements the Receive service of the Simple Network Protocol. * This function implements the Receive service of the Simple Network Protocol.
* See the UEFI spec for details. * See the UEFI spec for details.
* *
* @this the instance of the Simple Network Protocol * @this: the instance of the Simple Network Protocol
* @header_size size of the media header * @header_size: size of the media header
* @buffer_size size of the buffer to receive the packet * @buffer_size: size of the buffer to receive the packet
* @buffer buffer to receive the packet * @buffer: buffer to receive the packet
* @src_addr source MAC address * @src_addr: source MAC address
* @dest_addr destination MAC address * @dest_addr: destination MAC address
* @protocol protocol * @protocol: protocol
* @return status code * Return: status code
*/ */
static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, static efi_status_t EFIAPI efi_net_receive
size_t *header_size, size_t *buffer_size, void *buffer, (struct efi_simple_network *this, size_t *header_size,
struct efi_mac_address *src_addr, size_t *buffer_size, void *buffer,
struct efi_mac_address *dest_addr, u16 *protocol) 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; struct ethernet_hdr *eth_hdr;
size_t hdr_size = sizeof(struct ethernet_hdr); size_t hdr_size = sizeof(struct ethernet_hdr);
u16 protlen; 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, EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
buffer_size, buffer, src_addr, dest_addr, protocol); buffer_size, buffer, src_addr, dest_addr, protocol);
/* Execute events */
efi_timer_check(); efi_timer_check();
if (!new_rx_packet) /* Check parameters */
return EFI_EXIT(EFI_NOT_READY); 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 */ /* Check that we at least received an Ethernet header */
if (net_rx_packet_len < sizeof(struct ethernet_hdr)) { if (net_rx_packet_len < sizeof(struct ethernet_hdr)) {
new_rx_packet = false; new_rx_packet = false;
return EFI_EXIT(EFI_NOT_READY); ret = EFI_NOT_READY;
goto out;
} }
/* Fill export parameters */ /* Fill export parameters */
eth_hdr = (struct ethernet_hdr *)net_rx_packet; 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) if (protocol)
*protocol = protlen; *protocol = protlen;
if (*buffer_size < net_rx_packet_len) { 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; *buffer_size = net_rx_packet_len;
return EFI_EXIT(EFI_BUFFER_TOO_SMALL); ret = EFI_BUFFER_TOO_SMALL;
goto out;
} }
/* Copy packet */ /* Copy packet */
memcpy(buffer, net_rx_packet, net_rx_packet_len); memcpy(buffer, net_rx_packet, net_rx_packet_len);
*buffer_size = net_rx_packet_len; *buffer_size = net_rx_packet_len;
new_rx_packet = false; new_rx_packet = false;
out:
return EFI_EXIT(EFI_SUCCESS); 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) void efi_net_set_dhcp_ack(void *pkt, int len)
{ {
int maxsize = sizeof(*dhcp_ack); 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)); 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. * 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, static void EFIAPI efi_network_timer_notify(struct efi_event *event,
void *context) void *context)
{ {
struct efi_simple_network *this = (struct efi_simple_network *)context;
EFI_ENTRY("%p, %p", event, 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) { if (!new_rx_packet) {
push_packet = efi_net_push; push_packet = efi_net_push;
eth_rx(); eth_rx();
push_packet = NULL; push_packet = NULL;
} }
out:
EFI_EXIT(EFI_SUCCESS); 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) efi_status_t efi_net_register(void)
{ {
struct efi_net_obj *netobj; struct efi_net_obj *netobj = NULL;
efi_status_t r; efi_status_t r;
if (!eth_get_dev()) { if (!eth_get_dev()) {
/* No eth device active, don't expose any */ /* No network device active, don't expose any */
return EFI_SUCCESS; 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)); netobj = calloc(1, sizeof(*netobj));
if (!netobj) { if (!netobj)
printf("ERROR: Out of memory\n"); goto out_of_resources;
return EFI_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 */ /* Hook net up to the device list */
efi_add_handle(&netobj->parent); efi_add_handle(&netobj->header);
/* Fill in object data */ /* 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); &netobj->net);
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto failure_to_add_protocol; 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()); efi_dp_from_eth());
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto failure_to_add_protocol; 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); &netobj->pxe);
if (r != EFI_SUCCESS) if (r != EFI_SUCCESS)
goto failure_to_add_protocol; 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. * 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, 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); &network_timer_event);
if (r != EFI_SUCCESS) { if (r != EFI_SUCCESS) {
printf("ERROR: Failed to register network event\n"); printf("ERROR: Failed to register network event\n");
return r; 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); r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
if (r != EFI_SUCCESS) { if (r != EFI_SUCCESS) {
printf("ERROR: Failed to set network timer\n"); printf("ERROR: Failed to set network timer\n");
@ -402,4 +685,9 @@ efi_status_t efi_net_register(void)
failure_to_add_protocol: failure_to_add_protocol:
printf("ERROR: Failure to add protocol\n"); printf("ERROR: Failure to add protocol\n");
return r; return r;
out_of_resources:
free(netobj);
/* free(transmit_buffer) not needed yet */
printf("ERROR: Out of memory\n");
return EFI_OUT_OF_RESOURCES;
} }

View file

@ -141,7 +141,9 @@ static void EFIAPI efi_reset_system_boottime(
do_reset(NULL, 0, 0, NULL); do_reset(NULL, 0, 0, NULL);
break; break;
case EFI_RESET_SHUTDOWN: 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; break;
} }
@ -282,7 +284,7 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
}, { }, {
/* invalidate_*cache_all are gone */ /* invalidate_*cache_all are gone */
.ptr = &efi_runtime_services.set_virtual_address_map, .ptr = &efi_runtime_services.set_virtual_address_map,
.patchto = &efi_invalid_parameter, .patchto = &efi_unimplemented,
}, { }, {
/* RTC accessors are gone */ /* RTC accessors are gone */
.ptr = &efi_runtime_services.get_time, .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; ulong symidx = rel->info >> SYM_INDEX;
extern struct dyn_sym __dyn_sym_start[]; extern struct dyn_sym __dyn_sym_start[];
newaddr = __dyn_sym_start[symidx].addr + offset; newaddr = __dyn_sym_start[symidx].addr + offset;
#ifdef IS_RELA
newaddr -= CONFIG_SYS_TEXT_BASE;
#endif
break; break;
} }
#endif #endif
@ -623,8 +628,8 @@ efi_status_t __efi_runtime EFIAPI efi_update_capsule(
efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps( efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
struct efi_capsule_header **capsule_header_array, struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count, efi_uintn_t capsule_count,
u64 maximum_capsule_size, u64 *maximum_capsule_size,
u32 reset_type) u32 *reset_type)
{ {
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }

View file

@ -7,6 +7,7 @@
#include <common.h> #include <common.h>
#include <efi_loader.h> #include <efi_loader.h>
#include <mapmem.h>
#include <smbios.h> #include <smbios.h>
static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID; 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) efi_status_t efi_smbios_register(void)
{ {
/* Map within the low 32 bits, to allow for 32bit SMBIOS tables */ /* 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; efi_status_t ret;
void *dmi;
/* Reserve 4kiB page for SMBIOS */ /* Reserve 4kiB page for SMBIOS */
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, 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) { if (ret != EFI_SUCCESS) {
/* Could not find space in lowmem, use highmem instead */ /* Could not find space in lowmem, use highmem instead */
ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, 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) if (ret != EFI_SUCCESS)
return ret; return ret;
@ -39,11 +42,14 @@ efi_status_t efi_smbios_register(void)
* Generate SMBIOS tables - we know that efi_allocate_pages() returns * Generate SMBIOS tables - we know that efi_allocate_pages() returns
* a 4k-aligned address, so it is safe to assume that * a 4k-aligned address, so it is safe to assume that
* write_smbios_table() will write the table at that address. * 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)); assert(!(dmi_addr & 0xf));
write_smbios_table(dmi); dmi = (void *)(uintptr_t)dmi_addr;
write_smbios_table(map_to_sysmem(dmi));
/* And expose them to our EFI payload */ /* And expose them to our EFI payload */
return efi_install_configuration_table(&smbios_guid, return efi_install_configuration_table(&smbios_guid, dmi);
(void *)(uintptr_t)dmi);
} }

View file

@ -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 acpi_guid = EFI_ACPI_TABLE_GUID;
static const efi_guid_t smbios_guid = SMBIOS_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) static int hw_memcmp(const void *buf1, const void *buf2, size_t length)
{ {
const u8 *pos1 = buf1; const u8 *pos1 = buf1;
@ -31,12 +41,12 @@ static int hw_memcmp(const void *buf1, const void *buf2, size_t length)
return 0; return 0;
} }
/* /**
* Entry point of the EFI application. * efi_main() - entry point of the EFI application.
* *
* @handle handle of the loaded image * @handle: handle of the loaded image
* @systable system table * @systable: system table
* @return status code * @return: status code
*/ */
efi_status_t EFIAPI efi_main(efi_handle_t handle, efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable) struct efi_system_table *systable)
@ -48,7 +58,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
efi_uintn_t i; efi_uintn_t i;
u16 rev[] = L"0.0.0"; 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 */ /* Print the revision number */
rev[0] = (systable->hdr.revision >> 16) + '0'; 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, L"Running on UEFI ");
con_out->output_string(con_out, rev); 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 */ /* Get the loaded image protocol */
ret = boottime->handle_protocol(handle, &loaded_image_guid, ret = boottime->handle_protocol(handle, &loaded_image_guid,
(void **)&loaded_image); (void **)&loaded_image);
if (ret != EFI_SUCCESS) { if (ret != EFI_SUCCESS) {
con_out->output_string(con_out, con_out->output_string
L"Cannot open loaded image protocol\n"); (con_out, L"Cannot open loaded image protocol\r\n");
goto out; goto out;
} }
/* Find configuration tables */ /* Find configuration tables */
for (i = 0; i < systable->nr_tables; ++i) { for (i = 0; i < systable->nr_tables; ++i) {
if (!hw_memcmp(&systable->tables[i].guid, &fdt_guid, if (!hw_memcmp(&systable->tables[i].guid, &fdt_guid,
sizeof(efi_guid_t))) 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, if (!hw_memcmp(&systable->tables[i].guid, &acpi_guid,
sizeof(efi_guid_t))) 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, if (!hw_memcmp(&systable->tables[i].guid, &smbios_guid,
sizeof(efi_guid_t))) 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 */ /* Output the load options */
con_out->output_string(con_out, L"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); (u16 *)loaded_image->load_options);
else else
con_out->output_string(con_out, L"<none>"); 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: out:
boottime->exit(handle, ret, 0, NULL); boottime->exit(handle, ret, 0, NULL);

View file

@ -1,6 +1,6 @@
config CMD_BOOTEFI_SELFTEST config CMD_BOOTEFI_SELFTEST
bool "Allow booting an EFI efi_selftest" bool "Allow booting an EFI efi_selftest"
depends on CMD_BOOTEFI && !SANDBOX depends on CMD_BOOTEFI
imply FAT imply FAT
imply FAT_WRITE imply FAT_WRITE
help help

View file

@ -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_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding
CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os
obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ obj-y += \
efi_selftest.o \ efi_selftest.o \
efi_selftest_bitblt.o \ efi_selftest_bitblt.o \
efi_selftest_config_table.o \ efi_selftest_config_table.o \
@ -21,11 +21,13 @@ efi_selftest_devicepath.o \
efi_selftest_devicepath_util.o \ efi_selftest_devicepath_util.o \
efi_selftest_events.o \ efi_selftest_events.o \
efi_selftest_event_groups.o \ efi_selftest_event_groups.o \
efi_selftest_exception.o \
efi_selftest_exitbootservices.o \ efi_selftest_exitbootservices.o \
efi_selftest_fdt.o \ efi_selftest_fdt.o \
efi_selftest_gop.o \ efi_selftest_gop.o \
efi_selftest_loaded_image.o \ efi_selftest_loaded_image.o \
efi_selftest_manageprotocols.o \ efi_selftest_manageprotocols.o \
efi_selftest_memory.o \
efi_selftest_rtc.o \ efi_selftest_rtc.o \
efi_selftest_snp.o \ efi_selftest_snp.o \
efi_selftest_textinput.o \ efi_selftest_textinput.o \
@ -37,20 +39,16 @@ efi_selftest_util.o \
efi_selftest_variables.o \ efi_selftest_variables.o \
efi_selftest_watchdog.o efi_selftest_watchdog.o
ifeq ($(CONFIG_CMD_BOOTEFI_SELFTEST),y)
obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o
endif
ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy) ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy)
obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest_block_device.o obj-y += efi_selftest_block_device.o
endif endif
# TODO: As of v2018.01 the relocation code for the EFI application cannot # TODO: As of v2018.01 the relocation code for the EFI application cannot
# be built on x86_64. # be built on x86_64.
ifeq ($(CONFIG_X86_64)$(CONFIG_SANDBOX),) ifeq ($(CONFIG_X86_64)$(CONFIG_SANDBOX),)
ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST),)
obj-y += \ obj-y += \
efi_selftest_startimage_exit.o \ efi_selftest_startimage_exit.o \
efi_selftest_startimage_return.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 $(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h
endif endif
endif

View file

@ -18,6 +18,7 @@ static const struct efi_boot_services *boottime;
static const struct efi_runtime_services *runtime; static const struct efi_runtime_services *runtime;
static efi_handle_t handle; static efi_handle_t handle;
static u16 reset_message[] = L"Selftest completed"; static u16 reset_message[] = L"Selftest completed";
static int *setup_status;
/* /*
* Exit the boot services. * 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) static int setup(struct efi_unit_test *test, unsigned int *failures)
{ {
if (!test->setup) { int ret;
test->setup_ok = EFI_ST_SUCCESS;
if (!test->setup)
return EFI_ST_SUCCESS; return EFI_ST_SUCCESS;
}
efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name); efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name);
test->setup_ok = test->setup(handle, systable); ret = test->setup(handle, systable);
if (test->setup_ok != EFI_ST_SUCCESS) { if (ret != EFI_ST_SUCCESS) {
efi_st_error("Setting up '%s' failed\n", test->name); efi_st_error("Setting up '%s' failed\n", test->name);
++*failures; ++*failures;
} else { } else {
efi_st_printc(EFI_LIGHTGREEN, efi_st_printc(EFI_LIGHTGREEN,
"Setting up '%s' succeeded\n", test->name); "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, void efi_st_do_tests(const u16 *testname, unsigned int phase,
unsigned int steps, unsigned int *failures) unsigned int steps, unsigned int *failures)
{ {
int i = 0;
struct efi_unit_test *test; struct efi_unit_test *test;
for (test = ll_entry_start(struct efi_unit_test, efi_unit_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 ? if (testname ?
efi_st_strcmp_16_8(testname, test->name) : test->on_request) efi_st_strcmp_16_8(testname, test->name) : test->on_request)
continue; continue;
if (test->phase != phase) if (test->phase != phase)
continue; continue;
if (steps & EFI_ST_SETUP) if (steps & EFI_ST_SETUP)
setup(test, failures); setup_status[i] = setup(test, failures);
if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS) if (steps & EFI_ST_EXECUTE && setup_status[i] == EFI_ST_SUCCESS)
execute(test, failures); execute(test, failures);
if (steps & EFI_ST_TEARDOWN) if (steps & EFI_ST_TEARDOWN)
teardown(test, failures); 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, ll_entry_count(struct efi_unit_test,
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 */ /* Execute boottime tests */
efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,

View file

@ -18,7 +18,7 @@ static efi_guid_t table_guid =
0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75); 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. * context is provided.
* *
* @event notified event * @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) static int check_table(const void *table)
{ {
efi_status_t ret; efi_status_t ret;
u32 crc32, res; 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; struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
crc32 = hdr->crc32; 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 * copying
*/ */
hdr->crc32 = 0; hdr->crc32 = 0;
ret = boottime->calculate_crc32(table, hdr->headersize, &res); 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; hdr->crc32 = crc32;
if (ret != EFI_ST_SUCCESS) { if (ret != EFI_ST_SUCCESS) {
efi_st_error("CalculateCrc32 failed\n"); efi_st_error("CalculateCrc32 failed\n");
@ -203,7 +203,7 @@ static int execute(void)
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
if (tabcnt > 1) { if (tabcnt > 1) {
efi_st_error("Duplicate table guid\n"); efi_st_error("Duplicate table GUID\n");
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
if (table != &tables[1]) { if (table != &tables[1]) {

View file

@ -33,7 +33,7 @@ static efi_handle_t handle_driver;
* Count child controllers * Count child controllers
* *
* @handle handle on which child controllers are installed * @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 * @count number of child controllers
* @return status code * @return status code
*/ */

View file

@ -5,7 +5,7 @@
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
* *
* This unit test checks the CalculateCrc32 bootservice and checks the * 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(). * services table before and after ExitBootServices().
*/ */
@ -19,7 +19,7 @@ static int check_table(const void *table)
{ {
efi_status_t ret; efi_status_t ret;
u32 crc32, res; 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; struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
if (!hdr->signature) { if (!hdr->signature) {

View file

@ -257,7 +257,7 @@ static int teardown(void)
static int execute(void) static int execute(void)
{ {
struct efi_device_path *remaining_dp; struct efi_device_path *remaining_dp;
void *handle; efi_handle_t handle;
/* /*
* This device path node ends with the letter 't' of 'u-boot'. * This device path node ends with the letter 't' of 'u-boot'.
* The following '.bin' does not belong to the node but is * The following '.bin' does not belong to the node but is

View file

@ -19,7 +19,7 @@ static efi_guid_t event_group =
0x0e, 0x5b, 0x45, 0xc0, 0x56, 0x91); 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. * context is provided.
* *
* @event notified event * @event notified event
@ -114,7 +114,7 @@ static int execute(void)
(unsigned int)i, (unsigned int)j, (unsigned int)i, (unsigned int)j,
(unsigned int)counter[j]); (unsigned int)counter[j]);
efi_st_error( efi_st_error(
"Nofification function not called\n"); "Notification function not called\n");
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
} }

View file

@ -17,7 +17,7 @@ static unsigned int timer_ticks;
static struct efi_boot_services *boottime; 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. * context is provided.
* *
* @event notified event * @event notified event

View file

@ -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,
};

View file

@ -16,7 +16,7 @@
static struct efi_boot_services *boottime; static struct efi_boot_services *boottime;
static const char *fdt; static const char *fdt;
/* This should be sufficent for */ /* This should be sufficient for */
#define BUFFERSIZE 0x100000 #define BUFFERSIZE 0x100000
static efi_guid_t fdt_guid = EFI_FDT_GUID; static efi_guid_t fdt_guid = EFI_FDT_GUID;

View file

@ -53,7 +53,7 @@ static int execute(void)
efi_st_error("ProtocolsPerHandle failed\n"); efi_st_error("ProtocolsPerHandle failed\n");
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
if (!protocol_buffer_count | !protocol_buffer) { if (!protocol_buffer_count || !protocol_buffer) {
efi_st_error("ProtocolsPerHandle returned no protocol\n"); efi_st_error("ProtocolsPerHandle returned no protocol\n");
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }

View file

@ -189,7 +189,14 @@ static int execute(void)
/* /*
* Test error handling in UninstallMultipleProtocols * 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( ret = boottime->uninstall_multiple_protocol_interfaces(
handle2, handle2,
@ -197,13 +204,18 @@ static int execute(void)
&guid2, &interface2, &guid2, &interface2,
&guid3, &interface3, &guid3, &interface3,
NULL); NULL);
if (ret == EFI_SUCCESS) { if (ret != EFI_INVALID_PARAMETER) {
printf("%lx", ret);
efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n"); efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n");
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
/* /*
* Test LocateHandleBuffer with ByProtocol * Test LocateHandleBuffer with ByProtocol
*
* These are the handles with a guid1 protocol interface installed:
*
* handle1, handle2
*/ */
count = buffer_size; count = buffer_size;
ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL,
@ -213,7 +225,7 @@ static int execute(void)
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
if (count != 2) { if (count != 2) {
efi_st_error("LocateHandleBuffer failed to locate new handles\n"); efi_st_error("UninstallMultipleProtocolInterfaces deleted handle\n");
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
ret = find_in_buffer(handle1, count, buffer); ret = find_in_buffer(handle1, count, buffer);

View file

@ -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,
};

View file

@ -103,7 +103,7 @@ static efi_status_t send_dhcp_discover(void)
struct dhcp p = {}; 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_dest, (void *)BROADCAST_MAC, ARP_HLEN);
boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address, boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address,
@ -228,6 +228,14 @@ static int setup(const efi_handle_t handle,
efi_st_error("WaitForPacket event missing\n"); efi_st_error("WaitForPacket event missing\n");
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
/*
* Start network adapter.
*/
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;
}
/* /*
* Initialize network adapter. * Initialize network adapter.
*/ */
@ -236,14 +244,6 @@ static int setup(const efi_handle_t handle,
efi_st_error("Failed to initialize network adapter\n"); efi_st_error("Failed to initialize network adapter\n");
return EFI_ST_FAILURE; return EFI_ST_FAILURE;
} }
/*
* Start network adapter.
*/
ret = net->start(net);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to start network adapter\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS; return EFI_ST_SUCCESS;
} }

View file

@ -5,7 +5,7 @@
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
* *
* Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL. * 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: * input. To run the test:
* *
* setenv efi_selftest text input * setenv efi_selftest text input

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: GPL-2.0+
/* /*
* efi_selftest_events * efi_selftest_tpl
* *
* Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
* *

View file

@ -52,7 +52,7 @@ static int test_stri_coll(void)
c1, c2); c1, c2);
if (ret) { if (ret) {
efi_st_error( 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; return EFI_ST_FAILURE;
} }
@ -60,7 +60,7 @@ static int test_stri_coll(void)
c1, c3); c1, c3);
if (ret >= 0) { if (ret >= 0) {
efi_st_error( 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; return EFI_ST_FAILURE;
} }
@ -68,7 +68,7 @@ static int test_stri_coll(void)
c3, c1); c3, c1);
if (ret <= 0) { if (ret <= 0) {
efi_st_error( 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; return EFI_ST_FAILURE;
} }

View file

@ -4,10 +4,8 @@
* *
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
* *
* This unit test checks the following protocol services: * This unit test checks the runtime services for variables:
* ConnectController, DisconnectController, * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
* InstallProtocol, ReinstallProtocol, UninstallProtocol,
* OpenProtocol, CloseProtcol, OpenProtocolInformation
*/ */
#include <efi_selftest.h> #include <efi_selftest.h>

View file

@ -35,7 +35,7 @@ static struct notify_context notification_context;
static bool watchdog_reset; static bool watchdog_reset;
/* /*
* Notification function, increments the notfication count if parameter * Notification function, increments the notification count if parameter
* context is provided. * context is provided.
* *
* @event notified event * @event notified event

View file

@ -11,6 +11,7 @@
#include <errno.h> #include <errno.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <fdt_support.h> #include <fdt_support.h>
#include <mapmem.h>
#include <linux/libfdt.h> #include <linux/libfdt.h>
#include <serial.h> #include <serial.h>
#include <asm/sections.h> #include <asm/sections.h>
@ -1253,8 +1254,9 @@ int fdtdec_setup(void)
# if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) # if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
gd->fdt_blob = (void *)prior_stage_fdt_address; gd->fdt_blob = (void *)prior_stage_fdt_address;
# else # else
gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16, gd->fdt_blob = map_sysmem
(uintptr_t)gd->fdt_blob); (env_get_ulong("fdtcontroladdr", 16,
(unsigned long)map_to_sysmem(gd->fdt_blob)), 0);
# endif # endif
# endif # endif

View file

@ -6,6 +6,7 @@
*/ */
#include <common.h> #include <common.h>
#include <mapmem.h>
#include <smbios.h> #include <smbios.h>
#include <tables_csum.h> #include <tables_csum.h>
#include <version.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) 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); int len = sizeof(struct smbios_type0);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type0)); memset(t, 0, sizeof(struct smbios_type0));
fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle); fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle);
t->vendor = smbios_add_string(t->eos, "U-Boot"); 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); len = t->length + smbios_string_table_len(t->eos);
*current += len; *current += len;
unmap_sysmem(t);
return len; return len;
} }
static int smbios_write_type1(ulong *current, int handle) 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); int len = sizeof(struct smbios_type1);
char *serial_str = env_get("serial#"); char *serial_str = env_get("serial#");
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type1)); memset(t, 0, sizeof(struct smbios_type1));
fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle); fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 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); len = t->length + smbios_string_table_len(t->eos);
*current += len; *current += len;
unmap_sysmem(t);
return len; return len;
} }
static int smbios_write_type2(ulong *current, int handle) 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); int len = sizeof(struct smbios_type2);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type2)); memset(t, 0, sizeof(struct smbios_type2));
fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle); fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 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); len = t->length + smbios_string_table_len(t->eos);
*current += len; *current += len;
unmap_sysmem(t);
return len; return len;
} }
static int smbios_write_type3(ulong *current, int handle) 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); int len = sizeof(struct smbios_type3);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type3)); memset(t, 0, sizeof(struct smbios_type3));
fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle); fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); 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); len = t->length + smbios_string_table_len(t->eos);
*current += len; *current += len;
unmap_sysmem(t);
return len; 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) 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); int len = sizeof(struct smbios_type4);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type4)); memset(t, 0, sizeof(struct smbios_type4));
fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle); fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle);
t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL; 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); len = t->length + smbios_string_table_len(t->eos);
*current += len; *current += len;
unmap_sysmem(t);
return len; return len;
} }
static int smbios_write_type32(ulong *current, int handle) 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); int len = sizeof(struct smbios_type32);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type32)); memset(t, 0, sizeof(struct smbios_type32));
fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle); fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle);
*current += len; *current += len;
unmap_sysmem(t);
return len; return len;
} }
static int smbios_write_type127(ulong *current, int handle) 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); int len = sizeof(struct smbios_type127);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type127)); memset(t, 0, sizeof(struct smbios_type127));
fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle); fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle);
*current += len; *current += len;
unmap_sysmem(t);
return len; return len;
} }
@ -257,6 +272,7 @@ static smbios_write_type smbios_write_funcs[] = {
ulong write_smbios_table(ulong addr) ulong write_smbios_table(ulong addr)
{ {
struct smbios_entry *se; struct smbios_entry *se;
ulong table_addr;
ulong tables; ulong tables;
int len = 0; int len = 0;
int max_struct_size = 0; int max_struct_size = 0;
@ -268,7 +284,7 @@ ulong write_smbios_table(ulong addr)
/* 16 byte align the table address */ /* 16 byte align the table address */
addr = ALIGN(addr, 16); 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)); memset(se, 0, sizeof(struct smbios_entry));
addr += 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; se->max_struct_size = max_struct_size;
memcpy(se->intermediate_anchor, "_DMI_", 5); memcpy(se->intermediate_anchor, "_DMI_", 5);
se->struct_table_length = len; 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; se->struct_count = handle;
/* calculate checksums */ /* calculate checksums */
@ -298,6 +331,7 @@ ulong write_smbios_table(ulong addr)
isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET; isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET;
se->intermediate_checksum = table_compute_checksum(istart, isize); se->intermediate_checksum = table_compute_checksum(istart, isize);
se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry)); se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry));
unmap_sysmem(se);
return addr; return addr;
} }

View file

@ -381,7 +381,7 @@ $(obj)/%.efi: $(obj)/%_efi.so
quiet_cmd_efi_ld = LD $@ quiet_cmd_efi_ld = LD $@
cmd_efi_ld = $(LD) -nostdlib -znocombreloc -T $(EFI_LDS_PATH) -shared \ 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) EFI_LDS_PATH = $(srctree)/arch/$(ARCH)/lib/$(EFI_LDS)

View file

@ -8,12 +8,14 @@ import u_boot_utils
@pytest.mark.buildconfigspec('cmd_bootefi_selftest') @pytest.mark.buildconfigspec('cmd_bootefi_selftest')
def test_efi_selftest(u_boot_console): def test_efi_selftest(u_boot_console):
""" """Test the UEFI implementation
Run bootefi selftest
"""
: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='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']) m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0: if m != 0:
raise Exception('Failures occurred during the EFI selftest') raise Exception('Failures occurred during the EFI selftest')