mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
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:
commit
f388e3bed7
65 changed files with 1558 additions and 591 deletions
1
Kconfig
1
Kconfig
|
@ -86,6 +86,7 @@ config DISTRO_DEFAULTS
|
|||
select SUPPORT_RAW_INITRD
|
||||
select SYS_LONGHELP
|
||||
imply CMD_MII if NET
|
||||
imply USB_STORAGE
|
||||
imply USE_BOOTCOMMAND
|
||||
help
|
||||
Select this to enable various options and commands which are suitable
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 && \
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
244
cmd/bootefi.c
244
cmd/bootefi.c
|
@ -148,16 +148,16 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info,
|
|||
/**
|
||||
* copy_fdt() - Copy the device tree to a new location available to EFI
|
||||
*
|
||||
* The FDT is relocated into a suitable location within the EFI memory map.
|
||||
* An additional 12KB is added to the space in case the device tree needs to be
|
||||
* The FDT is copied to a suitable location within the EFI memory map.
|
||||
* Additional 12 KiB are added to the space in case the device tree needs to be
|
||||
* expanded later with fdt_open_into().
|
||||
*
|
||||
* @fdt_addr: On entry, address of start of FDT. On exit, address of relocated
|
||||
* FDT start
|
||||
* @fdt_sizep: Returns new size of FDT, including
|
||||
* @return new relocated address of FDT
|
||||
* @fdtp: On entry a pointer to the flattened device tree.
|
||||
* On exit a pointer to the copy of the flattened device tree.
|
||||
* FDT start
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
|
||||
static efi_status_t copy_fdt(void **fdtp)
|
||||
{
|
||||
unsigned long fdt_ram_start = -1L, fdt_pages;
|
||||
efi_status_t ret = 0;
|
||||
|
@ -178,17 +178,19 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
|
|||
}
|
||||
|
||||
/*
|
||||
* Give us at least 4KB of breathing room in case the device tree needs
|
||||
* to be expanded later. Round up to the nearest EFI page boundary.
|
||||
* Give us at least 12 KiB of breathing room in case the device tree
|
||||
* needs to be expanded later.
|
||||
*/
|
||||
fdt = map_sysmem(*fdt_addrp, 0);
|
||||
fdt_size = fdt_totalsize(fdt);
|
||||
fdt_size += 4096 * 3;
|
||||
fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE);
|
||||
fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
1
fs/fs.c
1
fs/fs.c
|
@ -365,6 +365,7 @@ int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
|
|||
for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
|
||||
if (!info->probe(fs_dev_desc, &fs_partition)) {
|
||||
fs_type = info->fstype;
|
||||
fs_dev_part = part;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
50
lib/efi_selftest/efi_selftest_exception.c
Normal file
50
lib/efi_selftest/efi_selftest_exception.c
Normal 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,
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
187
lib/efi_selftest/efi_selftest_memory.c
Normal file
187
lib/efi_selftest/efi_selftest_memory.c
Normal 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,
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
52
lib/smbios.c
52
lib/smbios.c
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mapmem.h>
|
||||
#include <smbios.h>
|
||||
#include <tables_csum.h>
|
||||
#include <version.h>
|
||||
|
@ -72,9 +73,10 @@ static int smbios_string_table_len(char *start)
|
|||
|
||||
static int smbios_write_type0(ulong *current, int handle)
|
||||
{
|
||||
struct smbios_type0 *t = (struct smbios_type0 *)*current;
|
||||
struct smbios_type0 *t;
|
||||
int len = sizeof(struct smbios_type0);
|
||||
|
||||
t = map_sysmem(*current, len);
|
||||
memset(t, 0, sizeof(struct smbios_type0));
|
||||
fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle);
|
||||
t->vendor = smbios_add_string(t->eos, "U-Boot");
|
||||
|
@ -101,16 +103,18 @@ static int smbios_write_type0(ulong *current, int handle)
|
|||
|
||||
len = t->length + smbios_string_table_len(t->eos);
|
||||
*current += len;
|
||||
unmap_sysmem(t);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int smbios_write_type1(ulong *current, int handle)
|
||||
{
|
||||
struct smbios_type1 *t = (struct smbios_type1 *)*current;
|
||||
struct smbios_type1 *t;
|
||||
int len = sizeof(struct smbios_type1);
|
||||
char *serial_str = env_get("serial#");
|
||||
|
||||
t = map_sysmem(*current, len);
|
||||
memset(t, 0, sizeof(struct smbios_type1));
|
||||
fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
|
||||
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
|
||||
|
@ -122,15 +126,17 @@ static int smbios_write_type1(ulong *current, int handle)
|
|||
|
||||
len = t->length + smbios_string_table_len(t->eos);
|
||||
*current += len;
|
||||
unmap_sysmem(t);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int smbios_write_type2(ulong *current, int handle)
|
||||
{
|
||||
struct smbios_type2 *t = (struct smbios_type2 *)*current;
|
||||
struct smbios_type2 *t;
|
||||
int len = sizeof(struct smbios_type2);
|
||||
|
||||
t = map_sysmem(*current, len);
|
||||
memset(t, 0, sizeof(struct smbios_type2));
|
||||
fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle);
|
||||
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
|
||||
|
@ -140,15 +146,17 @@ static int smbios_write_type2(ulong *current, int handle)
|
|||
|
||||
len = t->length + smbios_string_table_len(t->eos);
|
||||
*current += len;
|
||||
unmap_sysmem(t);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int smbios_write_type3(ulong *current, int handle)
|
||||
{
|
||||
struct smbios_type3 *t = (struct smbios_type3 *)*current;
|
||||
struct smbios_type3 *t;
|
||||
int len = sizeof(struct smbios_type3);
|
||||
|
||||
t = map_sysmem(*current, len);
|
||||
memset(t, 0, sizeof(struct smbios_type3));
|
||||
fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle);
|
||||
t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER);
|
||||
|
@ -160,6 +168,7 @@ static int smbios_write_type3(ulong *current, int handle)
|
|||
|
||||
len = t->length + smbios_string_table_len(t->eos);
|
||||
*current += len;
|
||||
unmap_sysmem(t);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -198,9 +207,10 @@ static void smbios_write_type4_dm(struct smbios_type4 *t)
|
|||
|
||||
static int smbios_write_type4(ulong *current, int handle)
|
||||
{
|
||||
struct smbios_type4 *t = (struct smbios_type4 *)*current;
|
||||
struct smbios_type4 *t;
|
||||
int len = sizeof(struct smbios_type4);
|
||||
|
||||
t = map_sysmem(*current, len);
|
||||
memset(t, 0, sizeof(struct smbios_type4));
|
||||
fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle);
|
||||
t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL;
|
||||
|
@ -214,32 +224,37 @@ static int smbios_write_type4(ulong *current, int handle)
|
|||
|
||||
len = t->length + smbios_string_table_len(t->eos);
|
||||
*current += len;
|
||||
unmap_sysmem(t);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int smbios_write_type32(ulong *current, int handle)
|
||||
{
|
||||
struct smbios_type32 *t = (struct smbios_type32 *)*current;
|
||||
struct smbios_type32 *t;
|
||||
int len = sizeof(struct smbios_type32);
|
||||
|
||||
t = map_sysmem(*current, len);
|
||||
memset(t, 0, sizeof(struct smbios_type32));
|
||||
fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle);
|
||||
|
||||
*current += len;
|
||||
unmap_sysmem(t);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int smbios_write_type127(ulong *current, int handle)
|
||||
{
|
||||
struct smbios_type127 *t = (struct smbios_type127 *)*current;
|
||||
struct smbios_type127 *t;
|
||||
int len = sizeof(struct smbios_type127);
|
||||
|
||||
t = map_sysmem(*current, len);
|
||||
memset(t, 0, sizeof(struct smbios_type127));
|
||||
fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle);
|
||||
|
||||
*current += len;
|
||||
unmap_sysmem(t);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -257,6 +272,7 @@ static smbios_write_type smbios_write_funcs[] = {
|
|||
ulong write_smbios_table(ulong addr)
|
||||
{
|
||||
struct smbios_entry *se;
|
||||
ulong table_addr;
|
||||
ulong tables;
|
||||
int len = 0;
|
||||
int max_struct_size = 0;
|
||||
|
@ -268,7 +284,7 @@ ulong write_smbios_table(ulong addr)
|
|||
/* 16 byte align the table address */
|
||||
addr = ALIGN(addr, 16);
|
||||
|
||||
se = (struct smbios_entry *)(uintptr_t)addr;
|
||||
se = map_sysmem(addr, sizeof(struct smbios_entry));
|
||||
memset(se, 0, sizeof(struct smbios_entry));
|
||||
|
||||
addr += sizeof(struct smbios_entry);
|
||||
|
@ -290,7 +306,24 @@ ulong write_smbios_table(ulong addr)
|
|||
se->max_struct_size = max_struct_size;
|
||||
memcpy(se->intermediate_anchor, "_DMI_", 5);
|
||||
se->struct_table_length = len;
|
||||
se->struct_table_address = tables;
|
||||
|
||||
/*
|
||||
* We must use a pointer here so things work correctly on sandbox. The
|
||||
* user of this table is not aware of the mapping of addresses to
|
||||
* sandbox's DRAM buffer.
|
||||
*/
|
||||
table_addr = (ulong)map_sysmem(tables, 0);
|
||||
if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) {
|
||||
/*
|
||||
* We need to put this >32-bit pointer into the table but the
|
||||
* field is only 32 bits wide.
|
||||
*/
|
||||
printf("WARNING: SMBIOS table_address overflow %llx\n",
|
||||
(unsigned long long)table_addr);
|
||||
table_addr = 0;
|
||||
}
|
||||
se->struct_table_address = table_addr;
|
||||
|
||||
se->struct_count = handle;
|
||||
|
||||
/* calculate checksums */
|
||||
|
@ -298,6 +331,7 @@ ulong write_smbios_table(ulong addr)
|
|||
isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET;
|
||||
se->intermediate_checksum = table_compute_checksum(istart, isize);
|
||||
se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry));
|
||||
unmap_sysmem(se);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in a new issue