efi_loader: implement UnloadImage()
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Wed, 1 May 2019 16:25:45 +0000 (18:25 +0200)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Tue, 7 May 2019 19:10:03 +0000 (21:10 +0200)
Implement the UnloadImage() boot service

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
include/efi_api.h
lib/efi_loader/efi_boottime.c

index 472160cb300c661d4d5a0c260f8592b2f40bef6a..b2ae279747423201f13d69ccd028fda94ce476d4 100644 (file)
@@ -348,7 +348,7 @@ struct efi_loaded_image {
        aligned_u64 image_size;
        unsigned int image_code_type;
        unsigned int image_data_type;
-       unsigned long unload;
+       efi_status_t (EFIAPI *unload)(efi_handle_t image_handle);
 };
 
 #define EFI_DEVICE_PATH_PROTOCOL_GUID \
index 8f2c610b860011acd306a022c7b3bc1c8a6d6890..0385883ded2fc10d67c137c29da96e3f3a4aa8bf 100644 (file)
@@ -2669,6 +2669,20 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
        return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL));
 }
 
+/**
+ * efi_delete_image() - delete loaded image from memory)
+ *
+ * @image_obj:                 handle of the loaded image
+ * @loaded_image_protocol:     loaded image protocol
+ */
+static void efi_delete_image(struct efi_loaded_image_obj *image_obj,
+                            struct efi_loaded_image *loaded_image_protocol)
+{
+       efi_free_pages((uintptr_t)loaded_image_protocol->image_base,
+                      efi_size_in_pages(loaded_image_protocol->image_size));
+       efi_delete_handle(&image_obj->header);
+}
+
 /**
  * efi_unload_image() - unload an EFI image
  * @image_handle: handle of the image to be unloaded
@@ -2682,14 +2696,47 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
  */
 efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
 {
+       efi_status_t ret = EFI_SUCCESS;
        struct efi_object *efiobj;
+       struct efi_loaded_image *loaded_image_protocol;
 
        EFI_ENTRY("%p", image_handle);
-       efiobj = efi_search_obj(image_handle);
-       if (efiobj)
-               list_del(&efiobj->link);
 
-       return EFI_EXIT(EFI_SUCCESS);
+       efiobj = efi_search_obj(image_handle);
+       if (!efiobj) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+       /* Find the loaded image protocol */
+       ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image,
+                                        (void **)&loaded_image_protocol,
+                                        NULL, NULL,
+                                        EFI_OPEN_PROTOCOL_GET_PROTOCOL));
+       if (ret != EFI_SUCCESS) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+       switch (efiobj->type) {
+       case EFI_OBJECT_TYPE_STARTED_IMAGE:
+               /* Call the unload function */
+               if (!loaded_image_protocol->unload) {
+                       ret = EFI_UNSUPPORTED;
+                       goto out;
+               }
+               ret = EFI_CALL(loaded_image_protocol->unload(image_handle));
+               if (ret != EFI_SUCCESS)
+                       goto out;
+               break;
+       case EFI_OBJECT_TYPE_LOADED_IMAGE:
+               break;
+       default:
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+       efi_delete_image((struct efi_loaded_image_obj *)efiobj,
+                        loaded_image_protocol);
+out:
+       return EFI_EXIT(ret);
 }
 
 /**