Pull request for UEFI sub-system for v2019.10-rc1 (2)

* Implement the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
 * Address errors of type -Werror=address-of-packed-member when building
   with GCC9.1
 * Fix an error when adding memory add addres 0x00000000.
 * Rework some code comments for Sphinx compliance.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAl0vSQEACgkQxIHbvCwF
 GsQfxQ//d/i5Ix7V5rtm9U1ew2lkaQw5O1/E//Ta//0AeWLaEnFf0ln1Fx5jLF6E
 f70uE6iDRgnxfZWD/rnCqv7HZrokpy3GuXnUfAZTgEvsngqicw8dAAU9Ql9Q62i9
 N302GhaCGkbBp3MBOLRBXJmKuTnnzfU7jkeYo1tZbZe3AoqSNtI8ND86DHSotuUM
 9Ck5367LdcG5O86N8gIxBtCcnthq94GgS/tY69iuPhhKqN3oV6MbzjqmI4wtkVH6
 RhJSQspTsmyKTSivbcgpgIPXJJnTwh0nZcQWmzC81ehU3LF9i1M1J4SAqsZ7kpgt
 jWY959iXnd7iNfwFiCTLpf+mDrviyPzntt/aE8ras5IwbQdiwZONeQ/mhkP2Snoo
 RDX+dB3JqpyO/T+4uMdq+2saYBtKZ9CUKclqqh/xwvv5Bs63qHGC3KKYnjQx1sKA
 k5QD3XSOPDLYbqQBIcgiB9T5TWkO1igJVEWRxPtExl31DTkSXy6f7G1F7sZ+Ey+5
 gugIhNeTCme4a9bSIc7FjFaZSvPR2SNd8azUkSfso6Vqd9bNRShBF7pImlrCRmj8
 Xc0sknW824LOdeM6ZC54J7lYKyLfL3HljzYSiM7KExt21mAjNHWXt312hINr6SOA
 gz+/Osdyrv8GniP86Zw3kACto6Chaw51PEV1WReYPT3LNwinvoU=
 =aj4j
 -----END PGP SIGNATURE-----

Merge tag 'efi-2019-10-rc1-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for v2019.10-rc1 (2)

* Implement the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
* Address errors of type -Werror=address-of-packed-member when building
  with GCC9.1
* Fix an error when adding memory add addres 0x00000000.
* Rework some code comments for Sphinx compliance.
This commit is contained in:
Tom Rini 2019-07-23 22:29:53 -04:00
commit fe4243870d
24 changed files with 563 additions and 159 deletions

View File

@ -17,14 +17,13 @@
*/
.globl ImageBase
ImageBase:
.ascii "MZ"
.short IMAGE_DOS_SIGNATURE /* 'MZ' */
.skip 58 /* 'MZ' + pad + offset == 64 */
.long pe_header - ImageBase /* Offset to the PE header */
pe_header:
.ascii "PE"
.short 0
.long IMAGE_NT_SIGNATURE /* 'PE' */
coff_header:
.short 0xaa64 /* AArch64 */
.short IMAGE_FILE_MACHINE_ARM64 /* AArch64 */
.short 2 /* nr_sections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
@ -36,7 +35,7 @@ coff_header:
IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
.short 0x20b /* PE32+ format */
.short IMAGE_NT_OPTIONAL_HDR64_MAGIC /* PE32+ format */
.byte 0x02 /* MajorLinkerVersion */
.byte 0x14 /* MinorLinkerVersion */
.long _edata - _start /* SizeOfCode */

View File

@ -16,14 +16,13 @@
*/
.globl image_base
image_base:
.ascii "MZ"
.short IMAGE_DOS_SIGNATURE /* 'MZ' */
.skip 58 /* 'MZ' + pad + offset == 64 */
.long pe_header - image_base /* Offset to the PE header */
pe_header:
.ascii "PE"
.short 0
.long IMAGE_NT_SIGNATURE /* 'PE' */
coff_header:
.short 0x1c2 /* Mixed ARM/Thumb */
.short IMAGE_FILE_MACHINE_THUMB /* Mixed ARM/Thumb */
.short 2 /* nr_sections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
@ -36,7 +35,7 @@ coff_header:
IMAGE_FILE_32BIT_MACHINE | \
IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
.short 0x10b /* PE32 format */
.short IMAGE_NT_OPTIONAL_HDR32_MAGIC /* PE32 format */
.byte 0x02 /* MajorLinkerVersion */
.byte 0x14 /* MinorLinkerVersion */
.long _edata - _start /* SizeOfCode */

View File

