diff mbox

[U-Boot,RFC,10/10] efi_loader: support load_image() from a file-path

Message ID 20170727213807.7523-11-robdclark@gmail.com
State RFC
Delegated to: Alexander Graf
Headers show

Commit Message

Rob Clark July 27, 2017, 9:38 p.m. UTC
Previously we only supported the case when the EFI application loaded
the image into memory for us.  But fallback.efi does not do this.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 lib/efi_loader/efi_boottime.c | 91 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 76 insertions(+), 15 deletions(-)

Comments

Rob Clark July 27, 2017, 10:50 p.m. UTC | #1
On Thu, Jul 27, 2017 at 5:38 PM, Rob Clark <robdclark@gmail.com> wrote:
> Previously we only supported the case when the EFI application loaded
> the image into memory for us.  But fallback.efi does not do this.
>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  lib/efi_loader/efi_boottime.c | 91 ++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 76 insertions(+), 15 deletions(-)
>
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index aa342670c2..326a428a57 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -749,6 +749,45 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>         list_add_tail(&obj->link, &efi_obj_list);
>  }
>
> +static efi_status_t load_image_from_path(struct efi_device_path *file_path,
> +                                        void **buffer)
> +{
> +       struct efi_file_info *info = NULL;
> +       struct efi_file_handle *f;
> +       static efi_status_t ret;
> +       uint64_t bs;
> +
> +       f = efi_file_from_path(file_path);
> +       if (!f)
> +               return EFI_DEVICE_ERROR;
> +
> +       bs = sizeof(info);

oh, this should actually be: bs = 0;

already fixed up locally

BR,
-R

> +       EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs, info));
> +       if (ret == EFI_BUFFER_TOO_SMALL) {
> +               info = malloc(bs);
> +               EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs, info));
> +       }
> +       if (ret != EFI_SUCCESS)
> +               goto error;
> +
> +       ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer);
> +       if (ret)
> +               goto error;
> +
> +       EFI_CALL(ret = f->read(f, &info->file_size, *buffer));
> +
> +error:
> +       free(info);
> +       EFI_CALL(f->close(f));
> +
> +       if (ret != EFI_SUCCESS) {
> +               efi_free_pool(*buffer);
> +               *buffer = NULL;
> +       }
> +
> +       return ret;
> +}
> +
>  static efi_status_t EFIAPI efi_load_image(bool boot_policy,
>                                           efi_handle_t parent_image,
>                                           struct efi_device_path *file_path,
> @@ -756,25 +795,48 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
>                                           unsigned long source_size,
>                                           efi_handle_t *image_handle)
>  {
> -       static struct efi_object loaded_image_info_obj = {
> -               .protocols = {
> -                       {
> -                               .guid = &efi_guid_loaded_image,
> -                       },
> -               },
> -       };
>         struct efi_loaded_image *info;
>         struct efi_object *obj;
>
>         EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
>                   file_path, source_buffer, source_size, image_handle);
> -       info = malloc(sizeof(*info));
> -       loaded_image_info_obj.protocols[0].protocol_interface = info;
> -       obj = malloc(sizeof(loaded_image_info_obj));
> -       memset(info, 0, sizeof(*info));
> -       memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj));
> -       obj->handle = info;
> -       info->file_path = file_path;
> +
> +       info = calloc(1, sizeof(*info));
> +       obj = calloc(1, sizeof(*obj));
> +
> +       if (!source_buffer) {
> +               struct efi_device_path *dp, *fp, *p;
> +               efi_status_t ret;
> +
> +               ret = load_image_from_path(file_path, &source_buffer);
> +               if (ret != EFI_SUCCESS) {
> +                       free(info);
> +                       free(obj);
> +                       return EFI_EXIT(ret);
> +               }
> +
> +               /*
> +                * split file_path which contains both the device and
> +                * file parts:
> +                */
> +               dp = efi_dp_dup(file_path);
> +               p = dp;
> +               while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH))
> +                       p = efi_dp_next(p);
> +               fp = efi_dp_dup(p);
> +
> +               p->type = DEVICE_PATH_TYPE_END;
> +               p->sub_type = DEVICE_PATH_SUB_TYPE_END;
> +               p->length = sizeof(*p);
> +
> +               efi_setup_loaded_image(info, obj, dp, fp);
> +       } 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);
> +       }
> +
>         info->reserved = efi_load_pe(source_buffer, info);
>         if (!info->reserved) {
>                 free(info);
> @@ -783,7 +845,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
>         }
>
>         *image_handle = info;
> -       list_add_tail(&obj->link, &efi_obj_list);
>
>         return EFI_EXIT(EFI_SUCCESS);
>  }
> --
> 2.13.0
>
diff mbox

