return EFI_EXIT(r);
}
+/*
+ * Add a new object to the object list.
+ *
+ * The protocols list is initialized.
+ * The object handle is set.
+ *
+ * @obj object to be added
+ */
+void efi_add_handle(struct efi_object *obj)
+{
+ if (!obj)
+ return;
+ INIT_LIST_HEAD(&obj->protocols);
+ obj->handle = obj;
+ list_add_tail(&obj->link, &efi_obj_list);
+}
+
/*
* Create handle.
*
(void **)&obj);
if (r != EFI_SUCCESS)
return r;
- memset(obj, 0, sizeof(struct efi_object));
- obj->handle = obj;
- list_add_tail(&obj->link, &efi_obj_list);
- *handle = obj;
+ efi_add_handle(obj);
+ *handle = obj->handle;
return r;
}
+/*
+ * Find a protocol on a handle.
+ *
+ * @handle handle
+ * @protocol_guid GUID of the protocol
+ * @handler reference to the protocol
+ * @return status code
+ */
+efi_status_t efi_search_protocol(const void *handle,
+ const efi_guid_t *protocol_guid,
+ struct efi_handler **handler)
+{
+ struct efi_object *efiobj;
+ struct list_head *lhandle;
+
+ if (!handle || !protocol_guid)
+ return EFI_INVALID_PARAMETER;
+ efiobj = efi_search_obj(handle);
+ if (!efiobj)
+ return EFI_INVALID_PARAMETER;
+ list_for_each(lhandle, &efiobj->protocols) {
+ struct efi_handler *protocol;
+
+ protocol = list_entry(lhandle, struct efi_handler, link);
+ if (!guidcmp(protocol->guid, protocol_guid)) {
+ if (handler)
+ *handler = protocol;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+/*
+ * Delete protocol from a handle.
+ *
+ * @handle handle from which the protocol shall be deleted
+ * @protocol GUID of the protocol to be deleted
+ * @protocol_interface interface of the protocol implementation
+ * @return status code
+ */
+efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol,
+ void *protocol_interface)
+{
+ struct efi_handler *handler;
+ efi_status_t ret;
+
+ ret = efi_search_protocol(handle, protocol, &handler);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ if (guidcmp(handler->guid, protocol))
+ return EFI_INVALID_PARAMETER;
+ list_del(&handler->link);
+ free(handler);
+ return EFI_SUCCESS;
+}
+
+/*
+ * Delete all protocols from a handle.
+ *
+ * @handle handle from which the protocols shall be deleted
+ * @return status code
+ */
+efi_status_t efi_remove_all_protocols(const void *handle)
+{
+ struct efi_object *efiobj;
+ struct list_head *lhandle;
+ struct list_head *pos;
+
+ efiobj = efi_search_obj(handle);
+ if (!efiobj)
+ return EFI_INVALID_PARAMETER;
+ list_for_each_safe(lhandle, pos, &efiobj->protocols) {
+ struct efi_handler *protocol;
+ efi_status_t ret;
+
+ protocol = list_entry(lhandle, struct efi_handler, link);
+
+ ret = efi_remove_protocol(handle, protocol->guid,
+ protocol->protocol_interface);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ }
+ return EFI_SUCCESS;
+}
+
+/*
+ * Delete handle.
+ *
+ * @handle handle to delete
+ */
+void efi_delete_handle(struct efi_object *obj)
+{
+ if (!obj)
+ return;
+ efi_remove_all_protocols(obj->handle);
+ list_del(&obj->link);
+ free(obj);
+}
+
/*
* Our event capabilities are very limited. Only a small limited
* number of events is allowed to coexist.
return NULL;
}
-/*
- * Find a protocol on a handle.
- *
- * @handle handle
- * @protocol_guid GUID of the protocol
- * @handler reference to the protocol
- * @return status code
- */
-efi_status_t efi_search_protocol(const void *handle,
- const efi_guid_t *protocol_guid,
- struct efi_handler **handler)
-{
- struct efi_object *efiobj;
- size_t i;
- struct efi_handler *protocol;
-
- if (!handle || !protocol_guid)
- return EFI_INVALID_PARAMETER;
- efiobj = efi_search_obj(handle);
- if (!efiobj)
- return EFI_INVALID_PARAMETER;
- for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
- protocol = &efiobj->protocols[i];
- if (!protocol->guid)
- continue;
- if (!guidcmp(protocol->guid, protocol_guid)) {
- if (handler)
- *handler = protocol;
- return EFI_SUCCESS;
- }
- }
- return EFI_NOT_FOUND;
-}
-
/*
* Install new protocol on a handle.
*
struct efi_object *efiobj;
struct efi_handler *handler;
efi_status_t ret;
- size_t i;
efiobj = efi_search_obj(handle);
if (!efiobj)
handler = calloc(1, sizeof(struct efi_handler));
if (!handler)
return EFI_OUT_OF_RESOURCES;
- /* Install protocol in first empty slot. */
- for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
- handler = &efiobj->protocols[i];
- if (handler->guid)
- continue;
- handler->guid = protocol;
- handler->protocol_interface = protocol_interface;
- return EFI_SUCCESS;
- }
- return EFI_OUT_OF_RESOURCES;
-}
-
-/*
- * Delete protocol from a handle.
- *
- * @handle handle from which the protocol shall be deleted
- * @protocol GUID of the protocol to be deleted
- * @protocol_interface interface of the protocol implementation
- * @return status code
- */
-efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol,
- void *protocol_interface)
-{
- struct efi_handler *handler;
- efi_status_t ret;
-
- ret = efi_search_protocol(handle, protocol, &handler);
- if (ret != EFI_SUCCESS)
- return ret;
- if (handler->protocol_interface != protocol_interface)
- return EFI_NOT_FOUND;
- handler->guid = NULL;
- handler->protocol_interface = NULL;
- return EFI_SUCCESS;
-}
-
-/*
- * Delete all protocols from a handle.
- *
- * @handle handle from which the protocols shall be deleted
- * @return status code
- */
-efi_status_t efi_remove_all_protocols(const void *handle)
-{
- struct efi_object *efiobj;
- struct efi_handler *handler;
- size_t i;
-
- efiobj = efi_search_obj(handle);
- if (!efiobj)
- return EFI_INVALID_PARAMETER;
-
- for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
- handler = &efiobj->protocols[i];
- handler->guid = NULL;
- handler->protocol_interface = NULL;
- }
+ handler->guid = protocol;
+ handler->protocol_interface = protocol_interface;
+ list_add_tail(&handler->link, &efiobj->protocols);
return EFI_SUCCESS;
}
buffer_size, buffer));
}
-/*
- * Get the device path and handle of an device implementing a protocol.
- *
- * This function implements the LocateDevicePath service.
- * See the Unified Extensible Firmware Interface (UEFI) specification
- * for details.
- *
- * @protocol GUID of the protocol
- * @device_path device path
- * @device handle of the device
- * @return status code
- */
-static efi_status_t EFIAPI efi_locate_device_path(
- const efi_guid_t *protocol,
- struct efi_device_path **device_path,
- efi_handle_t *device)
-{
- struct efi_object *efiobj;
-
- EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
-
- efiobj = efi_dp_find_obj(*device_path, device_path);
- if (!efiobj)
- return EFI_EXIT(EFI_NOT_FOUND);
-
- *device = efiobj->handle;
-
- return EFI_EXIT(EFI_SUCCESS);
-}
-
/* Collapses configuration table entries, removing index i */
static void efi_remove_configuration_table(int i)
{
* @obj internal object associated with the loaded image
* @device_path device path of the loaded image
* @file_path file path of the loaded image
+ * @return status code
*/
-void 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_loaded_image *info, struct efi_object *obj,
+ struct efi_device_path *device_path,
+ struct efi_device_path *file_path)
{
efi_status_t ret;
+ /* Add internal object to object list */
+ efi_add_handle(obj);
+ /* efi_exit() assumes that the handle points to the info */
obj->handle = info;
info->file_path = file_path;
if (device_path)
info->device_handle = efi_dp_find_obj(device_path, NULL);
- list_add_tail(&obj->link, &efi_obj_list);
/*
* When asking for the device path interface, return
* bootefi_device_path
if (ret != EFI_SUCCESS)
goto failure;
- return;
+ return ret;
failure:
printf("ERROR: Failure to install protocols for loaded image\n");
+ return ret;
}
/*
{
struct efi_loaded_image *info;
struct efi_object *obj;
+ efi_status_t ret;
EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
file_path, source_buffer, source_size, image_handle);
if (!source_buffer) {
struct efi_device_path *dp, *fp;
- efi_status_t ret;
ret = efi_load_image_from_path(file_path, &source_buffer);
- if (ret != EFI_SUCCESS) {
- free(info);
- free(obj);
- return EFI_EXIT(ret);
- }
-
+ if (ret != EFI_SUCCESS)
+ goto failure;
/*
* split file_path which contains both the device and
* file parts:
*/
efi_dp_split_file_path(file_path, &dp, &fp);
-
- efi_setup_loaded_image(info, obj, 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.
* something like a HARDWARE_DEVICE:MEMORY_MAPPED
*/
- efi_setup_loaded_image(info, obj, file_path, NULL);
+ ret = efi_setup_loaded_image(info, obj, file_path, NULL);
+ if (ret != EFI_SUCCESS)
+ goto failure;
}
-
info->reserved = efi_load_pe(source_buffer, info);
if (!info->reserved) {
- free(info);
- free(obj);
- return EFI_EXIT(EFI_UNSUPPORTED);
+ ret = EFI_UNSUPPORTED;
+ goto failure;
}
-
info->system_table = &systab;
info->parent_handle = parent_image;
- *image_handle = info;
-
+ *image_handle = obj->handle;
return EFI_EXIT(EFI_SUCCESS);
+failure:
+ free(info);
+ efi_delete_handle(obj);
+ return EFI_EXIT(ret);
}
/*
{
ulong (*entry)(void *image_handle, struct efi_system_table *st);
struct efi_loaded_image *info = image_handle;
+ efi_status_t ret;
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
entry = info->reserved;
/* call the image! */
if (setjmp(&info->exit_jmp)) {
- /* We returned from the child image */
+ /*
+ * We called the entry point of the child image with EFI_CALL
+ * in the lines below. The child image called the Exit() boot
+ * service efi_exit() which executed the long jump that brought
+ * us to the current line. This implies that the second half
+ * of the EFI_CALL macro has not been executed.
+ */
+#ifdef CONFIG_ARM
+ /*
+ * 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;
+#endif
+ /*
+ * To get ready to call EFI_EXIT below we have to execute the
+ * missed out steps of EFI_CALL.
+ */
+ assert(__efi_entry_check());
+ debug("%sEFI: %lu returned by started image\n",
+ __efi_nesting_dec(),
+ (unsigned long)((uintptr_t)info->exit_status &
+ ~EFI_ERROR_MASK));
return EFI_EXIT(info->exit_status);
}
- __efi_nesting_dec();
- __efi_exit_check();
- entry(image_handle, &systab);
- __efi_entry_check();
- __efi_nesting_inc();
+ ret = EFI_CALL(entry(image_handle, &systab));
/* Should usually never get here */
- return EFI_EXIT(EFI_SUCCESS);
+ return EFI_EXIT(ret);
}
/*
efi_status_t exit_status, unsigned long exit_data_size,
int16_t *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;
EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
exit_data_size, exit_data);
/* Make sure entry/exit counts for EFI world cross-overs match */
- __efi_exit_check();
+ EFI_EXIT(exit_status);
/*
* But longjmp out with the U-Boot gd, not the application's, as
{
unsigned long buffer_size;
struct efi_object *efiobj;
- unsigned long i, j;
- struct list_head *lhandle;
+ struct list_head *protocol_handle;
efi_status_t r;
EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
*protocol_buffer = NULL;
*protocol_buffer_count = 0;
- list_for_each(lhandle, &efi_obj_list) {
- efiobj = list_entry(lhandle, struct efi_object, link);
- if (efiobj->handle != handle)
- continue;
+ efiobj = efi_search_obj(handle);
+ if (!efiobj)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
- /* Count protocols */
- for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
- if (efiobj->protocols[i].guid)
- ++*protocol_buffer_count;
- }
- /* Copy guids */
- if (*protocol_buffer_count) {
- buffer_size = sizeof(efi_guid_t *) *
- *protocol_buffer_count;
- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
- buffer_size,
- (void **)protocol_buffer);
- if (r != EFI_SUCCESS)
- return EFI_EXIT(r);
- j = 0;
- for (i = 0; i < ARRAY_SIZE(efiobj->protocols); ++i) {
- if (efiobj->protocols[i].guid) {
- (*protocol_buffer)[j] = (void *)
- efiobj->protocols[i].guid;
- ++j;
- }
- }
+ /* Count protocols */
+ list_for_each(protocol_handle, &efiobj->protocols) {
+ ++*protocol_buffer_count;
+ }
+
+ /* 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,
+ (void **)protocol_buffer);
+ if (r != EFI_SUCCESS)
+ return EFI_EXIT(r);
+ list_for_each(protocol_handle, &efiobj->protocols) {
+ struct efi_handler *protocol;
+
+ protocol = list_entry(protocol_handle,
+ struct efi_handler, link);
+ (*protocol_buffer)[j] = (void *)protocol->guid;
+ ++j;
}
- break;
}
return EFI_EXIT(EFI_SUCCESS);
return EFI_EXIT(EFI_NOT_FOUND);
}
+/*
+ * Get the device path and handle of an device implementing a protocol.
+ *
+ * This function implements the LocateDevicePath service.
+ * See the Unified Extensible Firmware Interface (UEFI) specification
+ * for details.
+ *
+ * @protocol GUID of the protocol
+ * @device_path device path
+ * @device handle of the device
+ * @return status code
+ */
+static efi_status_t EFIAPI efi_locate_device_path(
+ const efi_guid_t *protocol,
+ struct efi_device_path **device_path,
+ efi_handle_t *device)
+{
+ struct efi_device_path *dp;
+ size_t i;
+ struct efi_handler *handler;
+ efi_handle_t *handles;
+ size_t len, len_dp;
+ size_t len_best = 0;
+ efi_uintn_t no_handles;
+ u8 *remainder;
+ efi_status_t ret;
+
+ EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
+
+ if (!protocol || !device_path || !*device_path || !device) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /* Find end of device path */
+ len = efi_dp_size(*device_path);
+
+ /* Get all handles implementing the protocol */
+ ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
+ &no_handles, &handles));
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ for (i = 0; i < no_handles; ++i) {
+ /* Find the device path protocol */
+ ret = efi_search_protocol(handles[i], &efi_guid_device_path,
+ &handler);
+ if (ret != EFI_SUCCESS)
+ continue;
+ dp = (struct efi_device_path *)handler->protocol_interface;
+ len_dp = efi_dp_size(dp);
+ /*
+ * This handle can only be a better fit
+ * if its device path length is longer than the best fit and
+ * if its device path length is shorter of equal the searched
+ * device path.
+ */
+ if (len_dp <= len_best || len_dp > len)
+ continue;
+ /* Check if dp is a subpath of device_path */
+ if (memcmp(*device_path, dp, len_dp))
+ continue;
+ *device = handles[i];
+ len_best = len_dp;
+ }
+ if (len_best) {
+ remainder = (u8 *)*device_path + len_best;
+ *device_path = (struct efi_device_path *)remainder;
+ ret = EFI_SUCCESS;
+ } else {
+ ret = EFI_NOT_FOUND;
+ }
+out:
+ return EFI_EXIT(ret);
+}
+
/*
* Install multiple protocol interfaces.
*
void **protocol_interface, void *agent_handle,
void *controller_handle, uint32_t attributes)
{
- struct list_head *lhandle;
- int i;
+ struct efi_handler *handler;
efi_status_t r = EFI_INVALID_PARAMETER;
EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol,
goto out;
}
- EFI_PRINT_GUID("protocol", protocol);
-
switch (attributes) {
case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
goto out;
}
- list_for_each(lhandle, &efi_obj_list) {
- struct efi_object *efiobj;
- efiobj = list_entry(lhandle, struct efi_object, link);
-
- if (efiobj->handle != handle)
- continue;
-
- for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
- struct efi_handler *handler = &efiobj->protocols[i];
- const efi_guid_t *hprotocol = handler->guid;
- if (!hprotocol)
- continue;
- if (!guidcmp(hprotocol, protocol)) {
- if (attributes !=
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
- *protocol_interface =
- handler->protocol_interface;
- }
- r = EFI_SUCCESS;
- goto out;
- }
- }
- goto unsupported;
- }
+ r = efi_search_protocol(handle, protocol, &handler);
+ if (r != EFI_SUCCESS)
+ goto out;
-unsupported:
- r = EFI_UNSUPPORTED;
+ if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
+ *protocol_interface = handler->protocol_interface;
out:
return EFI_EXIT(r);
}
};
-static uint16_t __efi_runtime_data firmware_vendor[] =
- { 'D','a','s',' ','U','-','b','o','o','t',0 };
+static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot";
struct efi_system_table __efi_runtime_data systab = {
.hdr = {