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 | |
parent | ff8c23e784f57a7098e91a200ed7f5a48612b653 (diff) | |
parent | f62be16ddb76a32e6315bb9517b49e639726e1fa (diff) | |
download | u-boot-fe4243870df152f839f88e5aa355f53cfba0a866.tar.gz |
Merge tag 'efi-2019-10-rc1-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efiWIP/23Jul2019
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')
-rw-r--r-- | lib/charset.c | 23 | ||||
-rw-r--r-- | lib/efi_driver/efi_block_device.c | 39 | ||||
-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 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 1 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_exitbootservices.c | 23 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_set_virtual_address_map.c | 192 |
12 files changed, 398 insertions, 107 deletions
diff --git a/lib/charset.c b/lib/charset.c index 5e349ed5ee..72d745da4f 100644 --- a/lib/charset.c +++ b/lib/charset.c @@ -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; } diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c index 3f147cf608..cf02341931 100644 --- a/lib/efi_driver/efi_block_device.c +++ b/lib/efi_driver/efi_block_device.c @@ -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) { 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, diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 88678755cc..5d7a1643ef 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -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 \ diff --git a/lib/efi_selftest/efi_selftest_exitbootservices.c b/lib/efi_selftest/efi_selftest_exitbootservices.c index f1a136044d..4fecd1b415 100644 --- a/lib/efi_selftest/efi_selftest_exitbootservices.c +++ b/lib/efi_selftest/efi_selftest_exitbootservices.c @@ -56,28 +56,6 @@ static int setup(const efi_handle_t handle, } /* - * 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. * * Check that the notification function of the EVT_SIGNAL_EXIT_BOOT_SERVICES @@ -107,5 +85,4 @@ EFI_UNIT_TEST(exitbootservices) = { .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, .setup = setup, .execute = execute, - .teardown = teardown, }; diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c new file mode 100644 index 0000000000..6ee7bbeb01 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c @@ -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, +}; |