@ -14,12 +14,12 @@
#define SIZE_LONG 8
#define SAVE_LONG(reg, idx) sd reg, (idx*SIZE_LONG)(sp)
#define LOAD_LONG(reg, idx) ld reg, (idx*SIZE_LONG)(sp)
#define PE_MACHINE 0x5064
#define PE_MACHINE IMAGE_FILE_MACHINE_RISCV64
#else
#define SIZE_LONG 4
#define SAVE_LONG(reg, idx) sw reg, (idx*SIZE_LONG)(sp)
#define LOAD_LONG(reg, idx) lw reg, (idx*SIZE_LONG)(sp)
#define PE_MACHINE 0x5032
#define PE_MACHINE IMAGE_FILE_MACHINE_RISCV32
#endif
@ -30,12 +30,11 @@
*/
.globl ImageBase
ImageBase:
.ascii "MZ"
.short IMAGE_DOS_SIGNATURE /* 'MZ' */
.skip 58 /* 'MZ' + pad + offset == 64 */
.long pe_header - ImageBase /* Offset to the PE header */
pe_header:
.ascii "PE"
.short 0
.long IMAGE_NT_SIGNATURE /* 'PE' */
coff_header:
.short PE_MACHINE /* RISC-V 64/32-bit */
.short 2 /* nr_sections */
@ -49,7 +48,7 @@ coff_header:
IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
IMAGE_FILE_DEBUG_STRIPPED)
optional_header:
.short 0x20b /* PE32+ format */
.short IMAGE_NT_OPTIONAL_HDR64_MAGIC /* PE32+ format */
.byte 0x02 /* MajorLinkerVersion */
.byte 0x14 /* MinorLinkerVersion */
.long _edata - _start /* SizeOfCode */

View File

@ -24,7 +24,7 @@ DECLARE_GLOBAL_DATA_PTR;
static struct efi_device_path *bootefi_image_path;
static struct efi_device_path *bootefi_device_path;
/*
/**
* Set the load options of an image from an environment variable.
*
* @handle: the image handle
@ -143,7 +143,7 @@ done:
return ret;
}
/*
/**
* efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
*
* The mem_rsv entries of the FDT are added to the memory map. Any failures are
@ -169,8 +169,8 @@ static void efi_carve_out_dt_rsv(void *fdt)
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))
if (efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
false) != EFI_SUCCESS)
printf("FDT memrsv map %d: Failed to add to map\n", i);
}
}
@ -342,7 +342,7 @@ static int do_efibootmgr(void)
return CMD_RET_SUCCESS;
}
/*
/**
* do_bootefi_image() - execute EFI binary
*
* Set up memory image for the binary to be loaded, prepare device path, and
@ -612,6 +612,16 @@ U_BOOT_CMD(
bootefi_help_text
);
/**
* efi_set_bootdev() - set boot device
*
* This function is called when a file is loaded, e.g. via the 'load' command.
* We use the path to this file to inform the UEFI binary about the boot device.
*
* @dev: device, e.g. "MMC"
* @devnr: number of the device, e.g. "1:2"
* @path: path to file loaded
*/
void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
{
struct efi_device_path *device, *image;

View File

@ -394,6 +394,7 @@ static const struct efi_mem_attrs {
/**
* print_memory_attributes() - print memory map attributes
*
* @attributes: Attribute value
*
* Print memory map attributes
@ -487,9 +488,9 @@ static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
* Return: CMD_RET_SUCCESS on success,
* CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
*
* Implement efidebug "boot add" sub-command.
* Create or change UEFI load option.
* - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
* Implement efidebug "boot add" sub-command. Create or change UEFI load option.
*
* efidebug boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
*/
static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
@ -587,7 +588,8 @@ out:
*
* Implement efidebug "boot rm" sub-command.
* Delete UEFI load options.
* - boot rm <id> ...
*
* efidebug boot rm <id> ...
*/
static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
@ -890,7 +892,8 @@ out:
*
* Implement efidebug "boot next" sub-command.
* Set BootNext variable.
* - boot next <id>
*
* efidebug boot next <id>
*/
static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
@ -938,7 +941,8 @@ out:
*
* Implement efidebug "boot order" sub-command.
* Show order of UEFI load options, or change it in BootOrder variable.
* - boot order [<id> ...]
*
* efidebug boot order [<id> ...]
*/
static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])

View File

