X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Fefi_loader%2Fefi_boottime.c;h=bd8b8a17ae719d80be4bae933aeb18788b9bf06a;hb=da206916a14fc8ab8962763c47673128a29b4b9c;hp=1192bdb5f5fa1f60631d95e9be7c7a93a3cc567f;hpb=3748ed908fd478b36bf698839632b2514c450513;p=platform%2Fkernel%2Fu-boot.git diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1192bdb..bd8b8a1 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -13,7 +13,6 @@ #include #include #include -#include #include DECLARE_GLOBAL_DATA_PTR; @@ -45,7 +44,8 @@ static bool efi_is_direct_boot = true; static volatile void *efi_gd, *app_gd; #endif -static int entry_count; +/* 1 if inside U-Boot code, 0 if inside EFI payload code */ +static int entry_count = 1; static int nesting_level; /* GUID of the device tree table */ const efi_guid_t efi_guid_fdt = EFI_FDT_GUID; @@ -106,8 +106,8 @@ void efi_save_gd(void) /* * Special case handler for error/abort that just forces things back to u-boot - * world so we can dump out an abort msg, without any care about returning back - * to UEFI world. + * world so we can dump out an abort message, without any care about returning + * back to UEFI world. */ void efi_restore_gd(void) { @@ -154,18 +154,6 @@ const char *__efi_nesting_dec(void) } /** - * efi_update_table_header_crc32() - Update CRC32 in table header - * - * @table: EFI table - */ -static void efi_update_table_header_crc32(struct efi_table_hdr *table) -{ - table->crc32 = 0; - table->crc32 = crc32(0, (const unsigned char *)table, - table->headersize); -} - -/** * efi_queue_event() - queue an EFI event * @event: event to signal * @check_tpl: check the TPL level @@ -196,7 +184,7 @@ static void efi_queue_event(struct efi_event *event, bool check_tpl) * is_valid_tpl() - check if the task priority level is valid * * @tpl: TPL level to check - * ReturnValue: status code + * Return: status code */ efi_status_t is_valid_tpl(efi_uintn_t tpl) { @@ -350,7 +338,7 @@ static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, { efi_status_t r; - EFI_ENTRY("%" PRIx64 ", 0x%zx", memory, pages); + EFI_ENTRY("%llx, 0x%zx", memory, pages); r = efi_free_pages(memory, pages); return EFI_EXIT(r); } @@ -437,13 +425,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); } /** @@ -461,7 +448,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; } @@ -557,13 +544,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); } /** @@ -639,7 +626,7 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, evt->notify_function = notify_function; evt->notify_context = notify_context; evt->group = group; - /* Disable timers on bootup */ + /* Disable timers on boot up */ evt->trigger_next = -1ULL; evt->is_queued = false; evt->is_signaled = false; @@ -745,7 +732,7 @@ void efi_timer_check(void) * efi_set_timer() - set the trigger time for a timer event or stop the event * @event: event for which the timer is set * @type: type of the timer - * @trigger_time: trigger period in multiples of 100ns + * @trigger_time: trigger period in multiples of 100 ns * * This is the function for internal usage in U-Boot. For the API function * implementing the SetTimer service see efi_set_timer_ext. @@ -760,8 +747,8 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, return EFI_INVALID_PARAMETER; /* - * The parameter defines a multiple of 100ns. - * We use multiples of 1000ns. So divide by 10. + * The parameter defines a multiple of 100 ns. + * We use multiples of 1000 ns. So divide by 10. */ do_div(trigger_time, 10); @@ -787,7 +774,7 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, * event * @event: event for which the timer is set * @type: type of the timer - * @trigger_time: trigger period in multiples of 100ns + * @trigger_time: trigger period in multiples of 100 ns * * This function implements the SetTimer service. * @@ -801,7 +788,7 @@ static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time) { - EFI_ENTRY("%p, %d, %" PRIx64, event, type, trigger_time); + EFI_ENTRY("%p, %d, %llx", event, type, trigger_time); return EFI_EXIT(efi_set_timer(event, type, trigger_time)); } @@ -948,7 +935,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; } @@ -1040,7 +1027,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; @@ -1073,8 +1060,8 @@ out: /** * efi_get_drivers() - get all drivers associated to a controller - * @efiobj: handle of the controller - * @protocol: protocol guid (optional) + * @handle: handle of the controller + * @protocol: protocol GUID (optional) * @number_of_drivers: number of child controllers * @driver_handle_buffer: handles of the the drivers * @@ -1082,7 +1069,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) @@ -1093,7 +1080,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) { @@ -1111,7 +1098,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) { @@ -1138,8 +1125,8 @@ 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 - * @protocol: protocol guid (optional) + * @handle: handle of the controller + * @protocol: protocol GUID (optional) * @child_handle: handle of the child to destroy * * This function implements the DisconnectController service. @@ -1149,16 +1136,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; @@ -1166,7 +1153,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) @@ -1177,21 +1164,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; @@ -1199,8 +1184,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) { @@ -1231,7 +1214,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); } /** @@ -1261,7 +1278,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. * @@ -1269,7 +1286,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; @@ -1280,7 +1297,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 */ @@ -1352,7 +1369,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; @@ -1421,7 +1438,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, if (!guid) return EFI_INVALID_PARAMETER; - /* Check for guid override */ + /* Check for GUID override */ for (i = 0; i < systab.nr_tables; i++) { if (!guidcmp(guid, &systab.tables[i].guid)) { if (table) @@ -1445,7 +1462,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, systab.nr_tables = i + 1; out: - /* systab.nr_tables may have changed. So we need to update the crc32 */ + /* systab.nr_tables may have changed. So we need to update the CRC32 */ efi_update_table_header_crc32(&systab.hdr); /* Notify that the configuration table was changed */ @@ -1481,30 +1498,47 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, /** * efi_setup_loaded_image() - initialize a loaded image - * @info: loaded image info to be passed to the entry point of the image - * @obj: internal object associated with the loaded image - * @device_path: device path of the loaded image - * @file_path: file path of the loaded image * * Initialize a loaded_image_info and loaded_image_info object with correct * protocols, boot-device, etc. * - * Return: status code + * 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 + * @file_path: file path of the loaded image + * @handle_ptr: handle of the loaded image + * @info_ptr: loaded image protocol + * Return: status code */ -efi_status_t efi_setup_loaded_image( - struct efi_loaded_image *info, struct efi_object *obj, - struct efi_device_path *device_path, - struct efi_device_path *file_path) +efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, + struct efi_device_path *file_path, + struct efi_loaded_image_obj **handle_ptr, + struct efi_loaded_image **info_ptr) { efi_status_t ret; + struct efi_loaded_image *info = NULL; + struct efi_loaded_image_obj *obj = NULL; + + /* In case of EFI_OUT_OF_RESOURCES avoid illegal free by caller. */ + *handle_ptr = NULL; + *info_ptr = NULL; + + info = calloc(1, sizeof(*info)); + if (!info) + return EFI_OUT_OF_RESOURCES; + obj = calloc(1, sizeof(*obj)); + if (!obj) { + free(info); + return EFI_OUT_OF_RESOURCES; + } /* Add internal object to object list */ - efi_add_handle(obj); - /* efi_exit() assumes that the handle points to the info */ - obj->handle = info; + efi_add_handle(&obj->header); info->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; info->file_path = file_path; + info->system_table = &systab; if (device_path) { info->device_handle = efi_dp_find_obj(device_path, NULL); @@ -1512,8 +1546,8 @@ efi_status_t efi_setup_loaded_image( * When asking for the device path interface, return * bootefi_device_path */ - ret = efi_add_protocol(obj->handle, &efi_guid_device_path, - device_path); + ret = efi_add_protocol(&obj->header, + &efi_guid_device_path, device_path); if (ret != EFI_SUCCESS) goto failure; } @@ -1522,74 +1556,112 @@ efi_status_t efi_setup_loaded_image( * When asking for the loaded_image interface, just * return handle which points to loaded_image_info */ - ret = efi_add_protocol(obj->handle, &efi_guid_loaded_image, info); + ret = efi_add_protocol(&obj->header, + &efi_guid_loaded_image, info); if (ret != EFI_SUCCESS) goto failure; - ret = efi_add_protocol(obj->handle, - &efi_guid_device_path_to_text_protocol, - (void *)&efi_device_path_to_text); +#if CONFIG_IS_ENABLED(EFI_LOADER_HII) + ret = efi_add_protocol(&obj->header, + &efi_guid_hii_string_protocol, + (void *)&efi_hii_string); if (ret != EFI_SUCCESS) goto failure; - ret = efi_add_protocol(obj->handle, - &efi_guid_device_path_utilities_protocol, - (void *)&efi_device_path_utilities); + ret = efi_add_protocol(&obj->header, + &efi_guid_hii_database_protocol, + (void *)&efi_hii_database); if (ret != EFI_SUCCESS) goto failure; + ret = efi_add_protocol(&obj->header, + &efi_guid_hii_config_routing_protocol, + (void *)&efi_hii_config_routing); + if (ret != EFI_SUCCESS) + goto failure; +#endif + + if (info_ptr) + *info_ptr = info; + if (handle_ptr) + *handle_ptr = obj; + return ret; failure: printf("ERROR: Failure to install protocols for loaded image\n"); + efi_delete_handle(&obj->header); + free(info); return ret; } /** * efi_load_image_from_path() - load an image using a file path - * @file_path: the path of the image to load - * @buffer: buffer containing the loaded image * - * Return: status code + * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the + * callers obligation to update the memory type as needed. + * + * @file_path: the path of the image to load + * @buffer: buffer containing the loaded image + * @size: size of the loaded image + * Return: status code */ efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, - void **buffer) + void **buffer, efi_uintn_t *size) { struct efi_file_info *info = NULL; struct efi_file_handle *f; static efi_status_t ret; + u64 addr; efi_uintn_t bs; + /* In case of failure nothing is returned */ + *buffer = NULL; + *size = 0; + + /* Open file */ f = efi_file_from_path(file_path); if (!f) return EFI_DEVICE_ERROR; + /* Get file size */ bs = 0; EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs, info)); - if (ret == EFI_BUFFER_TOO_SMALL) { - info = malloc(bs); - EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, - &bs, info)); - } - if (ret != EFI_SUCCESS) + if (ret != EFI_BUFFER_TOO_SMALL) { + ret = EFI_DEVICE_ERROR; goto error; + } - ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer); - if (ret) + info = malloc(bs); + EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs, + info)); + if (ret != EFI_SUCCESS) goto error; + /* + * When reading the file we do not yet know if it contains an + * application, a boottime driver, or a runtime driver. So here we + * allocate a buffer as EFI_BOOT_SERVICES_DATA. The caller has to + * update the reservation according to the image type. + */ bs = info->file_size; - EFI_CALL(ret = f->read(f, &bs, *buffer)); - -error: - free(info); - EFI_CALL(f->close(f)); - + ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_BOOT_SERVICES_DATA, + efi_size_in_pages(bs), &addr); if (ret != EFI_SUCCESS) { - efi_free_pool(*buffer); - *buffer = NULL; + ret = EFI_OUT_OF_RESOURCES; + goto error; } + /* Read file */ + EFI_CALL(ret = f->read(f, &bs, (void *)(uintptr_t)addr)); + if (ret != EFI_SUCCESS) + efi_free_pages(addr, efi_size_in_pages(bs)); + *buffer = (void *)(uintptr_t)addr; + *size = bs; +error: + EFI_CALL(f->close(f)); + free(info); return ret; } @@ -1616,8 +1688,10 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, efi_uintn_t source_size, efi_handle_t *image_handle) { - struct efi_loaded_image *info; - struct efi_object *obj; + struct efi_device_path *dp, *fp; + struct efi_loaded_image *info = NULL; + struct efi_loaded_image_obj **image_obj = + (struct efi_loaded_image_obj **)image_handle; efi_status_t ret; EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image, @@ -1633,58 +1707,61 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, goto error; } - info = calloc(1, sizeof(*info)); - if (!info) { - ret = EFI_OUT_OF_RESOURCES; - goto error; - } - obj = calloc(1, sizeof(*obj)); - if (!obj) { - free(info); - ret = EFI_OUT_OF_RESOURCES; - goto error; - } - if (!source_buffer) { - struct efi_device_path *dp, *fp; - - ret = efi_load_image_from_path(file_path, &source_buffer); + ret = efi_load_image_from_path(file_path, &source_buffer, + &source_size); if (ret != EFI_SUCCESS) - goto failure; + goto error; /* * split file_path which contains both the device and * file parts: */ efi_dp_split_file_path(file_path, &dp, &fp); - ret = efi_setup_loaded_image(info, obj, dp, fp); - if (ret != EFI_SUCCESS) - goto failure; } else { - /* In this case, file_path is the "device" path, ie. + /* In this case, file_path is the "device" path, i.e. * something like a HARDWARE_DEVICE:MEMORY_MAPPED */ - ret = efi_setup_loaded_image(info, obj, file_path, NULL); + u64 addr; + void *dest_buffer; + + ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_CODE, + efi_size_in_pages(source_size), &addr); if (ret != EFI_SUCCESS) - goto failure; - } - info->reserved = efi_load_pe(source_buffer, info); - if (!info->reserved) { - ret = EFI_UNSUPPORTED; - goto failure; + goto error; + dest_buffer = (void *)(uintptr_t)addr; + memcpy(dest_buffer, source_buffer, source_size); + source_buffer = dest_buffer; + + dp = file_path; + fp = NULL; } + ret = efi_setup_loaded_image(dp, fp, image_obj, &info); + if (ret != EFI_SUCCESS) + goto error_invalid_image; + ret = efi_load_pe(*image_obj, source_buffer, info); + if (ret != EFI_SUCCESS) + goto error_invalid_image; + /* Update the type of the allocated memory */ + efi_add_memory_map((uintptr_t)source_buffer, + efi_size_in_pages(source_size), + info->image_code_type, false); info->system_table = &systab; info->parent_handle = parent_image; - *image_handle = obj->handle; return EFI_EXIT(EFI_SUCCESS); -failure: +error_invalid_image: + /* The image is invalid. Release all associated resources. */ + efi_free_pages((uintptr_t)source_buffer, + efi_size_in_pages(source_size)); + efi_delete_handle(*image_handle); + *image_handle = NULL; free(info); - efi_delete_handle(obj); error: return EFI_EXIT(ret); } /** - * efi_start_image() - dall the entry point of an image + * efi_start_image() - call the entry point of an image * @image_handle: handle of the image * @exit_data_size: size of the buffer * @exit_data: buffer to receive the exit data of the called image @@ -1696,22 +1773,20 @@ error: * * Return: status code */ -static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, - unsigned long *exit_data_size, - s16 **exit_data) +efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, + efi_uintn_t *exit_data_size, + u16 **exit_data) { - EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, - struct efi_system_table *st); - struct efi_loaded_image *info = image_handle; + struct efi_loaded_image_obj *image_obj = + (struct efi_loaded_image_obj *)image_handle; efi_status_t ret; EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); - entry = info->reserved; efi_is_direct_boot = false; /* call the image! */ - if (setjmp(&info->exit_jmp)) { + if (setjmp(&image_obj->exit_jmp)) { /* * We called the entry point of the child image with EFI_CALL * in the lines below. The child image called the Exit() boot @@ -1734,16 +1809,16 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, assert(__efi_entry_check()); debug("%sEFI: %lu returned by started image\n", __efi_nesting_dec(), - (unsigned long)((uintptr_t)info->exit_status & + (unsigned long)((uintptr_t)image_obj->exit_status & ~EFI_ERROR_MASK)); - return EFI_EXIT(info->exit_status); + return EFI_EXIT(image_obj->exit_status); } - ret = EFI_CALL(entry(image_handle, &systab)); + ret = EFI_CALL(image_obj->entry(image_handle, &systab)); /* * Usually UEFI applications call Exit() instead of returning. - * But because the world doesn not consist of ponies and unicorns, + * But because the world doesn't consist of ponies and unicorns, * we're happy to emulate that behavior on behalf of a payload * that forgot. */ @@ -1766,23 +1841,17 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, */ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, efi_status_t exit_status, - unsigned long exit_data_size, - int16_t *exit_data) + efi_uintn_t exit_data_size, + u16 *exit_data) { /* - * We require that the handle points to the original loaded - * image protocol interface. - * - * For getting the longjmp address this is safer than locating - * the protocol because the protocol may have been reinstalled - * pointing to another memory location. - * * TODO: We should call the unload procedure of the loaded * image protocol. */ - struct efi_loaded_image *loaded_image_info = (void *)image_handle; + struct efi_loaded_image_obj *image_obj = + (struct efi_loaded_image_obj *)image_handle; - EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status, + EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status, exit_data_size, exit_data); /* Make sure entry/exit counts for EFI world cross-overs match */ @@ -1794,8 +1863,8 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, */ efi_restore_gd(); - loaded_image_info->exit_status = exit_status; - longjmp(&loaded_image_info->exit_jmp, 1); + image_obj->exit_status = exit_status; + longjmp(&image_obj->exit_jmp, 1); panic("EFI application exited"); } @@ -1887,7 +1956,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, } } - /* TODO Should persist EFI variables here */ + /* TODO: Should persist EFI variables here */ board_quiesce_devices(); @@ -1897,7 +1966,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, /* This stops all lingering devices */ bootm_disable_interrupts(); - /* Disable boottime services */ + /* Disable boot time services */ systab.con_in_handle = NULL; systab.con_in = NULL; systab.con_out_handle = NULL; @@ -1973,7 +2042,7 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, unsigned long data_size, uint16_t *watchdog_data) { - EFI_ENTRY("%ld, 0x%" PRIx64 ", %ld, %p", timeout, watchdog_code, + EFI_ENTRY("%ld, 0x%llx, %ld, %p", timeout, watchdog_code, data_size, watchdog_data); return EFI_EXIT(efi_set_watchdog(timeout)); } @@ -2079,7 +2148,7 @@ static efi_status_t EFIAPI efi_open_protocol_information( /* Copy entries */ buffer_size = count * sizeof(struct efi_open_protocol_info_entry); - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size, + r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, (void **)entry_buffer); if (r != EFI_SUCCESS) goto out; @@ -2131,12 +2200,12 @@ static efi_status_t EFIAPI efi_protocols_per_handle( ++*protocol_buffer_count; } - /* Copy guids */ + /* Copy GUIDs */ if (*protocol_buffer_count) { size_t j = 0; buffer_size = sizeof(efi_guid_t *) * *protocol_buffer_count; - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size, + r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, (void **)protocol_buffer); if (r != EFI_SUCCESS) return EFI_EXIT(r); @@ -2189,7 +2258,7 @@ static efi_status_t EFIAPI efi_locate_handle_buffer( *buffer); if (r != EFI_BUFFER_TOO_SMALL) goto out; - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size, + r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, (void **)buffer); if (r != EFI_SUCCESS) goto out; @@ -2232,7 +2301,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); @@ -2335,8 +2404,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); @@ -2372,7 +2441,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); @@ -2395,7 +2464,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); @@ -2414,16 +2483,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); @@ -2436,7 +2510,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); } /** @@ -2476,7 +2551,7 @@ static void EFIAPI efi_copy_mem(void *destination, const void *source, size_t length) { EFI_ENTRY("%p, %p, %ld", destination, source, (unsigned long)length); - memcpy(destination, source, length); + memmove(destination, source, length); EFI_EXIT(EFI_SUCCESS); } @@ -2562,7 +2637,7 @@ static efi_status_t efi_protocol_open( if (item->info.attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) opened_by_driver = true; } - /* Only one controller can be conncected */ + /* Only one controller can be connected */ if (opened_by_driver) return EFI_ACCESS_DENIED; } @@ -2609,10 +2684,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; @@ -2722,7 +2797,7 @@ static efi_status_t efi_bind_controller( * efi_connect_single_controller() - connect a single driver to a controller * @controller_handle: controller * @driver_image_handle: driver - * @remain_device_path: remainting path + * @remain_device_path: remaining path * * Return: status code */ @@ -2803,7 +2878,7 @@ static efi_status_t efi_connect_single_controller( * details. * * First all driver binding protocol handles are tried for binding drivers. - * Afterwards all handles that have openened a protocol of the controller + * Afterwards all handles that have opened a protocol of the controller * with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers. * * Return: status code @@ -2818,7 +2893,7 @@ static efi_status_t EFIAPI efi_connect_controller( efi_status_t ret = EFI_NOT_FOUND; struct efi_object *efiobj; - EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle, + EFI_ENTRY("%p, %p, %pD, %d", controller_handle, driver_image_handle, remain_device_path, recursive); efiobj = efi_search_obj(controller_handle); @@ -2884,13 +2959,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; /* @@ -3136,7 +3217,7 @@ struct efi_system_table __efi_runtime_data systab = { /** * efi_initialize_system_table() - Initialize system table * - * Return Value: status code + * Return: status code */ efi_status_t efi_initialize_system_table(void) { @@ -3148,7 +3229,7 @@ efi_status_t efi_initialize_system_table(void) sizeof(struct efi_configuration_table), (void **)&systab.tables); - /* Set crc32 field in table headers */ + /* Set CRC32 field in table headers */ efi_update_table_header_crc32(&systab.hdr); efi_update_table_header_crc32(&efi_runtime_services.hdr); efi_update_table_header_crc32(&efi_boot_services.hdr);