Patch

diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index aa342670c2..326a428a57 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -749,6 +749,45 @@  void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
 	list_add_tail(&obj->link, &efi_obj_list);
 }
 
+static efi_status_t load_image_from_path(struct efi_device_path *file_path,
+					 void **buffer)
+{
+	struct efi_file_info *info = NULL;
+	struct efi_file_handle *f;
+	static efi_status_t ret;
+	uint64_t bs;
+
+	f = efi_file_from_path(file_path);
+	if (!f)
+		return EFI_DEVICE_ERROR;
+
+	bs = sizeof(info);
+	EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs, info));
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		info = malloc(bs);
+		EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs, info));
+	}
+	if (ret != EFI_SUCCESS)
+		goto error;
+
+	ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer);
+	if (ret)
+		goto error;
+
+	EFI_CALL(ret = f->read(f, &info->file_size, *buffer));
+
+error:
+	free(info);
+	EFI_CALL(f->close(f));
+
+	if (ret != EFI_SUCCESS) {
+		efi_free_pool(*buffer);
+		*buffer = NULL;
+	}
+
+	return ret;
+}
+
 static efi_status_t EFIAPI efi_load_image(bool boot_policy,
 					  efi_handle_t parent_image,
 					  struct efi_device_path *file_path,
@@ -756,25 +795,48 @@  static efi_status_t EFIAPI efi_load_image(bool boot_policy,
 					  unsigned long source_size,
 					  efi_handle_t *image_handle)
 {
-	static struct efi_object loaded_image_info_obj = {
-		.protocols = {
-			{
-				.guid = &efi_guid_loaded_image,
-			},
-		},
-	};
 	struct efi_loaded_image *info;
 	struct efi_object *obj;
 
 	EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
 		  file_path, source_buffer, source_size, image_handle);
-	info = malloc(sizeof(*info));
-	loaded_image_info_obj.protocols[0].protocol_interface = info;
-	obj = malloc(sizeof(loaded_image_info_obj));
-	memset(info, 0, sizeof(*info));
-	memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj));
-	obj->handle = info;
-	info->file_path = file_path;
+
+	info = calloc(1, sizeof(*info));
+	obj = calloc(1, sizeof(*obj));
+
+	if (!source_buffer) {
+		struct efi_device_path *dp, *fp, *p;
+		efi_status_t ret;
+
+		ret = load_image_from_path(file_path, &source_buffer);
+		if (ret != EFI_SUCCESS) {
+			free(info);
+			free(obj);
+			return EFI_EXIT(ret);
+		}
+
+		/*
+		 * split file_path which contains both the device and
+		 * file parts:
+		 */
+		dp = efi_dp_dup(file_path);
+		p = dp;
+		while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH))
+			p = efi_dp_next(p);
+		fp = efi_dp_dup(p);
+
+		p->type = DEVICE_PATH_TYPE_END;
+		p->sub_type = DEVICE_PATH_SUB_TYPE_END;
+		p->length = sizeof(*p);
+
+		efi_setup_loaded_image(info, obj, dp, fp);
+	} 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);
+	}
+
 	info->reserved = efi_load_pe(source_buffer, info);
 	if (!info->reserved) {
 		free(info);
@@ -783,7 +845,6 @@  static efi_status_t EFIAPI efi_load_image(bool boot_policy,
 	}
 
 	*image_handle = info;
-	list_add_tail(&obj->link, &efi_obj_list);
 
 	return EFI_EXIT(EFI_SUCCESS);
 }