@ -670,9 +670,18 @@ err:
return ret;
}
static void gpt_convert_efi_name_to_char(char *s, efi_char16_t *es, int n)
/**
* gpt_convert_efi_name_to_char() - convert u16 string to char string
*
* TODO: this conversion only supports ANSI characters
*
* @s: target buffer
* @es: u16 string to be converted
* @n: size of target buffer
*/
static void gpt_convert_efi_name_to_char(char *s, void *es, int n)
{
char *ess = (char *)es;
char *ess = es;
int i, j;
memset(s, '\0', n);

View File

@ -1,7 +1,64 @@
.. SPDX-License-Identifier: GPL-2.0+
EFI subsystem
=============
UEFI subsystem
==============
Lauching UEFI images
--------------------
Bootefi command
~~~~~~~~~~~~~~~
The bootefi command is used to start UEFI applications or to install UEFI
drivers. It takes two parameters
bootefi <image address> [fdt address]
* image address - the memory address of the UEFI binary
* fdt address - the memory address of the flattened device tree
The environment variable 'bootargs' is passed as load options in the UEFI system
table. The Linux kernel EFI stub uses the load options as command line
arguments.
.. kernel-doc:: cmd/bootefi.c
:internal:
Boot manager
~~~~~~~~~~~~
The UEFI specification foresees to define boot entries and boot sequence via UEFI
variables. Booting according to these variables is possible via
bootefi bootmgr [fdt address]
* fdt address - the memory address of the flattened device tree
The relevant variables are:
* Boot0000-BootFFFF define boot entries
* BootNext specifies next boot option to be booted
* BootOrder specifies in which sequence the boot options shall be tried if
BootNext is not defined or booting via BootNext fails
.. kernel-doc:: lib/efi_loader/efi_bootmgr.c
:internal:
Efidebug command
~~~~~~~~~~~~~~~~
The efidebug command is used to set and display boot options as well as to
display information about internal data of the UEFI subsystem (devices,
drivers, handles, loaded images, and the memory map).
.. kernel-doc:: cmd/efidebug.c
:internal:
Initialization of the UEFI sub-system
-------------------------------------
.. kernel-doc:: lib/efi_loader/efi_setup.c
:internal:
Boot services
-------------
@ -15,8 +72,34 @@ Image relocation
.. kernel-doc:: lib/efi_loader/efi_image_loader.c
:internal:
Memory services
~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_loader/efi_memory.c
:internal:
Runtime services
----------------
.. kernel-doc:: lib/efi_loader/efi_runtime.c
:internal:
Variable services
~~~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_loader/efi_variable.c
:internal:
UEFI drivers
------------
UEFI driver uclass
~~~~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_driver/efi_uclass.c
:internal:
Block device driver
~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_driver/efi_block_device.c
:internal:

View File

@ -29,6 +29,22 @@
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
/* Machine types */
#define IMAGE_FILE_MACHINE_I386 0x014c
#define IMAGE_FILE_MACHINE_ARM 0x01c0
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#define IMAGE_FILE_MACHINE_ARM64 0xaa64
#define IMAGE_FILE_MACHINE_RISCV32 0x5032
#define IMAGE_FILE_MACHINE_RISCV64 0x5064
/* Header magic constants */
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b
#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
/* Subsystem type */
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11

View File

@ -178,7 +178,7 @@ s32 utf_to_upper(const s32 code);
* ReturnValue: number of non-zero words.
* This is not the number of utf-16 letters!
*/
size_t u16_strlen(const u16 *in);
size_t u16_strlen(const void *in);
/**
* u16_strlen - count non-zero words
@ -214,7 +214,7 @@ u16 *u16_strcpy(u16 *dest, const u16 *src);
* @src: source buffer (null terminated)
* Return: allocated new buffer on success, NULL on failure
*/
u16 *u16_strdup(const u16 *src);
u16 *u16_strdup(const void *src);
/**
* utf16_to_utf8() - Convert an utf16 string to utf8

View File

@ -476,8 +476,8 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
efi_uintn_t *descriptor_size,
uint32_t *descriptor_version);
/* Adds a range into the EFI memory map */
uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
bool overlap_only_ram);
efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
bool overlap_only_ram);
/* Called by board init to initialize the EFI drivers */
efi_status_t efi_driver_init(void);
/* Called by board init to initialize the EFI memory map */
@ -567,7 +567,7 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii)
*unicode = 0;
}
static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2)
static inline int guidcmp(const void *g1, const void *g2)
{
return memcmp(g1, g2, sizeof(efi_guid_t));
}

View File

