efi_loader: correctly call images
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Thu, 18 Jan 2018 19:28:43 +0000 (20:28 +0100)
committerAlexander Graf <agraf@suse.de>
Mon, 22 Jan 2018 22:09:12 +0000 (23:09 +0100)
Avoid a failed assertion when an EFI app calls an EFI app.

Avoid that the indent level increases when calling 'bootefi hello'
repeatedly.

Avoid negative indent level when an EFI app calls an EFI app that
calls an EFI app (e.g. iPXE loads grub which starts the kernel).

Return the status code of a loaded image that returns without
calling the Exit boot service.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
lib/efi_loader/efi_boottime.c

index 02bc9fdcf056c6cd68178be049663ddc94326bfa..965eb1f0c51ea8eeb2f59e7763aa0c9a0648242e 100644 (file)
@@ -1371,6 +1371,7 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
 {
        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;
@@ -1379,18 +1380,37 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
 
        /* 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);
 }
 
 /*
@@ -1427,7 +1447,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
                  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