efi_loader: rename parent to header
[oweals/u-boot.git] / lib / efi_loader / efi_boottime.c
index 9a0c3235cf22efe53d96b4ea10b6d0b7cfa005c7..e3d911fad67d6a0c196c5cce65384c303c7cae07 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/libfdt_env.h>
 #include <u-boot/crc.h>
 #include <bootm.h>
-#include <inttypes.h>
 #include <watchdog.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -27,24 +26,6 @@ LIST_HEAD(efi_obj_list);
 /* List of all events */
 LIST_HEAD(efi_events);
 
-/*
- * If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
- * we need to do trickery with caches. Since we don't want to break the EFI
- * aware boot path, only apply hacks when loading exiting directly (breaking
- * direct Linux EFI booting along the way - oh well).
- */
-static bool efi_is_direct_boot = true;
-
-/*
- * EFI can pass arbitrary additional "tables" containing vendor specific
- * information to the payload. One such table is the FDT table which contains
- * a pointer to a flattened device tree blob.
- *
- * In most cases we want to pass an FDT to the payload, so reserve one slot of
- * config table space for it. The pointer gets populated by do_bootefi_exec().
- */
-static struct efi_configuration_table __efi_runtime_data efi_conf_table[16];
-
 #ifdef CONFIG_ARM
 /*
  * The "gd" pointer lives in a register on ARM and AArch64 that we declare
@@ -116,8 +97,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)
 {
@@ -194,7 +175,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)
 {
@@ -348,7 +329,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);
 }
@@ -435,13 +416,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);
 }
 
 /**
@@ -459,7 +439,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;
 }
@@ -555,13 +535,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);
 }
 
 /**
@@ -625,7 +605,8 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
                return EFI_INVALID_PARAMETER;
        }
 
-       if (is_valid_tpl(notify_tpl) != EFI_SUCCESS)
+       if ((type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) &&
+           (is_valid_tpl(notify_tpl) != EFI_SUCCESS))
                return EFI_INVALID_PARAMETER;
 
        evt = calloc(1, sizeof(struct efi_event));
@@ -636,7 +617,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;
@@ -742,7 +723,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.
@@ -757,8 +738,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);
 
@@ -784,7 +765,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.
  *
@@ -798,7 +779,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));
 }
 
@@ -945,7 +926,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;
        }
 
@@ -1037,7 +1018,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;
@@ -1070,8 +1051,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
  *
@@ -1079,7 +1060,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)
@@ -1090,7 +1071,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) {
@@ -1108,7 +1089,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) {
@@ -1135,8 +1116,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.
@@ -1146,16 +1127,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;
@@ -1163,7 +1144,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)
@@ -1174,21 +1155,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;
@@ -1196,8 +1175,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) {
@@ -1228,7 +1205,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);
 }
 
 /**
@@ -1258,7 +1269,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.
  *
@@ -1266,7 +1277,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;
 
@@ -1277,7 +1288,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 */
@@ -1349,7 +1360,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;
@@ -1390,9 +1401,9 @@ static efi_status_t EFIAPI efi_locate_handle_ext(
  */
 static void efi_remove_configuration_table(int i)
 {
-       struct efi_configuration_table *this = &efi_conf_table[i];
-       struct efi_configuration_table *next = &efi_conf_table[i + 1];
-       struct efi_configuration_table *end = &efi_conf_table[systab.nr_tables];
+       struct efi_configuration_table *this = &systab.tables[i];
+       struct efi_configuration_table *next = &systab.tables[i + 1];
+       struct efi_configuration_table *end = &systab.tables[systab.nr_tables];
 
        memmove(this, next, (ulong)end - (ulong)next);
        systab.nr_tables--;
@@ -1418,11 +1429,11 @@ 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, &efi_conf_table[i].guid)) {
+               if (!guidcmp(guid, &systab.tables[i].guid)) {
                        if (table)
-                               efi_conf_table[i].table = table;
+                               systab.tables[i].table = table;
                        else
                                efi_remove_configuration_table(i);
                        goto out;
@@ -1433,15 +1444,18 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
                return EFI_NOT_FOUND;
 
        /* No override, check for overflow */
-       if (i >= ARRAY_SIZE(efi_conf_table))
+       if (i >= EFI_MAX_CONFIGURATION_TABLES)
                return EFI_OUT_OF_RESOURCES;
 
        /* Add a new entry */
-       memcpy(&efi_conf_table[i].guid, guid, sizeof(*guid));
-       efi_conf_table[i].table = table;
+       memcpy(&systab.tables[i].guid, guid, sizeof(*guid));
+       systab.tables[i].table = table;
        systab.nr_tables = i + 1;
 
 out:
+       /* 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 */
        list_for_each_entry(evt, &efi_events, link) {
                if (evt->group && !guidcmp(evt->group, guid)) {
@@ -1485,20 +1499,35 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
  *
  * 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;
+       struct efi_loaded_image_obj *obj;
+
+       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);
+
+       if (info_ptr)
+               *info_ptr = info;
+       if (handle_ptr)
+               *handle_ptr = obj;
 
        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);
@@ -1506,8 +1535,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;
        }
@@ -1516,19 +1545,8 @@ 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);
-       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 (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_loaded_image, info);
        if (ret != EFI_SUCCESS)
                goto failure;
 
@@ -1610,8 +1628,9 @@ 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_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,
@@ -1627,18 +1646,6 @@ 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;
 
@@ -1650,35 +1657,35 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
                 * file parts:
                 */
                efi_dp_split_file_path(file_path, &dp, &fp);
-               ret = efi_setup_loaded_image(info, obj, dp, fp);
+               ret = efi_setup_loaded_image(dp, fp, image_obj, &info);
                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);