@ -34,22 +34,6 @@ typedef struct _IMAGE_DOS_HEADER {
uint32_t e_lfanew; /* 3c: Offset to extended header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
#define IMAGE_FILE_MACHINE_I386 0x014c
#define IMAGE_FILE_MACHINE_ARM 0x01c0
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#define IMAGE_FILE_MACHINE_ARM64 0xaa64
#define IMAGE_FILE_MACHINE_RISCV32 0x5032
#define IMAGE_FILE_MACHINE_RISCV64 0x5064
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
typedef struct _IMAGE_FILE_HEADER {
uint16_t Machine;
uint16_t NumberOfSections;

View File

@ -335,11 +335,16 @@ s32 utf_to_upper(const s32 code)
return ret;
}
size_t u16_strlen(const u16 *in)
size_t u16_strlen(const void *in)
{
size_t i;
for (i = 0; in[i]; i++);
return i;
const char *pos = in;
size_t ret;
for (; pos[0] || pos[1]; pos += 2)
;
ret = pos - (char *)in;
ret >>= 1;
return ret;
}
size_t u16_strnlen(const u16 *in, size_t count)
@ -362,18 +367,18 @@ u16 *u16_strcpy(u16 *dest, const u16 *src)
return tmp;
}
u16 *u16_strdup(const u16 *src)
u16 *u16_strdup(const void *src)
{
u16 *new;
size_t len;
if (!src)
return NULL;
new = malloc((u16_strlen(src) + 1) * sizeof(u16));
len = (u16_strlen(src) + 1) * sizeof(u16);
new = malloc(len);
if (!new)
return NULL;
u16_strcpy(new, src);
memcpy(new, src, len);
return new;
}

View File

@ -43,14 +43,14 @@ struct efi_blk_platdata {
struct efi_block_io *io;
};
/*
/**
* Read from block device
*
* @dev device
* @blknr first block to be read
* @blkcnt number of blocks to read
* @buffer output buffer
* @return number of blocks transferred
* @dev: device
* @blknr: first block to be read
* @blkcnt: number of blocks to read
* @buffer: output buffer
* Return: number of blocks transferred
*/
static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
@ -72,14 +72,14 @@ static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
return blkcnt;
}
/*
/**
* Write to block device
*
* @dev device
* @blknr first block to be write
* @blkcnt number of blocks to write
* @buffer input buffer
* @return number of blocks transferred
* @dev: device
* @blknr: first block to be write
* @blkcnt: number of blocks to write
* @buffer: input buffer
* Return: number of blocks transferred
*/
static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
@ -102,11 +102,12 @@ static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
return blkcnt;
}
/*
/**
* Create partions for the block device.
*
* @handle EFI handle of the block device
* @dev udevice of the block device
* @handle: EFI handle of the block device
* @dev: udevice of the block device
* Return: number of partitions created
*/
static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
{
@ -120,12 +121,12 @@ static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
desc->devnum, dev->name);
}
/*
/**
* Create a block device for a handle
*
* @handle handle
* @interface block io protocol
* @return 0 = success
* @handle: handle
* @interface: block io protocol
* Return: 0 = success
*/
static int efi_bl_bind(efi_handle_t handle, void *interface)
{

View File

@ -27,7 +27,15 @@ static const struct efi_runtime_services *rs;
*/
/* Parse serialized data and transform it into efi_load_option structure */
/**
* efi_deserialize_load_option() - parse serialized data
*
* Parse serialized data describing a load option and transform it to the
* efi_load_option structure.
*
* @lo: pointer to target
* @data: serialized data
*/
void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data)
{
lo->attributes = get_unaligned_le32(data);
@ -47,9 +55,14 @@ void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data)
lo->optional_data = data;
}
/*
/**
* efi_serialize_load_option() - serialize load option
*
* Serialize efi_load_option structure into byte stream for BootXXXX.
* Return a size of allocated data.
*
* @data: buffer for serialized data
* @lo: load option
* Return: size of allocated buffer
*/
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
{
@ -92,7 +105,16 @@ unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
return size;
}
/* free() the result */
/**
* get_var() - get UEFI variable
*
* It is the caller's duty to free the returned buffer.
*
* @name: name of variable
* @vendor: vendor GUID of variable
* @size: size of allocated buffer
* Return: buffer with variable data or NULL
*/
static void *get_var(u16 *name, const efi_guid_t *vendor,
efi_uintn_t *size)
{
@ -116,10 +138,16 @@ static void *get_var(u16 *name, const efi_guid_t *vendor,
return buf;
}
/*
/**
* try_load_entry() - try to load image for boot option
*
* Attempt to load load-option number 'n', returning device_path and file_path
* if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
* if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
* and that the specified file to boot exists.
*
* @n: number of the boot option, e.g. 0x0a13 for Boot0A13
* @handle: on return handle for the newly installed image
* Return: status code
*/
static efi_status_t try_load_entry(u16 n, efi_handle_t *handle)
{
@ -180,10 +208,15 @@ error:
return ret;
}
/*
/**
* efi_bootmgr_load() - try to load from BootNext or BootOrder
*
* Attempt to load from BootNext or in the order specified by BootOrder
* EFI variable, the available load-options, finding and returning
* the first one that can be loaded successfully.
*
* @handle: on return handle for the newly installed image
* Return: status code
*/
efi_status_t efi_bootmgr_load(efi_handle_t *handle)
{

View File

@ -25,7 +25,7 @@ static efi_uintn_t efi_tpl = TPL_APPLICATION;
LIST_HEAD(efi_obj_list);
/* List of all events */
LIST_HEAD(efi_events);
__efi_runtime_data LIST_HEAD(efi_events);
/* List of queued events */
LIST_HEAD(efi_event_queue);
@ -596,7 +596,7 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
/**
* efi_delete_handle() - delete handle
*
* @obj: handle to delete
* @handle: handle to delete
*/
void efi_delete_handle(efi_handle_t handle)
{
@ -628,6 +628,7 @@ static efi_status_t efi_is_event(const struct efi_event *event)
/**
* efi_create_event() - create an event
*
* @type: type of the event to create
* @notify_tpl: task priority level of the event
* @notify_function: notification function of the event
@ -650,6 +651,8 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
struct efi_event **event)
{
struct efi_event *evt;
efi_status_t ret;
int pool_type;
if (event == NULL)
return EFI_INVALID_PARAMETER;
@ -662,7 +665,10 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
case EVT_NOTIFY_WAIT:
case EVT_TIMER | EVT_NOTIFY_WAIT:
case EVT_SIGNAL_EXIT_BOOT_SERVICES:
pool_type = EFI_BOOT_SERVICES_DATA;
break;
case EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE:
pool_type = EFI_RUNTIME_SERVICES_DATA;
break;
default:
return EFI_INVALID_PARAMETER;
@ -672,9 +678,11 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
(!notify_function || is_valid_tpl(notify_tpl) != EFI_SUCCESS))
return EFI_INVALID_PARAMETER;
evt = calloc(1, sizeof(struct efi_event));
if (!evt)
return EFI_OUT_OF_RESOURCES;
ret = efi_allocate_pool(pool_type, sizeof(struct efi_event),
(void **)&evt);
if (ret != EFI_SUCCESS)
return ret;
memset(evt, 0, sizeof(struct efi_event));
evt->type = type;
evt->notify_tpl = notify_tpl;
evt->notify_function = notify_function;
@ -982,7 +990,7 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
list_del(&event->queue_link);
list_del(&event->link);
free(event);
efi_free_pool(event);
return EFI_EXIT(EFI_SUCCESS);
}
@ -1411,9 +1419,9 @@ out:
/**
* efi_search() - determine if an EFI handle implements a protocol
*
* @search_type: selection criterion
* @protocol: GUID of the protocol
* @search_key: registration key
* @handle: handle
*
* See the documentation of the LocateHandle service in the UEFI specification.
@ -1675,7 +1683,7 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
* Initialize a loaded_image_info and loaded_image_info object with correct
* protocols, boot-device, etc.
*
* In case of an error *handle_ptr and *info_ptr are set to NULL and an error
* In case of an error \*handle_ptr and \*info_ptr are set to NULL and an error
* code is returned.
*
* @device_path: device path of the loaded image
@ -1932,7 +1940,7 @@ static void efi_exit_caches(void)
static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
efi_uintn_t map_key)
{
struct efi_event *evt;
struct efi_event *evt, *next_event;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %zx", image_handle, map_key);
@ -1971,6 +1979,12 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
/* Notify variable services */
efi_variables_boot_exit_notify();
/* Remove all events except EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
list_for_each_entry_safe(evt, next_event, &efi_events, link) {
if (evt->type != EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)
list_del(&evt->link);
}
board_quiesce_devices();
/* Patch out unsupported runtime function */
@ -3034,9 +3048,9 @@ out:
/**
* efi_update_exit_data() - fill exit data parameters of StartImage()
*
* @image_obj image handle
* @exit_data_size size of the exit data buffer
* @exit_data buffer with data returned by UEFI payload
* @image_obj: image handle
* @exit_data_size: size of the exit data buffer
* @exit_data: buffer with data returned by UEFI payload
* Return: status code
*/
static efi_status_t efi_update_exit_data(struct efi_loaded_image_obj *image_obj,

View File

@ -12,6 +12,7 @@
#include <mmc.h>
#include <efi_loader.h>
#include <part.h>
#include <asm-generic/unaligned.h>
/* template END node: */
static const struct efi_device_path END = {
@ -793,16 +794,36 @@ struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
return buf;
}
/* 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)
/**
* path_to_uefi() - convert UTF-8 path to an UEFI style path
*
* Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
* separators and UTF-16).
*
* @src: source buffer
* @uefi: target buffer, possibly unaligned
*/
static void path_to_uefi(void *uefi, const char *src)
{
while (*path) {
char c = *(path++);
if (c == '/')
c = '\\';
*(uefi++) = c;
u16 *pos = uefi;
/*
* efi_set_bootdev() calls this routine indirectly before the UEFI
* subsystem is initialized. So we cannot assume unaligned access to be
* enabled.
*/
allow_unaligned();
while (*src) {
s32 code = utf8_get(&src);
if (code < 0)
code = '?';
else if (code == '/')
code = '\\';
utf16_put(code, &pos);
}
*uefi = '\0';
*pos = 0;
}
/*
@ -819,7 +840,8 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
if (desc)
dpsize = dp_part_size(desc, part);
fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
fpsize = sizeof(struct efi_device_path) +
2 * (utf8_utf16_strlen(path) + 1);
dpsize += fpsize;
start = buf = dp_alloc(dpsize + sizeof(END));

View File

@ -755,6 +755,7 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
struct efi_device_path_file_path *fdp =
container_of(fp, struct efi_device_path_file_path, dp);
struct efi_file_handle *f2;
u16 *filename;
if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
printf("bad file path!\n");
@ -762,8 +763,12 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
return NULL;
}
EFI_CALL(ret = f->open(f, &f2, fdp->str,
filename = u16_strdup(fdp->str);
if (!filename)
return NULL;
EFI_CALL(ret = f->open(f, &f2, filename,
EFI_FILE_MODE_READ, 0));
free(filename);
if (ret != EFI_SUCCESS)
return NULL;

View File

@ -37,17 +37,21 @@ void *efi_bounce_buffer;
#endif
/**
* efi_pool_allocation - memory block allocated from pool
* struct efi_pool_allocation - memory block allocated from pool
*
* @num_pages: number of pages allocated
* @checksum: checksum
* @data: allocated pool memory
*
* U-Boot services each EFI AllocatePool request as a separate
* (multiple) page allocation. We have to track the number of pages
* U-Boot services each UEFI AllocatePool() request as a separate
* (multiple) page allocation. We have to track the number of pages
* to be able to free the correct amount later.
*
* The checksum calculated in function checksum() is used in FreePool() to avoid
* freeing memory not allocated by AllocatePool() and duplicate freeing.
*
* EFI requires 8 byte alignment for pool allocations, so we can
* prepend each allocation with an 64 bit header tracking the
* allocation size, and hand out the remainder to the caller.
* prepend each allocation with these header fields.
*/
struct efi_pool_allocation {
u64 num_pages;
@ -223,8 +227,17 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map,
return EFI_CARVE_LOOP_AGAIN;
}
uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
bool overlap_only_ram)
/**
* efi_add_memory_map() - add memory area to the memory map
*
* @start: start address, must be a multiple of EFI_PAGE_SIZE
* @pages: number of pages to add
* @memory_type: type of memory added
* @overlap_only_ram: the memory area must overlap existing
* Return: status code
*/
efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
bool overlap_only_ram)
{
struct list_head *lhandle;
struct efi_mem_list *newlist;
@ -239,7 +252,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
return EFI_INVALID_PARAMETER;
if (!pages)
return start;
return EFI_SUCCESS;
++efi_memory_map_key;
newlist = calloc(1, sizeof(*newlist));
@ -277,7 +290,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
* The user requested to only have RAM overlaps,
* but we hit a non-RAM region. Error out.
*/
return 0;
return EFI_NO_MAPPING;
case EFI_CARVE_NO_OVERLAP:
/* Just ignore this list entry */
break;
@ -307,7 +320,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
* The payload wanted to have RAM overlaps, but we overlapped
* with an unallocated region. Error out.
*/
return 0;
return EFI_NO_MAPPING;
}
/* Add our new map */
@ -326,7 +339,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
}
}
return start;
return EFI_SUCCESS;
}
/**
@ -455,7 +468,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
}
/* Reserve that map in our memory maps */
if (efi_add_memory_map(addr, pages, memory_type, true) != addr)
if (efi_add_memory_map(addr, pages, memory_type, true) != EFI_SUCCESS)
/* Map would overlap, bail out */
return EFI_OUT_OF_RESOURCES;
@ -487,7 +500,6 @@ 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;
efi_status_t ret;
ret = efi_check_allocated(memory, true);
@ -501,13 +513,13 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
return EFI_INVALID_PARAMETER;
}
r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
ret = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
/* Merging of adjacent free regions is missing */
if (r == memory)
return EFI_SUCCESS;
if (ret != EFI_SUCCESS)
return EFI_NOT_FOUND;
return EFI_NOT_FOUND;
return ret;
}
/**

View File

@ -391,8 +391,10 @@ efi_status_t __weak __efi_runtime EFIAPI efi_set_time(struct efi_time *time)
*/
static bool efi_is_runtime_service_pointer(void *p)
{
return p >= (void *)&efi_runtime_services.get_time &&
p <= (void *)&efi_runtime_services.query_variable_info;
return (p >= (void *)&efi_runtime_services.get_time &&
p <= (void *)&efi_runtime_services.query_variable_info) ||
p == (void *)&efi_events.prev ||
p == (void *)&efi_events.next;
}
/**
@ -424,7 +426,7 @@ void efi_runtime_detach(void)
* @virtmap: virtual address mapping information
* Return: status code EFI_UNSUPPORTED
*/
static efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
unsigned long memory_map_size,
unsigned long descriptor_size,
uint32_t descriptor_version,
@ -577,6 +579,7 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
int n = memory_map_size / descriptor_size;
int i;
int rt_code_sections = 0;
struct efi_event *event;
EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
descriptor_version, virtmap);
@ -610,6 +613,13 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
return EFI_EXIT(EFI_INVALID_PARAMETER);
}
/* Notify EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
list_for_each_entry(event, &efi_events, link) {
if (event->notify_function)
EFI_CALL_VOID(event->notify_function(
event, event->notify_context));
}
/* Rebind mmio pointers */
for (i = 0; i < n; i++) {
struct efi_mem_desc *map = (void*)virtmap +
@ -684,10 +694,10 @@ efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len)
struct efi_runtime_mmio_list *newmmio;
u64 pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
uint64_t addr = *(uintptr_t *)mmio_ptr;
uint64_t retaddr;
efi_status_t ret;
retaddr = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false);
if (retaddr != addr)
ret = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false);
if (ret != EFI_SUCCESS)
return EFI_OUT_OF_RESOURCES;
newmmio = calloc(1, sizeof(*newmmio));

