X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Fefi_loader%2Fefi_boottime.c;h=246b59d3b354bc037766b29af2c5d67e8c51abc9;hb=5a1a8a63be8f7262a300eddafb18020926b12fb6;hp=f75ca1a67c98a0ba4b9e6f7fc10d15ef0d1ea2ae;hpb=6f3badb67dcce2d67ac9abe35b10a04f560bbd08;p=platform%2Fkernel%2Fu-boot.git diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index f75ca1a..246b59d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -6,15 +6,20 @@ */ #include +#include #include +#include +#include #include -#include +#include +#include #include -#include -#include -#include #include +#include +#include +#include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -33,20 +38,23 @@ LIST_HEAD(efi_event_queue); /* Flag to disable timer activity in ExitBootServices() */ static bool timers_enabled = true; +/* Flag used by the selftest to avoid detaching devices in ExitBootServices() */ +bool efi_st_keep_devices; + /* List of all events registered by RegisterProtocolNotify() */ LIST_HEAD(efi_register_notify_events); /* Handle of the currently executing image */ static efi_handle_t current_image; -#ifdef CONFIG_ARM +#if defined(CONFIG_ARM) || defined(CONFIG_RISCV) /* - * The "gd" pointer lives in a register on ARM and AArch64 that we declare + * The "gd" pointer lives in a register on ARM and RISC-V that we declare * fixed when compiling U-Boot. However, the payload does not know about that * restriction so we need to manually swap its and our view of that register on * EFI callback entry/exit. */ -static volatile void *efi_gd, *app_gd; +static volatile gd_t *efi_gd, *app_gd; #endif /* 1 if inside U-Boot code, 0 if inside EFI payload code */ @@ -83,10 +91,10 @@ static efi_status_t EFIAPI efi_disconnect_controller( int __efi_entry_check(void) { int ret = entry_count++ == 0; -#ifdef CONFIG_ARM +#if defined(CONFIG_ARM) || defined(CONFIG_RISCV) assert(efi_gd); app_gd = gd; - gd = efi_gd; + set_gd(efi_gd); #endif return ret; } @@ -95,32 +103,42 @@ int __efi_entry_check(void) int __efi_exit_check(void) { int ret = --entry_count == 0; -#ifdef CONFIG_ARM - gd = app_gd; +#if defined(CONFIG_ARM) || defined(CONFIG_RISCV) + set_gd(app_gd); #endif return ret; } -/* Called from do_bootefi_exec() */ +/** + * efi_save_gd() - save global data register + * + * On the ARM and RISC-V architectures gd is mapped to a fixed register. + * As this register may be overwritten by an EFI payload we save it here + * and restore it on every callback entered. + * + * This function is called after relocation from initr_reloc_global_data(). + */ void efi_save_gd(void) { -#ifdef CONFIG_ARM +#if defined(CONFIG_ARM) || defined(CONFIG_RISCV) efi_gd = gd; #endif } -/* - * Special case handler for error/abort that just forces things back to u-boot - * world so we can dump out an abort message, without any care about returning - * back to UEFI world. +/** + * efi_restore_gd() - restore global data register + * + * On the ARM and RISC-V architectures gd is mapped to a fixed register. + * Restore it after returning from the UEFI world to the value saved via + * efi_save_gd(). */ void efi_restore_gd(void) { -#ifdef CONFIG_ARM +#if defined(CONFIG_ARM) || defined(CONFIG_RISCV) /* Only restore if we're already in EFI context */ if (!efi_gd) return; - gd = efi_gd; + set_gd(efi_gd); #endif } @@ -206,7 +224,7 @@ static void efi_process_event_queue(void) */ static void efi_queue_event(struct efi_event *event) { - struct efi_event *item = NULL; + struct efi_event *item; if (!event->notify_function) return; @@ -1399,7 +1417,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify( } item->event = event; - memcpy(&item->protocol, protocol, sizeof(efi_guid_t)); + guidcpy(&item->protocol, protocol); INIT_LIST_HEAD(&item->handles); list_add_tail(&item->link, &efi_register_notify_events); @@ -1630,7 +1648,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, return EFI_OUT_OF_RESOURCES; /* Add a new entry */ - memcpy(&systab.tables[i].guid, guid, sizeof(*guid)); + guidcpy(&systab.tables[i].guid, guid); systab.tables[i].table = table; systab.nr_tables = i + 1; @@ -1870,22 +1888,18 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy, if (ret != EFI_SUCCESS) goto error; } else { - if (!source_size) { - ret = EFI_LOAD_ERROR; - goto error; - } dest_buffer = source_buffer; } /* 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(dp, fp, image_obj, &info); if (ret == EFI_SUCCESS) - ret = efi_load_pe(*image_obj, dest_buffer, info); + ret = efi_load_pe(*image_obj, dest_buffer, source_size, info); if (!source_buffer) /* Release buffer to which file was loaded */ efi_free_pages((uintptr_t)dest_buffer, efi_size_in_pages(source_size)); - if (ret == EFI_SUCCESS) { + if (ret == EFI_SUCCESS || ret == EFI_SECURITY_VIOLATION) { info->system_table = &systab; info->parent_handle = parent_image; } else { @@ -1985,7 +1999,12 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, list_del(&evt->link); } - board_quiesce_devices(); + if (!efi_st_keep_devices) { + if IS_ENABLED(CONFIG_USB_DEVICE) + udc_disconnect(); + board_quiesce_devices(); + dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); + } /* Patch out unsupported runtime function */ efi_runtime_detach(); @@ -2104,10 +2123,10 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, * * Return: status code */ -static efi_status_t EFIAPI efi_close_protocol(efi_handle_t handle, - const efi_guid_t *protocol, - efi_handle_t agent_handle, - efi_handle_t controller_handle) +efi_status_t EFIAPI efi_close_protocol(efi_handle_t handle, + const efi_guid_t *protocol, + efi_handle_t agent_handle, + efi_handle_t controller_handle) { struct efi_handler *handler; struct efi_open_protocol_info_item *item; @@ -2280,7 +2299,7 @@ static efi_status_t EFIAPI efi_protocols_per_handle( * * Return: status code */ -static efi_status_t EFIAPI efi_locate_handle_buffer( +efi_status_t EFIAPI efi_locate_handle_buffer( enum efi_locate_search_type search_type, const efi_guid_t *protocol, void *search_key, efi_uintn_t *no_handles, efi_handle_t **buffer) @@ -2883,10 +2902,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); + if (!efi_search_obj(image_handle)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + /* Check parameters */ if (image_obj->header.type != EFI_OBJECT_TYPE_LOADED_IMAGE) return EFI_EXIT(EFI_INVALID_PARAMETER); + if (image_obj->auth_status != EFI_IMAGE_AUTH_PASSED) + return EFI_EXIT(EFI_SECURITY_VIOLATION); + ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image, &info, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)); @@ -2905,13 +2930,13 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, * us to the current line. This implies that the second half * of the EFI_CALL macro has not been executed. */ -#ifdef CONFIG_ARM +#if defined(CONFIG_ARM) || defined(CONFIG_RISCV) /* * efi_exit() called efi_restore_gd(). We have to undo this * otherwise __efi_entry_check() will put the wrong value into * app_gd. */ - gd = app_gd; + set_gd(app_gd); #endif /* * To get ready to call EFI_EXIT below we have to execute the @@ -2931,10 +2956,10 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, ret = EFI_CALL(image_obj->entry(image_handle, &systab)); /* - * Usually UEFI applications call Exit() instead of returning. - * 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. + * Control is returned from a started UEFI image either by calling + * Exit() (where exit data can be provided) or by simply returning from + * the entry point. In the latter case call Exit() on behalf of the + * image. */ return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL)); } @@ -3180,9 +3205,9 @@ out: * * Return: status code */ -static efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle, - const efi_guid_t *protocol, - void **protocol_interface) +efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle, + const efi_guid_t *protocol, + void **protocol_interface) { return efi_open_protocol(handle, protocol, protocol_interface, efi_root, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); @@ -3450,6 +3475,8 @@ static efi_status_t efi_get_child_controllers( * the buffer will be too large. But that does not harm. */ *number_of_children = 0; + if (!count) + return EFI_SUCCESS; *child_handle_buffer = calloc(count, sizeof(efi_handle_t)); if (!*child_handle_buffer) return EFI_OUT_OF_RESOURCES; @@ -3500,8 +3527,8 @@ static efi_status_t EFIAPI efi_disconnect_controller( efi_handle_t *child_handle_buffer = NULL; size_t number_of_children = 0; efi_status_t r; - size_t stop_count = 0; struct efi_object *efiobj; + bool sole_child; EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle, child_handle); @@ -3524,14 +3551,18 @@ static efi_status_t EFIAPI efi_disconnect_controller( } /* Create list of child handles */ + r = efi_get_child_controllers(efiobj, + driver_image_handle, + &number_of_children, + &child_handle_buffer); + if (r != EFI_SUCCESS) + return r; + sole_child = (number_of_children == 1); + if (child_handle) { number_of_children = 1; + free(child_handle_buffer); child_handle_buffer = &child_handle; - } else { - efi_get_child_controllers(efiobj, - driver_image_handle, - &number_of_children, - &child_handle_buffer); } /* Get the driver binding protocol */ @@ -3540,32 +3571,35 @@ static efi_status_t EFIAPI efi_disconnect_controller( (void **)&binding_protocol, driver_image_handle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)); - if (r != EFI_SUCCESS) + if (r != EFI_SUCCESS) { + r = EFI_INVALID_PARAMETER; goto out; + } /* Remove the children */ if (number_of_children) { r = EFI_CALL(binding_protocol->stop(binding_protocol, controller_handle, number_of_children, child_handle_buffer)); - if (r == EFI_SUCCESS) - ++stop_count; + if (r != EFI_SUCCESS) { + r = EFI_DEVICE_ERROR; + goto out; + } } /* Remove the driver */ - if (!child_handle) + if (!child_handle || sole_child) { r = EFI_CALL(binding_protocol->stop(binding_protocol, controller_handle, 0, NULL)); - if (r == EFI_SUCCESS) - ++stop_count; + if (r != EFI_SUCCESS) { + r = EFI_DEVICE_ERROR; + goto out; + } + } EFI_CALL(efi_close_protocol(driver_image_handle, &efi_guid_driver_binding_protocol, driver_image_handle, NULL)); - - if (stop_count) - r = EFI_SUCCESS; - else - r = EFI_NOT_FOUND; + r = EFI_SUCCESS; out: if (!child_handle) free(child_handle_buffer);