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 SYS_LONGHELP
imply CMD_MII if NET
imply USB_STORAGE
imply USE_BOOTCOMMAND
help
Select this to enable various options and commands which are suitable

View file

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

View file

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

View file

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

View file

@ -7,7 +7,6 @@
#include <asm-offsets.h>
#include <config.h>
#include <efi_loader.h>
#include <version.h>
#include <asm/macro.h>
#include <asm/psci.h>
@ -19,7 +18,7 @@
* x0~x7: input arguments
* x0~x3: output arguments
*/
static void __efi_runtime hvc_call(struct pt_regs *args)
static void hvc_call(struct pt_regs *args)
{
asm volatile(
"ldr x0, %0\n"
@ -53,7 +52,7 @@ static void __efi_runtime hvc_call(struct pt_regs *args)
* x0~x3: output arguments
*/
void __efi_runtime smc_call(struct pt_regs *args)
void smc_call(struct pt_regs *args)
{
asm volatile(
"ldr x0, %0\n"
@ -83,9 +82,9 @@ void __efi_runtime smc_call(struct pt_regs *args)
* use PSCI on U-Boot running below a hypervisor, please detect
* this and set the flag accordingly.
*/
static const __efi_runtime_data bool use_smc_for_psci = true;
static const bool use_smc_for_psci = true;
void __noreturn __efi_runtime psci_system_reset(void)
void __noreturn psci_system_reset(void)
{
struct pt_regs regs;
@ -100,7 +99,7 @@ void __noreturn __efi_runtime psci_system_reset(void)
;
}
void __noreturn __efi_runtime psci_system_off(void)
void __noreturn psci_system_off(void)
{
struct pt_regs regs;
@ -114,44 +113,3 @@ void __noreturn __efi_runtime psci_system_off(void)
while (1)
;
}
#ifdef CONFIG_CMD_POWEROFF
int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
puts("poweroff ...\n");
udelay(50000); /* wait 50 ms */
disable_interrupts();
psci_system_off();
/*NOTREACHED*/
return 0;
}
#endif
#ifdef CONFIG_PSCI_RESET
void reset_misc(void)
{
psci_system_reset();
}
#ifdef CONFIG_EFI_LOADER
void __efi_runtime EFIAPI efi_reset_system(
enum efi_reset_type reset_type,
efi_status_t reset_status,
unsigned long data_size, void *reset_data)
{
if (reset_type == EFI_RESET_COLD ||
reset_type == EFI_RESET_WARM ||
reset_type == EFI_RESET_PLATFORM_SPECIFIC) {
psci_system_reset();
} else if (reset_type == EFI_RESET_SHUTDOWN) {
psci_system_off();
}
while (1) { }
}
#endif /* CONFIG_EFI_LOADER */
#endif /* CONFIG_PSCI_RESET */

View file

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

View file

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

View file

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

View file

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

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
# PLATFORM_LDFLAGS
LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined
LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined -s
OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
-j .rel -j .rela -j .reloc
@ -65,7 +65,7 @@ CPPFLAGS_crt0-efi-$(EFIARCH).o += $(CFLAGS_EFI)
ifeq ($(CONFIG_EFI_APP),y)
PLATFORM_CPPFLAGS += $(CFLAGS_EFI)
LDFLAGS_FINAL += -znocombreloc -shared
LDFLAGS_FINAL += -znocombreloc -shared -s
LDSCRIPT := $(LDSCRIPT_EFI)
else

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
*
* The FDT is relocated into a suitable location within the EFI memory map.
* An additional 12KB is added to the space in case the device tree needs to be
* The FDT is copied to a suitable location within the EFI memory map.
* Additional 12 KiB are added to the space in case the device tree needs to be
* expanded later with fdt_open_into().
*
* @fdt_addr: On entry, address of start of FDT. On exit, address of relocated
* FDT start
* @fdt_sizep: Returns new size of FDT, including
* @return new relocated address of FDT
* @fdtp: On entry a pointer to the flattened device tree.
* On exit a pointer to the copy of the flattened device tree.
* FDT start
* Return: status code
*/
static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
static efi_status_t copy_fdt(void **fdtp)
{
unsigned long fdt_ram_start = -1L, fdt_pages;
efi_status_t ret = 0;
@ -178,17 +178,19 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
}
/*
* Give us at least 4KB of breathing room in case the device tree needs
* to be expanded later. Round up to the nearest EFI page boundary.
* Give us at least 12 KiB of breathing room in case the device tree
* needs to be expanded later.
*/
fdt = map_sysmem(*fdt_addrp, 0);
fdt_size = fdt_totalsize(fdt);
fdt_size += 4096 * 3;
fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE);
fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
fdt = *fdtp;
fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
fdt_size = fdt_pages << 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,
EFI_RUNTIME_SERVICES_DATA, fdt_pages,
&new_fdt_addr);
@ -203,13 +205,11 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
goto done;
}
}
new_fdt = map_sysmem(new_fdt_addr, fdt_size);
new_fdt = (void *)(uintptr_t)new_fdt_addr;
memcpy(new_fdt, fdt, fdt_totalsize(fdt));
fdt_set_totalsize(new_fdt, fdt_size);
*fdt_addrp = new_fdt_addr;
*fdt_sizep = fdt_size;
*fdtp = (void *)(uintptr_t)new_fdt_addr;
done:
return ret;
}
@ -277,7 +277,11 @@ static void efi_carve_out_dt_rsv(void *fdt)
if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
continue;
pages = ALIGN(size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT;
/* Convert from sandbox address space. */
addr = (uintptr_t)map_sysmem(addr, 0);
pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
addr &= ~EFI_PAGE_MASK;
if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
false))
printf("FDT memrsv map %d: Failed to add to map\n", i);
@ -287,7 +291,6 @@ static void efi_carve_out_dt_rsv(void *fdt)
static efi_status_t efi_install_fdt(ulong fdt_addr)
{
bootm_headers_t img = { 0 };
ulong fdt_pages, fdt_size, fdt_start;
efi_status_t ret;
void *fdt;
@ -297,36 +300,60 @@ static efi_status_t efi_install_fdt(ulong fdt_addr)
return EFI_INVALID_PARAMETER;
}
/* Create memory reservation as indicated by the device tree */
efi_carve_out_dt_rsv(fdt);
/* Prepare fdt for payload */
ret = copy_fdt(&fdt_addr, &fdt_size);
ret = copy_fdt(&fdt);
if (ret)
return ret;
unmap_sysmem(fdt);
fdt = map_sysmem(fdt_addr, 0);
fdt_size = fdt_totalsize(fdt);
if (image_setup_libfdt(&img, fdt, 0, NULL)) {
printf("ERROR: failed to process device tree\n");
return EFI_LOAD_ERROR;
}
efi_carve_out_dt_rsv(fdt);
/* Link to it in the efi tables */
ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
if (ret != EFI_SUCCESS)
return EFI_OUT_OF_RESOURCES;
/* And reserve the space in the memory map */
fdt_start = fdt_addr;
fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
ret = efi_add_memory_map(fdt_start, fdt_pages,
EFI_BOOT_SERVICES_DATA, true);
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
*
@ -345,7 +372,7 @@ static efi_status_t do_bootefi_exec(void *efi,
efi_handle_t mem_handle = NULL;
struct efi_device_path *memdp = NULL;
efi_status_t ret;
struct efi_loaded_image_obj *image_handle = NULL;
struct efi_loaded_image_obj *image_obj = NULL;
struct efi_loaded_image *loaded_image_info = NULL;
EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
@ -354,7 +381,7 @@ static efi_status_t do_bootefi_exec(void *efi,
/*
* Special case for efi payload not loaded from disk, such as
* 'bootefi hello' or for example payload loaded directly into
* memory via jtag, etc:
* memory via JTAG, etc:
*/
if (!device_path && !image_path) {
printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
@ -367,27 +394,25 @@ static efi_status_t do_bootefi_exec(void *efi,
*/
ret = efi_create_handle(&mem_handle);
if (ret != EFI_SUCCESS)
goto exit;
return ret; /* TODO: leaks device_path */
ret = efi_add_protocol(mem_handle, &efi_guid_device_path,
device_path);
if (ret != EFI_SUCCESS)
goto exit;
goto err_add_protocol;
} else {
assert(device_path && image_path);
}
ret = efi_setup_loaded_image(device_path, image_path, &image_handle,
&loaded_image_info);
if (ret != EFI_SUCCESS)
goto exit;
ret = bootefi_run_prepare("bootargs", device_path, image_path,
&image_obj, &loaded_image_info);
if (ret)
goto err_prepare;
/* Transfer environment variable bootargs as load options */
set_load_options(loaded_image_info, "bootargs");
/* Load the EFI payload */
entry = efi_load_pe(image_handle, efi, loaded_image_info);
entry = efi_load_pe(image_obj, efi, loaded_image_info);
if (!entry) {
ret = EFI_LOAD_ERROR;
goto exit;
goto err_prepare;
}
if (memdp) {
@ -405,9 +430,9 @@ static efi_status_t do_bootefi_exec(void *efi,
/* Call our payload! */
debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
if (setjmp(&image_handle->exit_jmp)) {
ret = image_handle->exit_status;
goto exit;
if (setjmp(&image_obj->exit_jmp)) {
ret = image_obj->exit_status;
goto err_prepare;
}
#ifdef CONFIG_ARM64
@ -418,7 +443,7 @@ static efi_status_t do_bootefi_exec(void *efi,
/* Move into EL2 and keep running there */
armv8_switch_to_el2((ulong)entry,
(ulong)image_handle,
(ulong)&image_obj->header,
(ulong)&systab, 0, (ulong)efi_run_in_el2,
ES_TO_AARCH64);
@ -435,7 +460,7 @@ static efi_status_t do_bootefi_exec(void *efi,
secure_ram_addr(_do_nonsec_entry)(
efi_run_in_hyp,
(uintptr_t)entry,
(uintptr_t)image_handle,
(uintptr_t)&image_obj->header,
(uintptr_t)&systab);
/* Should never reach here, efi exits with longjmp */
@ -443,18 +468,59 @@ static efi_status_t do_bootefi_exec(void *efi,
}
#endif
ret = efi_do_enter(image_handle, &systab, entry);
ret = efi_do_enter(&image_obj->header, &systab, entry);
exit:
err_prepare:
/* image has returned, loaded-image obj goes *poof*: */
if (image_handle)
efi_delete_handle(&image_handle->parent);
bootefi_run_finish(image_obj, loaded_image_info);
err_add_protocol:
if (mem_handle)
efi_delete_handle(mem_handle);
return ret;
}
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
/**
* bootefi_test_prepare() - prepare to run an EFI test
*
* This sets things up so we can call EFI functions. This involves preparing
* the 'gd' pointer and setting up the load ed image data structures.
*
* @image_objp: loaded_image_infop: Pointer to a struct which will hold the
* loaded image object. This struct will be inited by this function before
* use.
* @loaded_image_infop: Pointer to a struct which will hold the loaded image
* info. This struct will be inited by this function before use.
* @path: File path to the test being run (often just the test name with a
* backslash before it
* @test_func: Address of the test function that is being run
* @load_options_path: U-Boot environment variable to use as load options
* @return 0 if OK, -ve on error
*/
static efi_status_t bootefi_test_prepare
(struct efi_loaded_image_obj **image_objp,
struct efi_loaded_image **loaded_image_infop, const char *path,
ulong test_func, const char *load_options_path)
{
/* Construct a dummy device path */
bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
(uintptr_t)test_func,
(uintptr_t)test_func);
if (!bootefi_device_path)
return EFI_OUT_OF_RESOURCES;
bootefi_image_path = efi_dp_from_file(NULL, 0, path);
if (!bootefi_image_path)
return EFI_OUT_OF_RESOURCES;
return bootefi_run_prepare(load_options_path, bootefi_device_path,
bootefi_image_path, image_objp,
loaded_image_infop);
}
#endif /* CONFIG_CMD_BOOTEFI_SELFTEST */
static int do_bootefi_bootmgr_exec(void)
{
struct efi_device_path *device_path, *file_path;
@ -527,29 +593,17 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
#endif
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
if (!strcmp(argv[1], "selftest")) {
struct efi_loaded_image_obj *image_handle;
struct efi_loaded_image_obj *image_obj;
struct efi_loaded_image *loaded_image_info;
/* Construct a dummy device path. */
bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
(uintptr_t)&efi_selftest,
(uintptr_t)&efi_selftest);
bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest");
r = efi_setup_loaded_image(bootefi_device_path,
bootefi_image_path, &image_handle,
&loaded_image_info);
if (r != EFI_SUCCESS)
if (bootefi_test_prepare(&image_obj, &loaded_image_info,
"\\selftest", (uintptr_t)&efi_selftest,
"efi_selftest"))
return CMD_RET_FAILURE;
efi_save_gd();
/* Transfer environment variable efi_selftest as load options */
set_load_options(loaded_image_info, "efi_selftest");
/* Execute the test */
r = efi_selftest(image_handle, &systab);
efi_restore_gd();
free(loaded_image_info->load_options);
efi_delete_handle(&image_handle->parent);
r = efi_selftest(&image_obj->header, &systab);
bootefi_run_finish(image_obj, loaded_image_info);
return r != EFI_SUCCESS;
} else
#endif
@ -608,45 +662,19 @@ U_BOOT_CMD(
void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
{
char filename[32] = { 0 }; /* dp->str is u16[32] long */
char *s;
struct efi_device_path *device, *image;
efi_status_t ret;
/* efi_set_bootdev is typically called repeatedly, recover memory */
efi_free_pool(bootefi_device_path);
efi_free_pool(bootefi_image_path);
/* If blk_get_device_part_str fails, avoid duplicate free. */
bootefi_device_path = NULL;
bootefi_image_path = NULL;
if (strcmp(dev, "Net")) {
struct blk_desc *desc;
disk_partition_t fs_partition;
int part;
part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1);
if (part < 0)
return;
bootefi_device_path = efi_dp_from_part(desc, part);
ret = efi_dp_from_name(dev, devnr, path, &device, &image);
if (ret == EFI_SUCCESS) {
bootefi_device_path = device;
bootefi_image_path = image;
} else {
#ifdef CONFIG_NET
bootefi_device_path = efi_dp_from_eth();
#endif
bootefi_device_path = NULL;
bootefi_image_path = NULL;
}
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
set_default_env(NULL, 0);
#ifdef CONFIG_OF_CONTROL
env_set_addr("fdtcontroladdr", gd->fdt_blob);
env_set_hex("fdtcontroladdr",
(unsigned long)map_to_sysmem(gd->fdt_blob));
#endif
/* Initialize from environment */

View file

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

View file

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

View file

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

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
network booting has been on UDP based protocols. A TCP stack and HTTP support
@ -41,8 +39,7 @@ fine grained control of the boot process and can provide a command shell.
iPXE can be built as an EFI application (named snp.efi) which can be loaded and
run by U-Boot.
Boot sequence
-------------
## Boot sequence
U-Boot loads the EFI application iPXE snp.efi using the bootefi command. This
application has network access via the simple network protocol offered by
@ -106,19 +103,16 @@ the EFI stub Linux is called as an EFI application::
| |
| ~ ~ ~ ~|
Security
--------
## Security
The iSCSI protocol is not encrypted. The traffic could be secured using IPsec
but neither U-Boot nor iPXE does support this. So we should at least separate
the iSCSI traffic from all other network traffic. This can be achieved using a
virtual local area network (VLAN).
Configuration
-------------
## Configuration
iPXE
^^^^
### iPXE
For running iPXE on arm64 the bin-arm64-efi/snp.efi build target is needed::
@ -157,9 +151,20 @@ following into src/config/local/general.h is sufficient for most use cases::
#define DOWNLOAD_PROTO_NFS /* Network File System Protocol */
#define DOWNLOAD_PROTO_FILE /* Local file system access */
Links
-----
### Open-iSCSI
When the root file system is on an iSCSI drive you should disable pings and set
the replacement timer to a high value [3]:
node.conn[0].timeo.noop_out_interval = 0
node.conn[0].timeo.noop_out_timeout = 0
node.session.timeo.replacement_timeout = 86400
## Links
* [1](https://ipxe.org) https://ipxe.org - iPXE open source boot firmware
* [2](https://www.gnu.org/software/grub/) https://www.gnu.org/software/grub/ -
GNU GRUB (Grand Unified Bootloader)
GNU GRUB (Grand Unified Bootloader)
* [3](https://github.com/open-iscsi/open-iscsi/blob/master/README)
https://github.com/open-iscsi/open-iscsi/blob/master/README -
Open-iSCSI README

View file

@ -9,31 +9,38 @@
#include <common.h>
#include <dm.h>
#include <dm/lists.h>
#include <efi_loader.h>
#include <linux/libfdt.h>
#include <linux/arm-smccc.h>
#include <linux/errno.h>
#include <linux/printk.h>
#include <linux/psci.h>
psci_fn *invoke_psci_fn;
#define DRIVER_NAME "psci"
static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
unsigned long arg0, unsigned long arg1,
unsigned long arg2)
#define PSCI_METHOD_HVC 1
#define PSCI_METHOD_SMC 2
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;
arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
return res.a0;
}
static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
unsigned long arg0, unsigned long arg1,
unsigned long arg2)
{
struct arm_smccc_res res;
arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
/*
* In the __efi_runtime we need to avoid the switch statement. In some
* cases the compiler creates lookup tables to implement switch. These
* tables are not correctly relocated when SetVirtualAddressMap is
* called.
*/
if (psci_method == PSCI_METHOD_SMC)
arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
else if (psci_method == PSCI_METHOD_HVC)
arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
else
res.a0 = PSCI_RET_DISABLED;
return res.a0;
}
@ -67,9 +74,9 @@ static int psci_probe(struct udevice *dev)
}
if (!strcmp("hvc", method)) {
invoke_psci_fn = __invoke_psci_fn_hvc;
psci_method = PSCI_METHOD_HVC;
} else if (!strcmp("smc", method)) {
invoke_psci_fn = __invoke_psci_fn_smc;
psci_method = PSCI_METHOD_SMC;
} else {
pr_warn("invalid \"method\" property: %s\n", method);
return -EINVAL;
@ -78,6 +85,67 @@ static int psci_probe(struct udevice *dev)
return 0;
}
/**
* void do_psci_probe() - probe PSCI firmware driver
*
* Ensure that psci_method is initialized.
*/
static void __maybe_unused do_psci_probe(void)
{
struct udevice *dev;
uclass_get_device_by_name(UCLASS_FIRMWARE, DRIVER_NAME, &dev);
}
#if IS_ENABLED(CONFIG_EFI_LOADER) && IS_ENABLED(CONFIG_PSCI_RESET)
efi_status_t efi_reset_system_init(void)
{
do_psci_probe();
return EFI_SUCCESS;
}
void __efi_runtime EFIAPI efi_reset_system(enum efi_reset_type reset_type,
efi_status_t reset_status,
unsigned long data_size,
void *reset_data)
{
if (reset_type == EFI_RESET_COLD ||
reset_type == EFI_RESET_WARM ||
reset_type == EFI_RESET_PLATFORM_SPECIFIC) {
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
} else if (reset_type == EFI_RESET_SHUTDOWN) {
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
while (1)
;
}
#endif /* IS_ENABLED(CONFIG_EFI_LOADER) && IS_ENABLED(CONFIG_PSCI_RESET) */
#ifdef CONFIG_PSCI_RESET
void reset_misc(void)
{
do_psci_probe();
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
}
#endif /* CONFIG_PSCI_RESET */
#ifdef CONFIG_CMD_POWEROFF
int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
do_psci_probe();
puts("poweroff ...\n");
udelay(50000); /* wait 50 ms */
disable_interrupts();
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
enable_interrupts();
log_err("Power off not supported on this platform\n");
return CMD_RET_FAILURE;
}
#endif
static const struct udevice_id psci_of_match[] = {
{ .compatible = "arm,psci" },
{ .compatible = "arm,psci-0.2" },
@ -86,7 +154,7 @@ static const struct udevice_id psci_of_match[] = {
};
U_BOOT_DRIVER(psci) = {
.name = "psci",
.name = DRIVER_NAME,
.id = UCLASS_FIRMWARE,
.of_match = psci_of_match,
.bind = psci_bind,

View file

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

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

View file

@ -11,6 +11,24 @@
#ifndef _ASM_PE_H
#define _ASM_PE_H
/* Characteristics */
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
/* Reserved 0x0040 */
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
#define IMAGE_FILE_32BIT_MACHINE 0x0100
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
#define IMAGE_FILE_SYSTEM 0x1000
#define IMAGE_FILE_DLL 0x2000
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
/* Subsystem type */
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11

View file

@ -105,6 +105,17 @@ int mdm_init(void);
*/
void board_show_dram(phys_size_t size);
/**
* Get the uppermost pointer that is valid to access
*
* Some systems may not map all of their address space. This function allows
* boards to indicate what their highest support pointer value is for DRAM
* access.
*
* @param total_size Size of U-Boot (unused?)
*/
ulong board_get_usable_ram_top(ulong total_size);
/**
* arch_fixup_fdt() - Write arch-specific information to fdt
*

View file

@ -96,7 +96,7 @@ typedef struct {
typedef unsigned long efi_status_t;
typedef u64 efi_physical_addr_t;
typedef u64 efi_virtual_addr_t;
typedef void *efi_handle_t;
typedef struct efi_object *efi_handle_t;
#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \

View file

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

View file

@ -167,28 +167,41 @@ struct efi_handler {
struct list_head open_infos;
};
/*
* UEFI has a poor man's OO model where one "object" can be polymorphic and have
* multiple different protocols (classes) attached to it.
/**
* struct efi_object - dereferenced EFI handle
*
* This struct is the parent struct for all of our actual implementation objects
* that can include it to make themselves an EFI object
* @link: pointers to put the handle into a linked list
* @protocols: linked list with the protocol interfaces installed on this
* handle
*
* UEFI offers a flexible and expandable object model. The objects in the UEFI
* API are devices, drivers, and loaded images. struct efi_object is our storage
* structure for these objects.
*
* When including this structure into a larger structure always put it first so
* that when deleting a handle the whole encompassing structure can be freed.
*
* A pointer to this structure is referred to as a handle. Typedef efi_handle_t
* has been created for such pointers.
*/
struct efi_object {
/* Every UEFI object is part of a global object list */
struct list_head link;
/* The list of protocols */
struct list_head protocols;
/* The object spawner can either use this for data or as identifier */
void *handle;
};
/**
* struct efi_loaded_image_obj - handle of a loaded image
*
* @header: EFI object header
* @reloc_base: base address for the relocated image
* @reloc_size: size of the relocated image
* @exit_jmp: long jump buffer for returning form started image
* @entry: entry address of the relocated image
*/
struct efi_loaded_image_obj {
/* Generic EFI object parent class data */
struct efi_object parent;
struct efi_object header;
void *reloc_base;
aligned_u64 reloc_size;
efi_status_t exit_status;
@ -290,11 +303,11 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
/* Call this to set the current device name */
void efi_set_bootdev(const char *dev, const char *devnr, const char *path);
/* Add a new object to the object list. */
void efi_add_handle(struct efi_object *obj);
void efi_add_handle(efi_handle_t obj);
/* Create handle */
efi_status_t efi_create_handle(efi_handle_t *handle);
/* Delete handle */
void efi_delete_handle(struct efi_object *obj);
void efi_delete_handle(efi_handle_t obj);
/* Call this to validate a handle and find the EFI object for it */
struct efi_object *efi_search_obj(const efi_handle_t handle);
/* Find a protocol on a handle */
@ -331,7 +344,16 @@ struct efi_simple_file_system_protocol *efi_simple_file_system(
/* open file from device-path: */
struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);
/**
* efi_size_in_pages() - convert size in bytes to size in pages
*
* This macro returns the number of EFI memory pages required to hold 'size'
* bytes.
*
* @size: size in bytes
* Return: size in pages
*/
#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
/* Generic EFI memory allocator, call this to get memory */
void *efi_alloc(uint64_t len, int memory_type);
/* More specific EFI memory allocator, called by EFI payloads */
@ -419,6 +441,10 @@ const struct efi_device_path *efi_dp_last_node(
efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
struct efi_device_path **device_path,
struct efi_device_path **file_path);
efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
const char *path,
struct efi_device_path **device,
struct efi_device_path **file);
#define EFI_DP_TYPE(_dp, _type, _subtype) \
(((_dp)->type == DEVICE_PATH_TYPE_##_type) && \
@ -492,6 +518,29 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
void *data);
/*
* See section 3.1.3 in the v2.7 UEFI spec for more details on
* the layout of EFI_LOAD_OPTION. In short it is:
*
* typedef struct _EFI_LOAD_OPTION {
* UINT32 Attributes;
* UINT16 FilePathListLength;
* // CHAR16 Description[]; <-- variable length, NULL terminated
* // EFI_DEVICE_PATH_PROTOCOL FilePathList[];
* <-- FilePathListLength bytes
* // UINT8 OptionalData[];
* } EFI_LOAD_OPTION;
*/
struct efi_load_option {
u32 attributes;
u16 file_path_length;
u16 *label;
struct efi_device_path *file_path;
u8 *optional_data;
};
void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data);
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data);
void *efi_bootmgr_load(struct efi_device_path **device_path,
struct efi_device_path **file_path);

View file

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

View file

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

View file

@ -8,7 +8,7 @@ ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_EFI) += efi/
obj-$(CONFIG_EFI_LOADER) += efi_driver/
obj-$(CONFIG_EFI_LOADER) += efi_loader/
obj-$(CONFIG_EFI_LOADER) += efi_selftest/
obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/
obj-$(CONFIG_LZMA) += lzma/
obj-$(CONFIG_BZIP2) += bzip2/
obj-$(CONFIG_TIZEN) += tizen/

View file

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

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* EFI utils
* EFI boot manager
*
* Copyright (c) 2017 Rob Clark
*/
@ -9,6 +9,7 @@
#include <charset.h>
#include <malloc.h>
#include <efi_loader.h>
#include <asm/unaligned.h>
static const struct efi_boot_services *bs;
static const struct efi_runtime_services *rs;
@ -30,42 +31,68 @@ static const struct efi_runtime_services *rs;
*/
/*
* See section 3.1.3 in the v2.7 UEFI spec for more details on
* the layout of EFI_LOAD_OPTION. In short it is:
*
* typedef struct _EFI_LOAD_OPTION {
* UINT32 Attributes;
* UINT16 FilePathListLength;
* // CHAR16 Description[]; <-- variable length, NULL terminated
* // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; <-- FilePathListLength bytes
* // UINT8 OptionalData[];
* } EFI_LOAD_OPTION;
*/
struct load_option {
u32 attributes;
u16 file_path_length;
u16 *label;
struct efi_device_path *file_path;
u8 *optional_data;
};
/* parse an EFI_LOAD_OPTION, as described above */
static void parse_load_option(struct load_option *lo, void *ptr)
/* Parse serialized data and transform it into efi_load_option structure */
void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data)
{
lo->attributes = *(u32 *)ptr;
ptr += sizeof(u32);
lo->attributes = get_unaligned_le32(data);
data += sizeof(u32);
lo->file_path_length = *(u16 *)ptr;
ptr += sizeof(u16);
lo->file_path_length = get_unaligned_le16(data);
data += sizeof(u16);
lo->label = ptr;
ptr += (u16_strlen(lo->label) + 1) * 2;
/* FIXME */
lo->label = (u16 *)data;
data += (u16_strlen(lo->label) + 1) * sizeof(u16);
lo->file_path = ptr;
ptr += lo->file_path_length;
/* FIXME */
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 */
@ -100,7 +127,7 @@ static void *get_var(u16 *name, const efi_guid_t *vendor,
static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
struct efi_device_path **file_path)
{
struct load_option lo;
struct efi_load_option lo;
u16 varname[] = L"Boot0000";
u16 hexmap[] = L"0123456789ABCDEF";
void *load_option, *image = NULL;
@ -115,7 +142,7 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
if (!load_option)
return NULL;
parse_load_option(&lo, load_option);
efi_deserialize_load_option(&lo, load_option);
if (lo.attributes & LOAD_OPTION_ACTIVE) {
efi_status_t ret;

View file

@ -26,6 +26,14 @@ LIST_HEAD(efi_obj_list);
/* List of all events */
LIST_HEAD(efi_events);
/*
* If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
* we need to do trickery with caches. Since we don't want to break the EFI
* aware boot path, only apply hacks when loading exiting directly (breaking
* direct Linux EFI booting along the way - oh well).
*/
static bool efi_is_direct_boot = true;
#ifdef CONFIG_ARM
/*
* The "gd" pointer lives in a register on ARM and AArch64 that we declare
@ -416,13 +424,12 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer)
*
* The protocols list is initialized. The object handle is set.
*/
void efi_add_handle(struct efi_object *obj)
void efi_add_handle(efi_handle_t handle)
{
if (!obj)
if (!handle)
return;
INIT_LIST_HEAD(&obj->protocols);
obj->handle = obj;
list_add_tail(&obj->link, &efi_obj_list);
INIT_LIST_HEAD(&handle->protocols);
list_add_tail(&handle->link, &efi_obj_list);
}
/**
@ -440,7 +447,7 @@ efi_status_t efi_create_handle(efi_handle_t *handle)
return EFI_OUT_OF_RESOURCES;
efi_add_handle(obj);
*handle = obj->handle;
*handle = obj;
return EFI_SUCCESS;
}
@ -536,13 +543,13 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
*
* @obj: handle to delete
*/
void efi_delete_handle(struct efi_object *obj)
void efi_delete_handle(efi_handle_t handle)
{
if (!obj)
if (!handle)
return;
efi_remove_all_protocols(obj->handle);
list_del(&obj->link);
free(obj);
efi_remove_all_protocols(handle);
list_del(&handle->link);
free(handle);
}
/**
@ -927,7 +934,7 @@ struct efi_object *efi_search_obj(const efi_handle_t handle)
struct efi_object *efiobj;
list_for_each_entry(efiobj, &efi_obj_list, link) {
if (efiobj->handle == handle)
if (efiobj == handle)
return efiobj;
}
@ -1019,7 +1026,7 @@ efi_status_t efi_add_protocol(const efi_handle_t handle,
* Return: status code
*/
static efi_status_t EFIAPI efi_install_protocol_interface(
void **handle, const efi_guid_t *protocol,
efi_handle_t *handle, const efi_guid_t *protocol,
int protocol_interface_type, void *protocol_interface)
{
efi_status_t r;
@ -1052,7 +1059,7 @@ out:
/**
* efi_get_drivers() - get all drivers associated to a controller
* @efiobj: handle of the controller
* @handle: handle of the controller
* @protocol: protocol GUID (optional)
* @number_of_drivers: number of child controllers
* @driver_handle_buffer: handles of the the drivers
@ -1061,7 +1068,7 @@ out:
*
* Return: status code
*/
static efi_status_t efi_get_drivers(struct efi_object *efiobj,
static efi_status_t efi_get_drivers(efi_handle_t handle,
const efi_guid_t *protocol,
efi_uintn_t *number_of_drivers,
efi_handle_t **driver_handle_buffer)
@ -1072,7 +1079,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
bool duplicate;
/* Count all driver associations */
list_for_each_entry(handler, &efiobj->protocols, link) {
list_for_each_entry(handler, &handle->protocols, link) {
if (protocol && guidcmp(handler->guid, protocol))
continue;
list_for_each_entry(item, &handler->open_infos, link) {
@ -1090,7 +1097,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
if (!*driver_handle_buffer)
return EFI_OUT_OF_RESOURCES;
/* Collect unique driver handles */
list_for_each_entry(handler, &efiobj->protocols, link) {
list_for_each_entry(handler, &handle->protocols, link) {
if (protocol && guidcmp(handler->guid, protocol))
continue;
list_for_each_entry(item, &handler->open_infos, link) {
@ -1117,7 +1124,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
/**
* efi_disconnect_all_drivers() - disconnect all drivers from a controller
* @efiobj: handle of the controller
* @handle: handle of the controller
* @protocol: protocol GUID (optional)
* @child_handle: handle of the child to destroy
*
@ -1128,16 +1135,16 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
*
* Return: status code
*/
static efi_status_t efi_disconnect_all_drivers(
struct efi_object *efiobj,
const efi_guid_t *protocol,
efi_handle_t child_handle)
static efi_status_t efi_disconnect_all_drivers
(efi_handle_t handle,
const efi_guid_t *protocol,
efi_handle_t child_handle)
{
efi_uintn_t number_of_drivers;
efi_handle_t *driver_handle_buffer;
efi_status_t r, ret;
ret = efi_get_drivers(efiobj, protocol, &number_of_drivers,
ret = efi_get_drivers(handle, protocol, &number_of_drivers,
&driver_handle_buffer);
if (ret != EFI_SUCCESS)
return ret;
@ -1145,7 +1152,7 @@ static efi_status_t efi_disconnect_all_drivers(
ret = EFI_NOT_FOUND;
while (number_of_drivers) {
r = EFI_CALL(efi_disconnect_controller(
efiobj->handle,
handle,
driver_handle_buffer[--number_of_drivers],
child_handle));
if (r == EFI_SUCCESS)
@ -1156,21 +1163,19 @@ static efi_status_t efi_disconnect_all_drivers(
}
/**
* efi_uninstall_protocol_interface() - uninstall protocol interface
* efi_uninstall_protocol() - uninstall protocol interface
*
* @handle: handle from which the protocol shall be removed
* @protocol: GUID of the protocol to be removed
* @protocol_interface: interface to be removed
*
* This function implements the UninstallProtocolInterface service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
* This function DOES NOT delete a handle without installed protocol.
*
* Return: status code
*/
static efi_status_t EFIAPI efi_uninstall_protocol_interface(
efi_handle_t handle, const efi_guid_t *protocol,
void *protocol_interface)
static efi_status_t efi_uninstall_protocol
(efi_handle_t handle, const efi_guid_t *protocol,
void *protocol_interface)
{
struct efi_object *efiobj;
struct efi_handler *handler;
@ -1178,8 +1183,6 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(
struct efi_open_protocol_info_item *pos;
efi_status_t r;
EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface);
/* Check handle */
efiobj = efi_search_obj(handle);
if (!efiobj) {
@ -1210,7 +1213,41 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(
}
r = efi_remove_protocol(handle, protocol, protocol_interface);
out:
return EFI_EXIT(r);
return r;
}
/**
* efi_uninstall_protocol_interface() - uninstall protocol interface
* @handle: handle from which the protocol shall be removed
* @protocol: GUID of the protocol to be removed
* @protocol_interface: interface to be removed
*
* This function implements the UninstallProtocolInterface service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
static efi_status_t EFIAPI efi_uninstall_protocol_interface
(efi_handle_t handle, const efi_guid_t *protocol,
void *protocol_interface)
{
efi_status_t ret;
EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface);
ret = efi_uninstall_protocol(handle, protocol, protocol_interface);
if (ret != EFI_SUCCESS)
goto out;
/* If the last protocol has been removed, delete the handle. */
if (list_empty(&handle->protocols)) {
list_del(&handle->link);
free(handle);
}
out:
return EFI_EXIT(ret);
}
/**
@ -1240,7 +1277,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify(
* @search_type: selection criterion
* @protocol: GUID of the protocol
* @search_key: registration key
* @efiobj: handle
* @handle: handle
*
* See the documentation of the LocateHandle service in the UEFI specification.
*
@ -1248,7 +1285,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify(
*/
static int efi_search(enum efi_locate_search_type search_type,
const efi_guid_t *protocol, void *search_key,
struct efi_object *efiobj)
efi_handle_t handle)
{
efi_status_t ret;
@ -1259,7 +1296,7 @@ static int efi_search(enum efi_locate_search_type search_type,
/* TODO: RegisterProtocolNotify is not implemented yet */
return -1;
case BY_PROTOCOL:
ret = efi_search_protocol(efiobj->handle, protocol, NULL);
ret = efi_search_protocol(handle, protocol, NULL);
return (ret != EFI_SUCCESS);
default:
/* Invalid search type */
@ -1331,7 +1368,7 @@ static efi_status_t efi_locate_handle(
/* Then fill the array */
list_for_each_entry(efiobj, &efi_obj_list, link) {
if (!efi_search(search_type, protocol, search_key, efiobj))
*buffer++ = efiobj->handle;
*buffer++ = efiobj;
}
return EFI_SUCCESS;
@ -1489,7 +1526,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
}
/* Add internal object to object list */
efi_add_handle(&obj->parent);
efi_add_handle(&obj->header);
if (info_ptr)
*info_ptr = info;
@ -1506,7 +1543,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
* When asking for the device path interface, return
* bootefi_device_path
*/
ret = efi_add_protocol(obj->parent.handle,
ret = efi_add_protocol(&obj->header,
&efi_guid_device_path, device_path);
if (ret != EFI_SUCCESS)
goto failure;
@ -1516,7 +1553,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
* When asking for the loaded_image interface, just
* return handle which points to loaded_image_info
*/
ret = efi_add_protocol(obj->parent.handle,
ret = efi_add_protocol(&obj->header,
&efi_guid_loaded_image, info);
if (ret != EFI_SUCCESS)
goto failure;
@ -1678,6 +1715,8 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
efi_is_direct_boot = false;
/* call the image! */
if (setjmp(&image_obj->exit_jmp)) {
/*
@ -1785,6 +1824,21 @@ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
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
* @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();
/* Fix up caches for EFI payloads if necessary */
efi_exit_caches();
/* This stops all lingering devices */
bootm_disable_interrupts();
@ -2176,7 +2233,7 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol,
efiobj = list_entry(lhandle, struct efi_object, link);
ret = efi_search_protocol(efiobj->handle, protocol, &handler);
ret = efi_search_protocol(efiobj, protocol, &handler);
if (ret == EFI_SUCCESS) {
*protocol_interface = handler->protocol_interface;
return EFI_EXIT(EFI_SUCCESS);
@ -2279,8 +2336,8 @@ out:
*
* Return: status code
*/
static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
void **handle, ...)
static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces
(efi_handle_t *handle, ...)
{
EFI_ENTRY("%p", handle);
@ -2316,7 +2373,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
for (; i; --i) {
protocol = efi_va_arg(argptr, efi_guid_t*);
protocol_interface = efi_va_arg(argptr, void*);
EFI_CALL(efi_uninstall_protocol_interface(handle, protocol,
EFI_CALL(efi_uninstall_protocol_interface(*handle, protocol,
protocol_interface));
}
efi_va_end(argptr);
@ -2339,7 +2396,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
* Return: status code
*/
static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
void *handle, ...)
efi_handle_t handle, ...)
{
EFI_ENTRY("%p", handle);
@ -2358,16 +2415,21 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
if (!protocol)
break;
protocol_interface = efi_va_arg(argptr, void*);
r = EFI_CALL(efi_uninstall_protocol_interface(
handle, protocol,
protocol_interface));
r = efi_uninstall_protocol(handle, protocol,
protocol_interface);
if (r != EFI_SUCCESS)
break;
i++;
}
efi_va_end(argptr);
if (r == EFI_SUCCESS)
if (r == EFI_SUCCESS) {
/* If the last protocol has been removed, delete the handle. */
if (list_empty(&handle->protocols)) {
list_del(&handle->link);
free(handle);
}
return EFI_EXIT(r);
}
/* If an error occurred undo all changes. */
efi_va_start(argptr, handle);
@ -2380,7 +2442,8 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
}
efi_va_end(argptr);
return EFI_EXIT(r);
/* In case of an error always return EFI_INVALID_PARAMETER */
return EFI_EXIT(EFI_INVALID_PARAMETER);
}
/**
@ -2553,10 +2616,10 @@ out:
*
* Return: status code
*/
static efi_status_t EFIAPI efi_open_protocol(
void *handle, const efi_guid_t *protocol,
void **protocol_interface, void *agent_handle,
void *controller_handle, uint32_t attributes)
static efi_status_t EFIAPI efi_open_protocol
(efi_handle_t handle, const efi_guid_t *protocol,
void **protocol_interface, efi_handle_t agent_handle,
efi_handle_t controller_handle, uint32_t attributes)
{
struct efi_handler *handler;
efi_status_t r = EFI_INVALID_PARAMETER;
@ -2828,13 +2891,19 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(
EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface,
new_interface);
ret = EFI_CALL(efi_uninstall_protocol_interface(handle, protocol,
old_interface));
/* Uninstall protocol but do not delete handle */
ret = efi_uninstall_protocol(handle, protocol, old_interface);
if (ret != EFI_SUCCESS)
goto out;
ret = EFI_CALL(efi_install_protocol_interface(&handle, protocol,
EFI_NATIVE_INTERFACE,
new_interface));
/* Install the new protocol */
ret = efi_add_protocol(handle, protocol, new_interface);
/*
* The UEFI spec does not specify what should happen to the handle
* if in case of an error no protocol interface remains on the handle.
* So let's do nothing here.
*/
if (ret != EFI_SUCCESS)
goto out;
/*

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.
* We should adhere to escape sequences documented in the console_codes
* manpage and the ECMA-48 standard.
* man page and the ECMA-48 standard.
*
* So here we follow a different approach. We position the cursor to the
* bottom right and query its position. Before leaving the function we
@ -480,7 +480,7 @@ void set_shift_mask(int mod, struct efi_key_state *key_state)
*
* This gets called when we have already parsed CSI.
*
* @modifiers: bitmask (shift, alt, ctrl)
* @modifiers: bit mask (shift, alt, ctrl)
* @return: the unmodified code
*/
static int analyze_modifiers(struct efi_key_state *key_state)
@ -1051,34 +1051,34 @@ static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
efi_status_t efi_console_register(void)
{
efi_status_t r;
struct efi_object *efi_console_output_obj;
struct efi_object *efi_console_input_obj;
efi_handle_t console_output_handle;
efi_handle_t console_input_handle;
/* Set up mode information */
query_console_size();
/* Create handles */
r = efi_create_handle((efi_handle_t *)&efi_console_output_obj);
r = efi_create_handle(&console_output_handle);
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_add_protocol(efi_console_output_obj->handle,
r = efi_add_protocol(console_output_handle,
&efi_guid_text_output_protocol, &efi_con_out);
if (r != EFI_SUCCESS)
goto out_of_memory;
systab.con_out_handle = efi_console_output_obj->handle;
systab.stderr_handle = efi_console_output_obj->handle;
systab.con_out_handle = console_output_handle;
systab.stderr_handle = console_output_handle;
r = efi_create_handle((efi_handle_t *)&efi_console_input_obj);
r = efi_create_handle(&console_input_handle);
if (r != EFI_SUCCESS)
goto out_of_memory;
r = efi_add_protocol(efi_console_input_obj->handle,
r = efi_add_protocol(console_input_handle,
&efi_guid_text_input_protocol, &efi_con_in);
if (r != EFI_SUCCESS)
goto out_of_memory;
systab.con_in_handle = efi_console_input_obj->handle;
r = efi_add_protocol(efi_console_input_obj->handle,
systab.con_in_handle = console_input_handle;
r = efi_add_protocol(console_input_handle,
&efi_guid_text_input_ex_protocol, &efi_con_in_ex);
if (r != EFI_SUCCESS)
goto out_of_memory;

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
* an End* node. This is useful to, for example, compare a device-path
* an End* node. This is useful to, for example, compare a device-path
* representing a device with one representing a file on the device, or
* a device with a parent device.
*/
@ -109,16 +109,17 @@ int efi_dp_match(const struct efi_device_path *a,
}
/*
* See UEFI spec (section 3.1.2, about short-form device-paths..
* tl;dr: we can have a device-path that starts with a USB WWID
* or USB Class node, and a few other cases which don't encode
* the full device path with bus hierarchy:
* We can have device paths that start with a USB WWID or a USB Class node,
* and a few other cases which don't encode the full device path with bus
* hierarchy:
*
* - MESSAGING:USB_WWID
* - MESSAGING:USB_CLASS
* - MEDIA:FILE_PATH
* - MEDIA:HARD_DRIVE
* - MESSAGING:URI
*
* See UEFI spec (section 3.1.2, about short-form device-paths)
*/
static struct efi_device_path *shorten_path(struct efi_device_path *dp)
{
@ -150,7 +151,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
struct efi_device_path *obj_dp;
efi_status_t ret;
ret = efi_search_protocol(efiobj->handle,
ret = efi_search_protocol(efiobj,
&efi_guid_device_path, &handler);
if (ret != EFI_SUCCESS)
continue;
@ -644,7 +645,7 @@ static unsigned dp_part_size(struct blk_desc *desc, int part)
/*
* Create a device node for a block device partition.
*
* @buf buffer to which the device path is wirtten
* @buf buffer to which the device path is written
* @desc block device descriptor
* @part partition number, 0 identifies a block device
*/
@ -709,7 +710,7 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
/*
* Create a device path for a block device or one of its partitions.
*
* @buf buffer to which the device path is wirtten
* @buf buffer to which the device path is written
* @desc block device descriptor
* @part partition number, 0 identifies a block device
*/
@ -728,7 +729,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
/*
* We *could* make a more accurate path, by looking at if_type
* and handling all the different cases like we do for non-
* legacy (ie CONFIG_BLK=y) case. But most important thing
* legacy (i.e. CONFIG_BLK=y) case. But most important thing
* is just to have a unique device-path for if_type+devnum.
* So map things to a fictitious USB device.
*/
@ -752,7 +753,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
return dp_part_node(buf, desc, part);
}
/* Construct a device-path from a partition on a blk device: */
/* Construct a device-path from a partition on a block device: */
struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
{
void *buf, *start;
@ -771,7 +772,7 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
/*
* Create a device node for a block device partition.
*
* @buf buffer to which the device path is wirtten
* @buf buffer to which the device path is written
* @desc block device descriptor
* @part partition number, 0 identifies a block device
*/
@ -791,7 +792,7 @@ struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
return buf;
}
/* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */
/* convert path to an UEFI style path (i.e. DOS style backslashes and UTF-16) */
static void path_to_uefi(u16 *uefi, const char *path)
{
while (*path) {
@ -941,3 +942,53 @@ efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
*file_path = fp;
return EFI_SUCCESS;
}
efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
const char *path,
struct efi_device_path **device,
struct efi_device_path **file)
{
int is_net;
struct blk_desc *desc = NULL;
disk_partition_t fs_partition;
int part = 0;
char filename[32] = { 0 }; /* dp->str is u16[32] long */
char *s;
if (path && !file)
return EFI_INVALID_PARAMETER;
is_net = !strcmp(dev, "Net");
if (!is_net) {
part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1);
if (part < 0)
return EFI_INVALID_PARAMETER;
if (device)
*device = efi_dp_from_part(desc, part);
} else {
#ifdef CONFIG_NET
if (device)
*device = efi_dp_from_eth();
#endif
}
if (!path)
return EFI_SUCCESS;
if (!is_net) {
/* Add leading / to fs paths, because they're absolute */
snprintf(filename, sizeof(filename), "/%s", path);
} else {
snprintf(filename, sizeof(filename), "%s", path);
}
/* DOS style file path: */
s = filename;
while ((s = strchr(s, '/')))
*s++ = '\\';
*file = efi_dp_from_file(((!is_net && device) ? desc : NULL),
part, filename);
return EFI_SUCCESS;
}

View file

@ -269,9 +269,9 @@ static char *efi_convert_single_device_node_to_text(
* for details.
*
* device_node device node to be converted
* display_only true if the shorter text represenation shall be used
* display_only true if the shorter text representation shall be used
* allow_shortcuts true if shortcut forms may be used
* @return text represenation of the device path
* @return text representation of the device path
* NULL if out of memory of device_path is NULL
*/
static uint16_t EFIAPI *efi_convert_device_node_to_text(
@ -302,9 +302,9 @@ out:
* for details.
*
* device_path device path to be converted
* display_only true if the shorter text represenation shall be used
* display_only true if the shorter text representation shall be used
* allow_shortcuts true if shortcut forms may be used
* @return text represenation of the device path
* @return text representation of the device path
* NULL if out of memory of device_path is NULL
*/
static uint16_t EFIAPI *efi_convert_device_path_to_text(

View file

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

View file

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

View file

@ -16,15 +16,22 @@ DECLARE_GLOBAL_DATA_PTR;
static const efi_guid_t efi_gop_guid = EFI_GOP_GUID;
/**
* struct efi_gop_obj - graphical output protocol object
*
* @header: EFI object header
* @ops: graphical output protocol interface
* @info: graphical output mode information
* @mode: graphical output mode
* @bpix: bits per pixel
* @fb: frame buffer
*/
struct efi_gop_obj {
/* Generic EFI object parent class data */
struct efi_object parent;
/* EFI Interface callback struct for gop */
struct efi_object header;
struct efi_gop ops;
/* The only mode we support */
struct efi_gop_mode_info info;
struct efi_gop_mode mode;
/* Fields we only have acces to during init */
/* Fields we only have access to during init */
u32 bpix;
void *fb;
};
@ -236,12 +243,12 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
}
/*
* Gcc can't optimize our BLT function well, but we need to make sure that
* GCC can't optimize our BLT function well, but we need to make sure that
* our 2-dimensional loop gets executed very quickly, otherwise the system
* will feel slow.
*
* By manually putting all obvious branch targets into functions which call
* our generic blt function with constants, the compiler can successfully
* our generic BLT function with constants, the compiler can successfully
* optimize for speed.
*/
static efi_status_t gop_blt_video_fill(struct efi_gop *this,
@ -439,13 +446,13 @@ efi_status_t efi_gop_register(void)
}
/* Hook up to the device list */
efi_add_handle(&gopobj->parent);
efi_add_handle(&gopobj->header);
/* Fill in object data */
ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid,
ret = efi_add_protocol(&gopobj->header, &efi_gop_guid,
&gopobj->ops);
if (ret != EFI_SUCCESS) {
printf("ERROR: Failure adding gop protocol\n");
printf("ERROR: Failure adding GOP protocol\n");
return ret;
}
gopobj->ops.query_mode = gop_query_mode;
@ -463,7 +470,10 @@ efi_status_t efi_gop_register(void)
if (bpix == LCD_COLOR32)
#endif
{
/* With 32bit color space we can directly expose the fb */
/*
* With 32bit color space we can directly expose the frame
* buffer
*/
gopobj->mode.fb_base = fb_base;
gopobj->mode.fb_size = fb_size;
}

View file

@ -11,6 +11,7 @@
#include <mapmem.h>
#include <watchdog.h>
#include <linux/list_sort.h>
#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
@ -294,6 +295,12 @@ static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr)
{
struct list_head *lhandle;
/*
* Prealign input max address, so we simplify our matching
* logic below and can just reuse it as return pointer.
*/
max_addr &= ~EFI_PAGE_MASK;
list_for_each(lhandle, &efi_mem) {
struct efi_mem_list *lmem = list_entry(lhandle,
struct efi_mem_list, link);
@ -378,7 +385,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
/* Reserve that map in our memory maps */
ret = efi_add_memory_map(addr, pages, memory_type, true);
if (ret == addr) {
*memory = (uintptr_t)map_sysmem(addr, len);
*memory = addr;
} else {
/* Map would overlap, bail out */
r = EFI_OUT_OF_RESOURCES;
@ -391,7 +398,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
void *efi_alloc(uint64_t len, int memory_type)
{
uint64_t ret = 0;
uint64_t pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
uint64_t pages = efi_size_in_pages(len);
efi_status_t r;
r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type, pages,
@ -412,12 +419,11 @@ void *efi_alloc(uint64_t len, int memory_type)
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
{
uint64_t r = 0;
uint64_t addr = map_to_sysmem((void *)(uintptr_t)memory);
r = efi_add_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY, false);
r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
/* Merging of adjacent free regions is missing */
if (r == addr)
if (r == memory)
return EFI_SUCCESS;
return EFI_NOT_FOUND;
@ -435,8 +441,8 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer)
{
efi_status_t r;
struct efi_pool_allocation *alloc;
u64 num_pages = (size + sizeof(struct efi_pool_allocation) +
EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
u64 num_pages = efi_size_in_pages(size +
sizeof(struct efi_pool_allocation));
if (!buffer)
return EFI_INVALID_PARAMETER;
@ -545,17 +551,51 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
__weak void efi_add_known_memory(void)
{
u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK;
int i;
/* Fix for 32bit targets with ram_top at 4G */
if (!ram_top)
ram_top = 0x100000000ULL;
/* Add RAM */
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
u64 ram_start = gd->bd->bi_dram[i].start;
u64 ram_size = gd->bd->bi_dram[i].size;
u64 start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
u64 pages = (ram_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
u64 ram_end, ram_start, pages;
efi_add_memory_map(start, pages, EFI_CONVENTIONAL_MEMORY,
false);
ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0);
ram_end = ram_start + gd->bd->bi_dram[i].size;
/* Remove partial pages */
ram_end &= ~EFI_PAGE_MASK;
ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
if (ram_end <= ram_start) {
/* Invalid mapping, keep going. */
continue;
}
pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
efi_add_memory_map(ram_start, pages,
EFI_CONVENTIONAL_MEMORY, false);
/*
* Boards may indicate to the U-Boot memory core that they
* can not support memory above ram_top. Let's honor this
* in the efi_loader subsystem too by declaring any memory
* above ram_top as "already occupied by firmware".
*/
if (ram_top < ram_start) {
/* ram_top is before this region, reserve all */
efi_add_memory_map(ram_start, pages,
EFI_BOOT_SERVICES_DATA, true);
} else if ((ram_top >= ram_start) && (ram_top < ram_end)) {
/* ram_top is inside this region, reserve parts */
pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT;
efi_add_memory_map(ram_top, pages,
EFI_BOOT_SERVICES_DATA, true);
}
}
}
@ -563,6 +603,7 @@ __weak void efi_add_known_memory(void)
static void add_u_boot_and_runtime(void)
{
unsigned long runtime_start, runtime_end, runtime_pages;
unsigned long runtime_mask = EFI_PAGE_MASK;
unsigned long uboot_start, uboot_pages;
unsigned long uboot_stack_size = 16 * 1024 * 1024;
@ -571,10 +612,22 @@ static void add_u_boot_and_runtime(void)
uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT;
efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false);
/* Add Runtime Services */
runtime_start = (ulong)&__efi_runtime_start & ~EFI_PAGE_MASK;
#if defined(__aarch64__)
/*
* Runtime Services must be 64KiB aligned according to the
* "AArch64 Platforms" section in the UEFI spec (2.7+).
*/
runtime_mask = SZ_64K - 1;
#endif
/*
* Add Runtime Services. We mark surrounding boottime code as runtime as
* well to fulfill the runtime alignment constraints but avoid padding.
*/
runtime_start = (ulong)&__efi_runtime_start & ~runtime_mask;
runtime_end = (ulong)&__efi_runtime_stop;
runtime_end = (runtime_end + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
runtime_end = (runtime_end + runtime_mask) & ~runtime_mask;
runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT;
efi_add_memory_map(runtime_start, runtime_pages,
EFI_RUNTIME_SERVICES_CODE, false);

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 bool new_rx_packet;
static void *new_tx_packet;
static void *transmit_buffer;
/*
* The notification function of this event is called in every timer cycle
* to check if a new network packet has been received.
@ -24,33 +26,85 @@ static struct efi_event *network_timer_event;
*/
static struct efi_event *wait_for_packet;
/**
* struct efi_net_obj - EFI object representing a network interface
*
* @header: EFI object header
* @net: simple network protocol interface
* @net_mode: status of the network interface
* @pxe: PXE base code protocol interface
* @pxe_mode: status of the PXE base code protocol
*/
struct efi_net_obj {
/* Generic EFI object parent class data */
struct efi_object parent;
/* EFI Interface callback struct for network */
struct efi_object header;
struct efi_simple_network net;
struct efi_simple_network_mode net_mode;
/* PXE struct to transmit dhcp data */
struct efi_pxe pxe;
struct efi_pxe_mode pxe_mode;
};
/*
* efi_net_start() - start the network interface
*
* This function implements the Start service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
* (UEFI) specification for details.
*
* @this: pointer to the protocol instance
* Return: status code
*/
static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
{
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p", this);
return EFI_EXIT(EFI_SUCCESS);
}
/* Check parameters */
if (!this) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
{
EFI_ENTRY("%p", this);
return EFI_EXIT(EFI_SUCCESS);
if (this->mode->state != EFI_NETWORK_STOPPED)
ret = EFI_ALREADY_STARTED;
else
this->mode->state = EFI_NETWORK_STARTED;
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
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
@ -59,7 +113,7 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
* @this: pointer to the protocol instance
* @extra_rx: extra receive buffer to be allocated
* @extra_tx: extra transmit buffer to be allocated
* @return: status code
* Return: status code
*/
static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
ulong extra_rx, ulong extra_tx)
@ -69,9 +123,10 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
/* Check parameters */
if (!this) {
r = EFI_INVALID_PARAMETER;
goto error;
goto out;
}
/* Setup packet buffers */
@ -84,32 +139,83 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
ret = eth_init();
if (ret < 0) {
eth_halt();
this->mode->state = EFI_NETWORK_STOPPED;
r = EFI_DEVICE_ERROR;
goto out;
} else {
this->mode->state = EFI_NETWORK_INITIALIZED;
}
error:
out:
return EFI_EXIT(r);
}
/*
* efi_net_reset() - reinitialize the network interface
*
* This function implements the Reset service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
* (UEFI) specification for details.
*
* @this: pointer to the protocol instance
* @extended_verification: execute exhaustive verification
* Return: status code
*/
static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
int extended_verification)
{
EFI_ENTRY("%p, %x", this, extended_verification);
return EFI_EXIT(EFI_SUCCESS);
return EFI_EXIT(EFI_CALL(efi_net_initialize(this, 0, 0)));
}
/*
* efi_net_shutdown() - shut down the network interface
*
* This function implements the Shutdown service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
* (UEFI) specification for details.
*
* @this: pointer to the protocol instance
* Return: status code
*/
static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
{
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p", this);
return EFI_EXIT(EFI_SUCCESS);
/* Check parameters */
if (!this) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
eth_halt();
this->mode->state = EFI_NETWORK_STOPPED;
out:
return EFI_EXIT(ret);
}
static efi_status_t EFIAPI efi_net_receive_filters(
struct efi_simple_network *this, u32 enable, u32 disable,
int reset_mcast_filter, ulong mcast_filter_count,
struct efi_mac_address *mcast_filter)
/*
* efi_net_receive_filters() - mange multicast receive filters
*
* This function implements the ReceiveFilters service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
* (UEFI) specification for details.
*
* @this: pointer to the protocol instance
* @enable: bit mask of receive filters to enable
* @disable: bit mask of receive filters to disable
* @reset_mcast_filter: true resets contents of the filters
* @mcast_filter_count: number of hardware MAC addresses in the new filters list
* @mcast_filter: list of new filters
* Return: status code
*/
static efi_status_t EFIAPI efi_net_receive_filters
(struct efi_simple_network *this, u32 enable, u32 disable,
int reset_mcast_filter, ulong mcast_filter_count,
struct efi_mac_address *mcast_filter)
{
EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
reset_mcast_filter, mcast_filter_count, mcast_filter);
@ -117,15 +223,40 @@ static efi_status_t EFIAPI efi_net_receive_filters(
return EFI_EXIT(EFI_UNSUPPORTED);
}
static efi_status_t EFIAPI efi_net_station_address(
struct efi_simple_network *this, int reset,
struct efi_mac_address *new_mac)
/*
* efi_net_station_address() - set the hardware MAC address
*
* This function implements the StationAddress service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
* (UEFI) specification for details.
*
* @this: pointer to the protocol instance
* @reset: if true reset the address to default
* @new_mac: new MAC address
* Return: status code
*/
static efi_status_t EFIAPI efi_net_station_address
(struct efi_simple_network *this, int reset,
struct efi_mac_address *new_mac)
{
EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
return EFI_EXIT(EFI_UNSUPPORTED);
}
/*
* efi_net_statistics() - reset or collect statistics of the network interface
*
* This function implements the Statistics service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
* (UEFI) specification for details.
*
* @this: pointer to the protocol instance
* @reset: if true, the statistics are reset
* @stat_size: size of the statistics table
* @stat_table: table to receive the statistics
* Return: status code
*/
static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
int reset, ulong *stat_size,
void *stat_table)
@ -135,6 +266,19 @@ static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
return EFI_EXIT(EFI_UNSUPPORTED);
}
/*
* efi_net_mcastiptomac() - translate multicast IP address to MAC address
*
* This function implements the Statistics service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
* (UEFI) specification for details.
*
* @this: pointer to the protocol instance
* @ipv6: true if the IP address is an IPv6 address
* @ip: IP address
* @mac: MAC address
* Return: status code
*/
static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
int ipv6,
struct efi_ip_address *ip,
@ -145,6 +289,19 @@ static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
return EFI_EXIT(EFI_INVALID_PARAMETER);
}
/**
* efi_net_nvdata() - read or write NVRAM
*
* This function implements the GetStatus service of the Simple Network
* Protocol. See the UEFI spec for details.
*
* @this: the instance of the Simple Network Protocol
* @readwrite: true for read, false for write
* @offset: offset in NVRAM
* @buffer_size: size of buffer
* @buffer: buffer
* Return: status code
*/
static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
int read_write, ulong offset,
ulong buffer_size, char *buffer)
@ -155,13 +312,42 @@ static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
return EFI_EXIT(EFI_UNSUPPORTED);
}
/**
* efi_net_get_status() - get interrupt status
*
* This function implements the GetStatus service of the Simple Network
* Protocol. See the UEFI spec for details.
*
* @this: the instance of the Simple Network Protocol
* @int_status: interface status
* @txbuf: transmission buffer
*/
static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
u32 *int_status, void **txbuf)
{
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
efi_timer_check();
/* Check parameters */
if (!this) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
switch (this->mode->state) {
case EFI_NETWORK_STOPPED:
ret = EFI_NOT_STARTED;
goto out;
case EFI_NETWORK_STARTED:
ret = EFI_DEVICE_ERROR;
goto out;
default:
break;
}
if (int_status) {
/* We send packets synchronously, so nothing is outstanding */
*int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
@ -172,65 +358,103 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
*txbuf = new_tx_packet;
new_tx_packet = NULL;
return EFI_EXIT(EFI_SUCCESS);
out:
return EFI_EXIT(ret);
}
static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this,
size_t header_size, size_t buffer_size, void *buffer,
struct efi_mac_address *src_addr,
struct efi_mac_address *dest_addr, u16 *protocol)
/**
* efi_net_transmit() - transmit a packet
*
* This function implements the Transmit service of the Simple Network Protocol.
* See the UEFI spec for details.
*
* @this: the instance of the Simple Network Protocol
* @header_size: size of the media header
* @buffer_size: size of the buffer to receive the packet
* @buffer: buffer to receive the packet
* @src_addr: source hardware MAC address
* @dest_addr: destination hardware MAC address
* @protocol: type of header to build
* Return: status code
*/
static efi_status_t EFIAPI efi_net_transmit
(struct efi_simple_network *this, size_t header_size,
size_t buffer_size, void *buffer,
struct efi_mac_address *src_addr,
struct efi_mac_address *dest_addr, u16 *protocol)
{
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this,
(unsigned long)header_size, (unsigned long)buffer_size,
buffer, src_addr, dest_addr, protocol);
efi_timer_check();
if (header_size) {
/* We would need to create the header if header_size != 0 */
return EFI_EXIT(EFI_INVALID_PARAMETER);
/* Check parameters */
if (!this) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
/* We do not support jumbo packets */
if (buffer_size > PKTSIZE_ALIGN) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
if (header_size) {
/*
* TODO: We would need to create the header
* if header_size != 0
*/
ret = EFI_INVALID_PARAMETER;
goto out;
}
switch (this->mode->state) {
case EFI_NETWORK_STOPPED:
ret = EFI_NOT_STARTED;
goto out;
case EFI_NETWORK_STARTED:
ret = EFI_DEVICE_ERROR;
goto out;
default:
break;
}
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
/* Ethernet packets always fit, just bounce */
memcpy(efi_bounce_buffer, buffer, buffer_size);
net_send_packet(efi_bounce_buffer, buffer_size);
#else
net_send_packet(buffer, buffer_size);
#endif
memcpy(transmit_buffer, buffer, buffer_size);
net_send_packet(transmit_buffer, buffer_size);
new_tx_packet = buffer;
return EFI_EXIT(EFI_SUCCESS);
out:
return EFI_EXIT(ret);
}
static void efi_net_push(void *pkt, int len)
{
new_rx_packet = true;
wait_for_packet->is_signaled = true;
}
/*
* Receive a packet from a network interface.
/**
* efi_net_receive() - receive a packet from a network interface
*
* This function implements the Receive service of the Simple Network Protocol.
* See the UEFI spec for details.
*
* @this the instance of the Simple Network Protocol
* @header_size size of the media header
* @buffer_size size of the buffer to receive the packet
* @buffer buffer to receive the packet
* @src_addr source MAC address
* @dest_addr destination MAC address
* @protocol protocol
* @return status code
* @this: the instance of the Simple Network Protocol
* @header_size: size of the media header
* @buffer_size: size of the buffer to receive the packet
* @buffer: buffer to receive the packet
* @src_addr: source MAC address
* @dest_addr: destination MAC address
* @protocol: protocol
* Return: status code
*/
static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
size_t *header_size, size_t *buffer_size, void *buffer,
struct efi_mac_address *src_addr,
struct efi_mac_address *dest_addr, u16 *protocol)
static efi_status_t EFIAPI efi_net_receive
(struct efi_simple_network *this, size_t *header_size,
size_t *buffer_size, void *buffer,
struct efi_mac_address *src_addr,
struct efi_mac_address *dest_addr, u16 *protocol)
{
efi_status_t ret = EFI_SUCCESS;
struct ethernet_hdr *eth_hdr;
size_t hdr_size = sizeof(struct ethernet_hdr);
u16 protlen;
@ -238,14 +462,35 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
buffer_size, buffer, src_addr, dest_addr, protocol);
/* Execute events */
efi_timer_check();
if (!new_rx_packet)
return EFI_EXIT(EFI_NOT_READY);
/* Check parameters */
if (!this) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
switch (this->mode->state) {
case EFI_NETWORK_STOPPED:
ret = EFI_NOT_STARTED;
goto out;
case EFI_NETWORK_STARTED:
ret = EFI_DEVICE_ERROR;
goto out;
default:
break;
}
if (!new_rx_packet) {
ret = EFI_NOT_READY;
goto out;
}
/* Check that we at least received an Ethernet header */
if (net_rx_packet_len < sizeof(struct ethernet_hdr)) {
new_rx_packet = false;
return EFI_EXIT(EFI_NOT_READY);
ret = EFI_NOT_READY;
goto out;
}
/* Fill export parameters */
eth_hdr = (struct ethernet_hdr *)net_rx_packet;
@ -263,18 +508,24 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this,
if (protocol)
*protocol = protlen;
if (*buffer_size < net_rx_packet_len) {
/* Packet doesn't fit, try again with bigger buf */
/* Packet doesn't fit, try again with bigger buffer */
*buffer_size = net_rx_packet_len;
return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
ret = EFI_BUFFER_TOO_SMALL;
goto out;
}
/* Copy packet */
memcpy(buffer, net_rx_packet, net_rx_packet_len);
*buffer_size = net_rx_packet_len;
new_rx_packet = false;
return EFI_EXIT(EFI_SUCCESS);
out:
return EFI_EXIT(ret);
}
/**
* efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
*
* This function is called by dhcp_handler().
*/
void efi_net_set_dhcp_ack(void *pkt, int len)
{
int maxsize = sizeof(*dhcp_ack);
@ -285,8 +536,22 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
memcpy(dhcp_ack, pkt, min(len, maxsize));
}
/*
* Check if a new network packet has been received.
/**
* efi_net_push() - callback for received network packet
*
* This function is called when a network packet is received by eth_rx().
*
* @pkt: network packet
* @len: length
*/
static void efi_net_push(void *pkt, int len)
{
new_rx_packet = true;
wait_for_packet->is_signaled = true;
}
/**
* efi_network_timer_notify() - check if a new network packet has been received
*
* This notification function is called in every timer cycle.
*
@ -296,47 +561,65 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
static void EFIAPI efi_network_timer_notify(struct efi_event *event,
void *context)
{
struct efi_simple_network *this = (struct efi_simple_network *)context;
EFI_ENTRY("%p, %p", event, context);
/*
* Some network drivers do not support calling eth_rx() before
* initialization.
*/
if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
goto out;
if (!new_rx_packet) {
push_packet = efi_net_push;
eth_rx();
push_packet = NULL;
}
out:
EFI_EXIT(EFI_SUCCESS);
}
/* This gets called from do_bootefi_exec(). */
/**
* efi_net_register() - register the simple network protocol
*
* This gets called from do_bootefi_exec().
*/
efi_status_t efi_net_register(void)
{
struct efi_net_obj *netobj;
struct efi_net_obj *netobj = NULL;
efi_status_t r;
if (!eth_get_dev()) {
/* No eth device active, don't expose any */
/* No network device active, don't expose any */
return EFI_SUCCESS;
}
/* We only expose the "active" eth device, so one is enough */
/* We only expose the "active" network device, so one is enough */
netobj = calloc(1, sizeof(*netobj));
if (!netobj) {
printf("ERROR: Out of memory\n");
return EFI_OUT_OF_RESOURCES;
}
if (!netobj)
goto out_of_resources;
/* Allocate an aligned transmit buffer */
transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
if (!transmit_buffer)
goto out_of_resources;
transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
/* Hook net up to the device list */
efi_add_handle(&netobj->parent);
efi_add_handle(&netobj->header);
/* Fill in object data */
r = efi_add_protocol(netobj->parent.handle, &efi_net_guid,
r = efi_add_protocol(&netobj->header, &efi_net_guid,
&netobj->net);
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
r = efi_add_protocol(netobj->parent.handle, &efi_guid_device_path,
r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
efi_dp_from_eth());
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
r = efi_add_protocol(netobj->parent.handle, &efi_pxe_guid,
r = efi_add_protocol(&netobj->header, &efi_pxe_guid,
&netobj->pxe);
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
@ -385,13 +668,13 @@ efi_status_t efi_net_register(void)
* iPXE is running at TPL_CALLBACK most of the time. Use a higher TPL.
*/
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
efi_network_timer_notify, NULL, NULL,
efi_network_timer_notify, &netobj->net, NULL,
&network_timer_event);
if (r != EFI_SUCCESS) {
printf("ERROR: Failed to register network event\n");
return r;
}
/* Network is time critical, create event in every timer cyle */
/* Network is time critical, create event in every timer cycle */
r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
if (r != EFI_SUCCESS) {
printf("ERROR: Failed to set network timer\n");
@ -402,4 +685,9 @@ efi_status_t efi_net_register(void)
failure_to_add_protocol:
printf("ERROR: Failure to add protocol\n");
return r;
out_of_resources:
free(netobj);
/* free(transmit_buffer) not needed yet */
printf("ERROR: Out of memory\n");
return EFI_OUT_OF_RESOURCES;
}

View file

@ -141,7 +141,9 @@ static void EFIAPI efi_reset_system_boottime(
do_reset(NULL, 0, 0, NULL);
break;
case EFI_RESET_SHUTDOWN:
/* We don't have anything to map this to */
#ifdef CONFIG_CMD_POWEROFF
do_poweroff(NULL, 0, 0, NULL);
#endif
break;
}
@ -282,7 +284,7 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
}, {
/* invalidate_*cache_all are gone */
.ptr = &efi_runtime_services.set_virtual_address_map,
.patchto = &efi_invalid_parameter,
.patchto = &efi_unimplemented,
}, {
/* RTC accessors are gone */
.ptr = &efi_runtime_services.get_time,
@ -378,6 +380,9 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
ulong symidx = rel->info >> SYM_INDEX;
extern struct dyn_sym __dyn_sym_start[];
newaddr = __dyn_sym_start[symidx].addr + offset;
#ifdef IS_RELA
newaddr -= CONFIG_SYS_TEXT_BASE;
#endif
break;
}
#endif
@ -623,8 +628,8 @@ efi_status_t __efi_runtime EFIAPI efi_update_capsule(
efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
u64 maximum_capsule_size,
u32 reset_type)
u64 *maximum_capsule_size,
u32 *reset_type)
{
return EFI_UNSUPPORTED;
}

View file

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

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 smbios_guid = SMBIOS_TABLE_GUID;
/**
* hw_memcmp() - compare memory areas
*
* @buf1: pointer to first area
* @buf2: pointer to second area
* @length: number of bytes to compare
* Return: 0 if both memory areas are the same, otherwise the sign of the
* result value is the same as the sign of ghe difference between
* the first differing pair of bytes taken as u8.
*/
static int hw_memcmp(const void *buf1, const void *buf2, size_t length)
{
const u8 *pos1 = buf1;
@ -31,12 +41,12 @@ static int hw_memcmp(const void *buf1, const void *buf2, size_t length)
return 0;
}
/*
* Entry point of the EFI application.
/**
* efi_main() - entry point of the EFI application.
*
* @handle handle of the loaded image
* @systable system table
* @return status code
* @handle: handle of the loaded image
* @systable: system table
* @return: status code
*/
efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
@ -48,7 +58,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
efi_uintn_t i;
u16 rev[] = L"0.0.0";
con_out->output_string(con_out, L"Hello, world!\n");
/* UEFI requires CR LF */
con_out->output_string(con_out, L"Hello, world!\r\n");
/* Print the revision number */
rev[0] = (systable->hdr.revision >> 16) + '0';
@ -65,27 +76,30 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
con_out->output_string(con_out, L"Running on UEFI ");
con_out->output_string(con_out, rev);
con_out->output_string(con_out, L"\n");
con_out->output_string(con_out, L"\r\n");
/* Get the loaded image protocol */
ret = boottime->handle_protocol(handle, &loaded_image_guid,
(void **)&loaded_image);
if (ret != EFI_SUCCESS) {
con_out->output_string(con_out,
L"Cannot open loaded image protocol\n");
con_out->output_string
(con_out, L"Cannot open loaded image protocol\r\n");
goto out;
}
/* Find configuration tables */
for (i = 0; i < systable->nr_tables; ++i) {
if (!hw_memcmp(&systable->tables[i].guid, &fdt_guid,
sizeof(efi_guid_t)))
con_out->output_string(con_out, L"Have device tree\n");
con_out->output_string
(con_out, L"Have device tree\r\n");
if (!hw_memcmp(&systable->tables[i].guid, &acpi_guid,
sizeof(efi_guid_t)))
con_out->output_string(con_out, L"Have ACPI 2.0 table\n");
con_out->output_string
(con_out, L"Have ACPI 2.0 table\r\n");
if (!hw_memcmp(&systable->tables[i].guid, &smbios_guid,
sizeof(efi_guid_t)))
con_out->output_string(con_out, L"Have SMBIOS table\n");
con_out->output_string
(con_out, L"Have SMBIOS table\r\n");
}
/* Output the load options */
con_out->output_string(con_out, L"Load options: ");
@ -94,7 +108,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
(u16 *)loaded_image->load_options);
else
con_out->output_string(con_out, L"<none>");
con_out->output_string(con_out, L"\n");
con_out->output_string(con_out, L"\r\n");
out:
boottime->exit(handle, ret, 0, NULL);

View file

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

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

View file

@ -18,6 +18,7 @@ static const struct efi_boot_services *boottime;
static const struct efi_runtime_services *runtime;
static efi_handle_t handle;
static u16 reset_message[] = L"Selftest completed";
static int *setup_status;
/*
* Exit the boot services.
@ -74,20 +75,20 @@ void efi_st_exit_boot_services(void)
*/
static int setup(struct efi_unit_test *test, unsigned int *failures)
{
if (!test->setup) {
test->setup_ok = EFI_ST_SUCCESS;
int ret;
if (!test->setup)
return EFI_ST_SUCCESS;
}
efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name);
test->setup_ok = test->setup(handle, systable);
if (test->setup_ok != EFI_ST_SUCCESS) {
ret = test->setup(handle, systable);
if (ret != EFI_ST_SUCCESS) {
efi_st_error("Setting up '%s' failed\n", test->name);
++*failures;
} else {
efi_st_printc(EFI_LIGHTGREEN,
"Setting up '%s' succeeded\n", test->name);
}
return test->setup_ok;
return ret;
}
/*
@ -186,18 +187,20 @@ static void list_all_tests(void)
void efi_st_do_tests(const u16 *testname, unsigned int phase,
unsigned int steps, unsigned int *failures)
{
int i = 0;
struct efi_unit_test *test;
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
test < ll_entry_end(struct efi_unit_test, efi_unit_test);
++test, ++i) {
if (testname ?
efi_st_strcmp_16_8(testname, test->name) : test->on_request)
continue;
if (test->phase != phase)
continue;
if (steps & EFI_ST_SETUP)
setup(test, failures);
if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS)
setup_status[i] = setup(test, failures);
if (steps & EFI_ST_EXECUTE && setup_status[i] == EFI_ST_SUCCESS)
execute(test, failures);
if (steps & EFI_ST_TEARDOWN)
teardown(test, failures);
@ -271,6 +274,16 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
ll_entry_count(struct efi_unit_test,
efi_unit_test));
/* Allocate buffer for setup results */
ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) *
ll_entry_count(struct efi_unit_test,
efi_unit_test),
(void **)&setup_status);
if (ret != EFI_SUCCESS) {
efi_st_error("Allocate pool failed\n");
return ret;
}
/* Execute boottime tests */
efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,

View file

@ -18,7 +18,7 @@ static efi_guid_t table_guid =
0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75);
/*
* Notification function, increments the notfication count if parameter
* Notification function, increments the notification count if parameter
* context is provided.
*
* @event notified event
@ -33,23 +33,23 @@ static void EFIAPI notify(struct efi_event *event, void *context)
}
/*
* Check crc32 of a table.
* Check CRC32 of a table.
*/
static int check_table(const void *table)
{
efi_status_t ret;
u32 crc32, res;
/* Casting from const to not const */
/* Casting from constant to not constant */
struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
crc32 = hdr->crc32;
/*
* Setting the crc32 of the 'const' table to zero is easier than
* Setting the CRC32 of the 'const' table to zero is easier than
* copying
*/
hdr->crc32 = 0;
ret = boottime->calculate_crc32(table, hdr->headersize, &res);
/* Reset table crc32 so it stays constant */
/* Reset table CRC32 so it stays constant */
hdr->crc32 = crc32;
if (ret != EFI_ST_SUCCESS) {
efi_st_error("CalculateCrc32 failed\n");
@ -203,7 +203,7 @@ static int execute(void)
return EFI_ST_FAILURE;
}
if (tabcnt > 1) {
efi_st_error("Duplicate table guid\n");
efi_st_error("Duplicate table GUID\n");
return EFI_ST_FAILURE;
}
if (table != &tables[1]) {

View file

@ -33,7 +33,7 @@ static efi_handle_t handle_driver;
* Count child controllers
*
* @handle handle on which child controllers are installed
* @protocol protocol for which the child controlles where installed
* @protocol protocol for which the child controllers were installed
* @count number of child controllers
* @return status code
*/

View file

@ -5,7 +5,7 @@
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* This unit test checks the CalculateCrc32 bootservice and checks the
* headers of the system table, the boot services tablle, and the runtime
* headers of the system table, the boot services table, and the runtime
* services table before and after ExitBootServices().
*/
@ -19,7 +19,7 @@ static int check_table(const void *table)
{
efi_status_t ret;
u32 crc32, res;
/* Casting from const to not const */
/* Casting from constant to not constant */
struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
if (!hdr->signature) {

View file

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

View file

@ -19,7 +19,7 @@ static efi_guid_t event_group =
0x0e, 0x5b, 0x45, 0xc0, 0x56, 0x91);
/*
* Notification function, increments the notfication count if parameter
* Notification function, increments the notification count if parameter
* context is provided.
*
* @event notified event
@ -114,7 +114,7 @@ static int execute(void)
(unsigned int)i, (unsigned int)j,
(unsigned int)counter[j]);
efi_st_error(
"Nofification function not called\n");
"Notification function not called\n");
return EFI_ST_FAILURE;
}
}

View file

@ -17,7 +17,7 @@ static unsigned int timer_ticks;
static struct efi_boot_services *boottime;
/*
* Notification function, increments the notfication count if parameter
* Notification function, increments the notification count if parameter
* context is provided.
*
* @event notified event

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 const char *fdt;
/* This should be sufficent for */
/* This should be sufficient for */
#define BUFFERSIZE 0x100000
static efi_guid_t fdt_guid = EFI_FDT_GUID;

View file

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

View file

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

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 = {};
/*
* Fill ethernet header
* Fill Ethernet header
*/
boottime->copy_mem(p.eth_hdr.et_dest, (void *)BROADCAST_MAC, ARP_HLEN);
boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address,
@ -228,6 +228,14 @@ static int setup(const efi_handle_t handle,
efi_st_error("WaitForPacket event missing\n");
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.
*/
@ -236,14 +244,6 @@ static int setup(const efi_handle_t handle,
efi_st_error("Failed to initialize network adapter\n");
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;
}

View file

@ -5,7 +5,7 @@
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
* The unicode character and the scan code are printed for text
* The Unicode character and the scan code are printed for text
* input. To run the test:
*
* setenv efi_selftest text input

View file

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

View file

@ -52,7 +52,7 @@ static int test_stri_coll(void)
c1, c2);
if (ret) {
efi_st_error(
"stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c2, ret);
"stri_coll(\"%ps\", \"%ps\") = %d\n", c1, c2, (int)ret);
return EFI_ST_FAILURE;
}
@ -60,7 +60,7 @@ static int test_stri_coll(void)
c1, c3);
if (ret >= 0) {
efi_st_error(
"stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c3, ret);
"stri_coll(\"%ps\", \"%ps\") = %d\n", c1, c3, (int)ret);
return EFI_ST_FAILURE;
}
@ -68,7 +68,7 @@ static int test_stri_coll(void)
c3, c1);
if (ret <= 0) {
efi_st_error(
"stri_coll(\"%ps\", \"%ps\") = %zu\n", c3, c1, ret);
"stri_coll(\"%ps\", \"%ps\") = %d\n", c3, c1, (int)ret);
return EFI_ST_FAILURE;
}

View file

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

View file

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

View file

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

View file

@ -6,6 +6,7 @@
*/
#include <common.h>
#include <mapmem.h>
#include <smbios.h>
#include <tables_csum.h>
#include <version.h>
@ -72,9 +73,10 @@ static int smbios_string_table_len(char *start)
static int smbios_write_type0(ulong *current, int handle)
{
struct smbios_type0 *t = (struct smbios_type0 *)*current;
struct smbios_type0 *t;
int len = sizeof(struct smbios_type0);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type0));
fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle);
t->vendor = smbios_add_string(t->eos, "U-Boot");
@ -101,16 +103,18 @@ static int smbios_write_type0(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
unmap_sysmem(t);
return len;
}
static int smbios_write_type1(ulong *current, int handle)
{
struct smbios_type1 *t = (struct smbios_type1 *)*current;
struct smbios_type1 *t;
int len = sizeof(struct smbios_type1);
char *serial_str = env_get("serial#");
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type1));
fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
@ -122,15 +126,17 @@ static int smbios_write_type1(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
unmap_sysmem(t);
return len;
}
static int smbios_write_type2(ulong *current, int handle)
{
struct smbios_type2 *t = (struct smbios_type2 *)*current;
struct smbios_type2 *t;
int len = sizeof(struct smbios_type2);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type2));
fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
@ -140,15 +146,17 @@ static int smbios_write_type2(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
unmap_sysmem(t);
return len;
}
static int smbios_write_type3(ulong *current, int handle)
{
struct smbios_type3 *t = (struct smbios_type3 *)*current;
struct smbios_type3 *t;
int len = sizeof(struct smbios_type3);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type3));
fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle);
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
@ -160,6 +168,7 @@ static int smbios_write_type3(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
unmap_sysmem(t);
return len;
}
@ -198,9 +207,10 @@ static void smbios_write_type4_dm(struct smbios_type4 *t)
static int smbios_write_type4(ulong *current, int handle)
{
struct smbios_type4 *t = (struct smbios_type4 *)*current;
struct smbios_type4 *t;
int len = sizeof(struct smbios_type4);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type4));
fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle);
t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL;
@ -214,32 +224,37 @@ static int smbios_write_type4(ulong *current, int handle)
len = t->length + smbios_string_table_len(t->eos);
*current += len;
unmap_sysmem(t);
return len;
}
static int smbios_write_type32(ulong *current, int handle)
{
struct smbios_type32 *t = (struct smbios_type32 *)*current;
struct smbios_type32 *t;
int len = sizeof(struct smbios_type32);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type32));
fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle);
*current += len;
unmap_sysmem(t);
return len;
}
static int smbios_write_type127(ulong *current, int handle)
{
struct smbios_type127 *t = (struct smbios_type127 *)*current;
struct smbios_type127 *t;
int len = sizeof(struct smbios_type127);
t = map_sysmem(*current, len);
memset(t, 0, sizeof(struct smbios_type127));
fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle);
*current += len;
unmap_sysmem(t);
return len;
}
@ -257,6 +272,7 @@ static smbios_write_type smbios_write_funcs[] = {
ulong write_smbios_table(ulong addr)
{
struct smbios_entry *se;
ulong table_addr;
ulong tables;
int len = 0;
int max_struct_size = 0;
@ -268,7 +284,7 @@ ulong write_smbios_table(ulong addr)
/* 16 byte align the table address */
addr = ALIGN(addr, 16);
se = (struct smbios_entry *)(uintptr_t)addr;
se = map_sysmem(addr, sizeof(struct smbios_entry));
memset(se, 0, sizeof(struct smbios_entry));
addr += sizeof(struct smbios_entry);
@ -290,7 +306,24 @@ ulong write_smbios_table(ulong addr)
se->max_struct_size = max_struct_size;
memcpy(se->intermediate_anchor, "_DMI_", 5);
se->struct_table_length = len;
se->struct_table_address = tables;
/*
* We must use a pointer here so things work correctly on sandbox. The
* user of this table is not aware of the mapping of addresses to
* sandbox's DRAM buffer.
*/
table_addr = (ulong)map_sysmem(tables, 0);
if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) {
/*
* We need to put this >32-bit pointer into the table but the
* field is only 32 bits wide.
*/
printf("WARNING: SMBIOS table_address overflow %llx\n",
(unsigned long long)table_addr);
table_addr = 0;
}
se->struct_table_address = table_addr;
se->struct_count = handle;
/* calculate checksums */
@ -298,6 +331,7 @@ ulong write_smbios_table(ulong addr)
isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET;
se->intermediate_checksum = table_compute_checksum(istart, isize);
se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry));
unmap_sysmem(se);
return addr;
}

View file

@ -381,7 +381,7 @@ $(obj)/%.efi: $(obj)/%_efi.so
quiet_cmd_efi_ld = LD $@
cmd_efi_ld = $(LD) -nostdlib -znocombreloc -T $(EFI_LDS_PATH) -shared \
-Bsymbolic $^ -o $@
-Bsymbolic -s $^ -o $@
EFI_LDS_PATH = $(srctree)/arch/$(ARCH)/lib/$(EFI_LDS)

View file

@ -8,12 +8,14 @@ import u_boot_utils
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
def test_efi_selftest(u_boot_console):
"""
Run bootefi selftest
"""
"""Test the UEFI implementation
:param u_boot_console: U-Boot console
This function executes all selftests that are not marked as on request.
"""
u_boot_console.run_command(cmd='setenv efi_selftest')
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0:
raise Exception('Failures occurred during the EFI selftest')