View File

@ -263,8 +263,8 @@ static char *efi_cur_variable;
* is the size of variable name including NULL.
*
* Return: EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when
the entire variable list has been returned,
otherwise non-zero status code
* the entire variable list has been returned,
* otherwise non-zero status code
*/
static efi_status_t parse_uboot_variable(char *variable,
efi_uintn_t *variable_name_size,
@ -315,6 +315,7 @@ static efi_status_t parse_uboot_variable(char *variable,
/**
* efi_get_next_variable_name() - enumerate the current variable names
*
* @variable_name_size: size of variable_name buffer in byte
* @variable_name: name of uefi variable's name in u16
* @vendor: vendor's guid
@ -322,8 +323,7 @@ static efi_status_t parse_uboot_variable(char *variable,
* This function implements the GetNextVariableName service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details: http://wiki.phoenix.com/wiki/index.php/
* EFI_RUNTIME_SERVICES#GetNextVariableName.28.29
* details.
*
* Return: status code
*/
@ -550,6 +550,13 @@ efi_status_t __efi_runtime EFIAPI efi_query_variable_info(
/**
* efi_get_variable_runtime() - runtime implementation of GetVariable()
*
* @variable_name: name of the variable
* @vendor: vendor GUID
* @attributes: attributes of the variable
* @data_size: size of the buffer to which the variable value is copied
* @data: buffer to which the variable value is copied
* Return: status code
*/
static efi_status_t __efi_runtime EFIAPI
efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
@ -561,6 +568,11 @@ efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
/**
* efi_get_next_variable_name_runtime() - runtime implementation of
* GetNextVariable()
*
* @variable_name_size: size of variable_name buffer in byte
* @variable_name: name of uefi variable's name in u16
* @vendor: vendor's guid
* Return: status code
*/
static efi_status_t __efi_runtime EFIAPI
efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
@ -571,6 +583,13 @@ efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
/**
* efi_set_variable_runtime() - runtime implementation of SetVariable()
*
* @variable_name: name of the variable
* @vendor: vendor GUID
* @attributes: attributes of the variable
* @data_size: size of the buffer with the variable value
* @data: buffer with the variable value
* Return: status code
*/
static efi_status_t __efi_runtime EFIAPI
efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,

View File

@ -28,6 +28,7 @@ efi_selftest_manageprotocols.o \
efi_selftest_memory.o \
efi_selftest_open_protocol.o \
efi_selftest_register_notify.o \
efi_selftest_set_virtual_address_map.o \
efi_selftest_snp.o \
efi_selftest_textinput.o \
efi_selftest_textinputex.o \

View File

@ -55,28 +55,6 @@ static int setup(const efi_handle_t handle,
return EFI_ST_SUCCESS;
}
/*
* Tear down unit test.
*
* Close the event created in setup.
*
* @return: EFI_ST_SUCCESS for success
*/
static int teardown(void)
{
efi_status_t ret;
if (event_notify) {
ret = boottime->close_event(event_notify);
event_notify = NULL;
if (ret != EFI_SUCCESS) {
efi_st_error("could not close event\n");
return EFI_ST_FAILURE;
}
}
return EFI_ST_SUCCESS;
}
/*
* Execute unit test.
*
@ -107,5 +85,4 @@ EFI_UNIT_TEST(exitbootservices) = {
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
.teardown = teardown,
};

View File

@ -0,0 +1,192 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* efi_selftest_set_virtual_address_map.c
*
* Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* This test checks the notification of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
* and the following services: SetVirtualAddressMap, ConvertPointer.
*/
#include <efi_selftest.h>
static const struct efi_boot_services *boottime;
static const struct efi_runtime_services *runtime;
static struct efi_event *event;
static struct efi_mem_desc *memory_map;
static efi_uintn_t map_size;
static efi_uintn_t desc_size;
static u32 desc_version;
static u64 page1;
static u64 page2;
static u32 notify_call_count;
/**
* notify () - notification function
*
* This function is called when the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event
* occurs. The correct output of ConvertPointer() is checked.
*
* @event notified event
* @context pointer to the notification count
*/
static void EFIAPI notify(struct efi_event *event, void *context)
{
void *addr;
efi_status_t ret;
++notify_call_count;
addr = (void *)(uintptr_t)page1;
ret = runtime->convert_pointer(0, &addr);
if (ret != EFI_SUCCESS)
efi_st_todo("ConvertPointer failed\n");
if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE)
efi_st_todo("ConvertPointer wrong address\n");
addr = (void *)(uintptr_t)page2;
ret = runtime->convert_pointer(0, &addr);
if (ret != EFI_SUCCESS)
efi_st_todo("ConvertPointer failed\n");
if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE)
efi_st_todo("ConvertPointer wrong address\n");
}
/**
* setup() - setup unit test
*
* The memory map is read. Boottime only entries are deleted. Two entries for
* newly allocated pages are added. For these virtual addresses deviating from
* the physical addresses are set.
*
* @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)
{
efi_uintn_t map_key;
efi_status_t ret;
struct efi_mem_desc *end, *pos1, *pos2;
boottime = systable->boottime;
runtime = systable->runtime;
ret = boottime->create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
TPL_CALLBACK, notify, NULL,
&event);
if (ret != EFI_SUCCESS) {
efi_st_error("could not create event\n");
return EFI_ST_FAILURE;
}
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 += 3 * 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 failed\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 failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
EFI_BOOT_SERVICES_DATA, 2, &page1);
if (ret != EFI_SUCCESS) {
efi_st_error("AllocatePages failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
EFI_BOOT_SERVICES_DATA, 3, &page2);
if (ret != EFI_SUCCESS) {
efi_st_error("AllocatePages failed\n");
return EFI_ST_FAILURE;
}
/* Remove entries not relevant for runtime from map */
end = (struct efi_mem_desc *)((u8 *)memory_map + map_size);
for (pos1 = memory_map, pos2 = memory_map;
pos2 < end; ++pos2) {
switch (pos2->type) {
case EFI_LOADER_CODE:
case EFI_LOADER_DATA:
case EFI_BOOT_SERVICES_CODE:
case EFI_BOOT_SERVICES_DATA:
continue;
}
memcpy(pos1, pos2, desc_size);
++pos1;
}
/*
* Add entries with virtual addresses deviating from the physical
* addresses. By choosing virtual address ranges within the allocated
* physical pages address space collisions are avoided.
*/
pos1->type = EFI_RUNTIME_SERVICES_DATA;
pos1->reserved = 0;
pos1->physical_start = page1;
pos1->virtual_start = page1 + EFI_PAGE_SIZE;
pos1->num_pages = 1;
pos1->attribute = EFI_MEMORY_RUNTIME;
++pos1;
pos1->type = EFI_RUNTIME_SERVICES_DATA;
pos1->reserved = 0;
pos1->physical_start = page2;
pos1->virtual_start = page2 + 2 * EFI_PAGE_SIZE;
pos1->num_pages = 1;
pos1->attribute = EFI_MEMORY_RUNTIME;
++pos1;
map_size = (u8 *)pos1 - (u8 *)memory_map;
return EFI_ST_SUCCESS;
}
/**
* execute() - execute unit test
*
* SetVirtualAddressMap() is called with the memory map prepared in setup().
*
* The triggering of the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event is checked via
* the call count of the notification function.
*
* @return: EFI_ST_SUCCESS for success
*/
static int execute(void)
{
efi_status_t ret;
ret = runtime->set_virtual_address_map(map_size, desc_size,
desc_version, memory_map);
if (ret != EFI_SUCCESS) {
efi_st_error("SetVirtualAddressMap failed\n");
return EFI_ST_FAILURE;
}
if (notify_call_count != 1) {
efi_st_error("EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE triggered %d times\n",
notify_call_count);
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(virtaddrmap) = {
.name = "virtual address map",
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
};

View File

@ -50,6 +50,16 @@ static const char j1[] = {0x6a, 0x31, 0xa1, 0x6c, 0x00};
static const char j2[] = {0x6a, 0x32, 0xc3, 0xc3, 0x6c, 0x00};
static const char j3[] = {0x6a, 0x33, 0xf0, 0x90, 0xf0, 0x00};
static int unicode_test_u16_strlen(struct unit_test_state *uts)
{
ut_asserteq(6, u16_strlen(c1));
ut_asserteq(8, u16_strlen(c2));
ut_asserteq(3, u16_strlen(c3));
ut_asserteq(6, u16_strlen(c4));
return 0;
}
UNICODE_TEST(unicode_test_u16_strlen);
static int unicode_test_u16_strdup(struct unit_test_state *uts)
{
u16 *copy = u16_strdup(c4);