diff options
author | Tom Rini <trini@konsulko.com> | 2019-07-23 22:29:53 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-07-23 22:29:53 -0400 |
commit | fe4243870df152f839f88e5aa355f53cfba0a866 (patch) | |
tree | 6f748cbe5c48597a4075ebea87344c4763736686 /lib/efi_loader | |
parent | ff8c23e784f57a7098e91a200ed7f5a48612b653 (diff) | |
parent | f62be16ddb76a32e6315bb9517b49e639726e1fa (diff) |
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.
Diffstat (limited to 'lib/efi_loader')
-rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 47 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 38 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path.c | 40 | ||||
-rw-r--r-- | lib/efi_loader/efi_file.c | 7 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 46 | ||||
-rw-r--r-- | lib/efi_loader/efi_runtime.c | 22 | ||||
-rw-r--r-- | lib/efi_loader/efi_variable.c | 27 |
7 files changed, 171 insertions, 56 deletions
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index b2102c5b5a..2ea21448f0 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -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) { diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index c2f89805c7..4f6e8d1679 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -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, diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 10f890f44f..eeeb806836 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -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)); diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 36ca719a82..f4ca5694ee 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -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; diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 27379381e8..b5775e0399 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -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; } /** diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 7a64dd42ca..8b56ab0207 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -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)); diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index bc8ed678c9..889a7f2ba0 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -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, |