+               ret = efi_setup_loaded_image(file_path, NULL, image_obj, &info);
                if (ret != EFI_SUCCESS)
-                       goto failure;
+                       goto error;
        }
-       info->reserved = efi_load_pe(source_buffer, info);
-       if (!info->reserved) {
+       (*image_obj)->entry = efi_load_pe(*image_obj, source_buffer, info);
+       if (!(*image_obj)->entry) {
                ret = EFI_UNSUPPORTED;
                goto failure;
        }
        info->system_table = &systab;
        info->parent_handle = parent_image;
-       *image_handle = obj->handle;
        return EFI_EXIT(EFI_SUCCESS);
 failure:
+       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
@@ -1694,18 +1701,14 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
                                           unsigned long *exit_data_size,
                                           s16 **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
@@ -1728,16 +1731,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.
         */
@@ -1764,17 +1767,11 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
                                    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;
+       struct efi_loaded_image_obj *image_obj =
+               (struct efi_loaded_image_obj *)image_handle;
 
        EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
                  exit_data_size, exit_data);
@@ -1788,8 +1785,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");
 }
@@ -1817,21 +1814,6 @@ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
        return EFI_EXIT(EFI_SUCCESS);
 }
 
-/**
- * efi_exit_caches() - fix up caches for EFI payloads if necessary
- */
-static void efi_exit_caches(void)
-{
-#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
-       /*
-        * Grub on 32bit ARM needs to have caches disabled before jumping into
-        * a zImage, but does not know of all cache layers. Give it a hand.
-        */
-       if (efi_is_direct_boot)
-               cleanup_before_linux();
-#endif
-}
-
 /**
  * efi_exit_boot_services() - stop all boot services
  * @image_handle: handle of the loaded image
@@ -1881,17 +1863,14 @@ 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();
 
-       /* Fix up caches for EFI payloads if necessary */
-       efi_exit_caches();
-
        /* 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;
@@ -1901,9 +1880,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
        systab.boottime = NULL;
 
        /* Recalculate CRC32 */
-       systab.hdr.crc32 = 0;
-       systab.hdr.crc32 = crc32(0, (const unsigned char *)&systab,
-                                sizeof(struct efi_system_table));
+       efi_update_table_header_crc32(&systab.hdr);
 
        /* Give the payload some time to boot */
        efi_set_watchdog(0);
@@ -1969,7 +1946,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));
 }
@@ -2075,7 +2052,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;
@@ -2127,12 +2104,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);
@@ -2185,7 +2162,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;
@@ -2228,7 +2205,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);
@@ -2331,8 +2308,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);
 
@@ -2368,7 +2345,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);
@@ -2391,7 +2368,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);
 
@@ -2410,16 +2387,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);
@@ -2448,11 +2430,11 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
  *
  * Return: status code
  */
-static efi_status_t EFIAPI efi_calculate_crc32(void *data,
-                                              unsigned long data_size,
-                                              uint32_t *crc32_p)
+static efi_status_t EFIAPI efi_calculate_crc32(const void *data,
+                                              efi_uintn_t data_size,
+                                              u32 *crc32_p)
 {
-       EFI_ENTRY("%p, %ld", data, data_size);
+       EFI_ENTRY("%p, %zu", data, data_size);
        *crc32_p = crc32(0, data, data_size);
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -2558,7 +2540,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;
        }
@@ -2605,10 +2587,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;
@@ -2718,7 +2700,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
  */
@@ -2799,7 +2781,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
@@ -2880,13 +2862,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;
        /*
@@ -3056,11 +3044,11 @@ out:
        return EFI_EXIT(r);
 }
 
-static const struct efi_boot_services efi_boot_services = {
+static struct efi_boot_services efi_boot_services = {
        .hdr = {
                .signature = EFI_BOOT_SERVICES_SIGNATURE,
                .revision = EFI_SPECIFICATION_VERSION,
-               .headersize = sizeof(struct efi_table_hdr),
+               .headersize = sizeof(struct efi_boot_services),
        },
        .raise_tpl = efi_raise_tpl,
        .restore_tpl = efi_restore_tpl,
@@ -3110,20 +3098,44 @@ static const struct efi_boot_services efi_boot_services = {
        .create_event_ex = efi_create_event_ex,
 };
 
-static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot";
+static u16 __efi_runtime_data firmware_vendor[] = L"Das U-Boot";
 
 struct efi_system_table __efi_runtime_data systab = {
        .hdr = {
                .signature = EFI_SYSTEM_TABLE_SIGNATURE,
                .revision = EFI_SPECIFICATION_VERSION,
-               .headersize = sizeof(struct efi_table_hdr),
+               .headersize = sizeof(struct efi_system_table),
        },
-       .fw_vendor = (long)firmware_vendor,
+       .fw_vendor = firmware_vendor,
+       .fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8,
        .con_in = (void *)&efi_con_in,
        .con_out = (void *)&efi_con_out,
        .std_err = (void *)&efi_con_out,
        .runtime = (void *)&efi_runtime_services,
        .boottime = (void *)&efi_boot_services,
        .nr_tables = 0,
-       .tables = (void *)efi_conf_table,
+       .tables = NULL,
 };
+
+/**
+ * efi_initialize_system_table() - Initialize system table
+ *
+ * Return:     status code
+ */
+efi_status_t efi_initialize_system_table(void)
+{
+       efi_status_t ret;
+
+       /* Allocate configuration table array */
+       ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA,
+                               EFI_MAX_CONFIGURATION_TABLES *
+                               sizeof(struct efi_configuration_table),
+                               (void **)&systab.tables);
+
+       /* 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);
+
+       return ret;
+}