diff mbox series

[U-Boot,10/11] efi_loader: Add mem-mapped for fallback

Message ID 20171010122309.25313-11-robdclark@gmail.com
State Accepted
Commit bf19273e81eb5e23c9bc14c3881f92a120565561
Delegated to: Alexander Graf
Headers show
Series efi_loader: patches for Shell.efi | expand

Commit Message

Rob Clark Oct. 10, 2017, 12:23 p.m. UTC
When we don't have a real device/image path, such as 'bootefi hello',
construct a mem-mapped device-path.

This fixes 'bootefi hello' after devicepath refactoring.

Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 cmd/bootefi.c                            | 23 +++++++++++++++++++++++
 include/efi_api.h                        |  8 ++++++++
 include/efi_loader.h                     |  3 +++
 lib/efi_loader/efi_device_path.c         | 24 ++++++++++++++++++++++++
 lib/efi_loader/efi_device_path_to_text.c |  9 +++++++++
 5 files changed, 67 insertions(+)

Comments

Heinrich Schuchardt Oct. 10, 2017, 10:31 p.m. UTC | #1
On 10/10/2017 02:23 PM, Rob Clark wrote:
> When we don't have a real device/image path, such as 'bootefi hello',
> construct a mem-mapped device-path.
> 
> This fixes 'bootefi hello' after devicepath refactoring.
> 
> Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>   cmd/bootefi.c                            | 23 +++++++++++++++++++++++
>   include/efi_api.h                        |  8 ++++++++
>   include/efi_loader.h                     |  3 +++
>   lib/efi_loader/efi_device_path.c         | 24 ++++++++++++++++++++++++
>   lib/efi_loader/efi_device_path_to_text.c |  9 +++++++++
>   5 files changed, 67 insertions(+)
> 
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 24958ada46..18176a1266 100644
> --- a/cmd/bootefi.c
> +++ b/cmd/bootefi.c
> @@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>   {
>   	struct efi_loaded_image loaded_image_info = {};
>   	struct efi_object loaded_image_info_obj = {};
> +	struct efi_device_path *memdp = NULL;
>   	ulong ret;
>   
>   	ulong (*entry)(void *image_handle, struct efi_system_table *st)
> @@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>   	const efi_guid_t fdt_guid = EFI_FDT_GUID;
>   	bootm_headers_t img = { 0 };
>   
> +	/*
> +	 * Special case for efi payload not loaded from disk, such as
> +	 * 'bootefi hello' or for example payload loaded directly into
> +	 * memory via jtag/etc:
> +	 */
> +	if (!device_path && !image_path) {
> +		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
> +		/* actual addresses filled in after efi_load_pe() */
> +		memdp = efi_dp_from_mem(0, 0, 0);
> +		device_path = image_path = memdp;
> +	} else {
> +		assert(device_path && image_path);
> +	}
> +
>   	/* Initialize and populate EFI object list */
>   	if (!efi_obj_list_initalized)
>   		efi_init_obj_list();
> @@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>   		goto exit;
>   	}
>   
> +	if (memdp) {
> +		struct efi_device_path_memory *mdp = (void *)memdp;
> +		mdp->memory_type = loaded_image_info.image_code_type;
> +		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
> +		mdp->end_address = mdp->start_address +
> +				loaded_image_info.image_size;
> +	}
> +
>   	/* we don't support much: */
>   	env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
>   		"{ro,boot}(blob)0000000000000000");
> diff --git a/include/efi_api.h b/include/efi_api.h
> index 9610d03d47..07b2af7020 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -299,8 +299,16 @@ struct efi_mac_addr {
>   } __packed;
>   
>   #define DEVICE_PATH_TYPE_HARDWARE_DEVICE	0x01
> +#  define DEVICE_PATH_SUB_TYPE_MEMORY		0x03
>   #  define DEVICE_PATH_SUB_TYPE_VENDOR		0x04
>   
> +struct efi_device_path_memory {
> +	struct efi_device_path dp;
> +	u32 memory_type;
> +	u64 start_address;
> +	u64 end_address;
> +} __packed;
> +
>   struct efi_device_path_vendor {
>   	struct efi_device_path dp;
>   	efi_guid_t guid;
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index fa4e1cdb1c..db805e898f 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -269,6 +269,9 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);
>   struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>   					 const char *path);
>   struct efi_device_path *efi_dp_from_eth(void);
> +struct efi_device_path *efi_dp_from_mem(uint32_t mem_type,
> +					uint64_t start_address,
> +					uint64_t end_address);
>   void efi_dp_split_file_path(struct efi_device_path *full_path,
>   			    struct efi_device_path **device_path,
>   			    struct efi_device_path **file_path);
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index 5d5c3b3464..f6e368e029 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -538,6 +538,30 @@ struct efi_device_path *efi_dp_from_eth(void)
>   }
>   #endif
>   
> +/* Construct a device-path for memory-mapped image */
> +struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
> +					uint64_t start_address,
> +					uint64_t end_address)
> +{
> +	struct efi_device_path_memory *mdp;
> +	void *buf, *start;
> +
> +	start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
> +
> +	mdp = buf;
> +	mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
> +	mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
> +	mdp->dp.length = sizeof(*mdp);
> +	mdp->memory_type = memory_type;
> +	mdp->start_address = start_address;
> +	mdp->end_address = end_address;
> +	buf = &mdp[1];
> +
> +	*((struct efi_device_path *)buf) = END;
> +
> +	return start;
> +}
> +
>   /*
>    * Helper to split a full device path (containing both device and file
>    * parts) into it's constituent parts.
> diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
> index 1a5ef3919b..62771338f0 100644
> --- a/lib/efi_loader/efi_device_path_to_text.c
> +++ b/lib/efi_loader/efi_device_path_to_text.c
> @@ -24,6 +24,15 @@ static char *dp_unknown(char *s, struct efi_device_path *dp)
>   static char *dp_hardware(char *s, struct efi_device_path *dp)
>   {
>   	switch (dp->sub_type) {
> +	case DEVICE_PATH_SUB_TYPE_MEMORY: {
> +		struct efi_device_path_memory *mdp =
> +			(struct efi_device_path_memory *)dp;
> +		s += sprintf(s, "/MemoryMapped(0x%x,0x%llx,0x%llx)",
> +			     mdp->memory_type,
> +			     mdp->start_address,
> +			     mdp->end_address);
> +		break;
> +	}
>   	case DEVICE_PATH_SUB_TYPE_VENDOR: {
>   		struct efi_device_path_vendor *vdp =
>   			(struct efi_device_path_vendor *)dp;
> 

Providing a dummmy device path for bootefi hello and bootefi selftest is 
reasonable.

Acked-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Alexander Graf Oct. 11, 2017, 2:59 p.m. UTC | #2
On 10.10.17 14:23, Rob Clark wrote:
> When we don't have a real device/image path, such as 'bootefi hello',
> construct a mem-mapped device-path.
> 
> This fixes 'bootefi hello' after devicepath refactoring.
> 
> Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  cmd/bootefi.c                            | 23 +++++++++++++++++++++++
>  include/efi_api.h                        |  8 ++++++++
>  include/efi_loader.h                     |  3 +++
>  lib/efi_loader/efi_device_path.c         | 24 ++++++++++++++++++++++++
>  lib/efi_loader/efi_device_path_to_text.c |  9 +++++++++
>  5 files changed, 67 insertions(+)
> 
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 24958ada46..18176a1266 100644
> --- a/cmd/bootefi.c
> +++ b/cmd/bootefi.c
> @@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>  {
>  	struct efi_loaded_image loaded_image_info = {};
>  	struct efi_object loaded_image_info_obj = {};
> +	struct efi_device_path *memdp = NULL;
>  	ulong ret;
>  
>  	ulong (*entry)(void *image_handle, struct efi_system_table *st)
> @@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>  	const efi_guid_t fdt_guid = EFI_FDT_GUID;
>  	bootm_headers_t img = { 0 };
>  
> +	/*
> +	 * Special case for efi payload not loaded from disk, such as
> +	 * 'bootefi hello' or for example payload loaded directly into
> +	 * memory via jtag/etc:
> +	 */
> +	if (!device_path && !image_path) {
> +		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
> +		/* actual addresses filled in after efi_load_pe() */
> +		memdp = efi_dp_from_mem(0, 0, 0);
> +		device_path = image_path = memdp;
> +	} else {
> +		assert(device_path && image_path);
> +	}
> +
>  	/* Initialize and populate EFI object list */
>  	if (!efi_obj_list_initalized)
>  		efi_init_obj_list();
> @@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>  		goto exit;
>  	}
>  
> +	if (memdp) {
> +		struct efi_device_path_memory *mdp = (void *)memdp;
> +		mdp->memory_type = loaded_image_info.image_code_type;
> +		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
> +		mdp->end_address = mdp->start_address +
> +				loaded_image_info.image_size;
> +	}
> +

memdp gets leaked after bootefi is done. Putting it on the stack would
at least remove that problem ;). We currently expect to only return from
bootefi when a payload was successfully quit.


Alex
Rob Clark Oct. 11, 2017, 10:14 p.m. UTC | #3
On Wed, Oct 11, 2017 at 10:59 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 10.10.17 14:23, Rob Clark wrote:
>> When we don't have a real device/image path, such as 'bootefi hello',
>> construct a mem-mapped device-path.
>>
>> This fixes 'bootefi hello' after devicepath refactoring.
>>
>> Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  cmd/bootefi.c                            | 23 +++++++++++++++++++++++
>>  include/efi_api.h                        |  8 ++++++++
>>  include/efi_loader.h                     |  3 +++
>>  lib/efi_loader/efi_device_path.c         | 24 ++++++++++++++++++++++++
>>  lib/efi_loader/efi_device_path_to_text.c |  9 +++++++++
>>  5 files changed, 67 insertions(+)
>>
>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>> index 24958ada46..18176a1266 100644
>> --- a/cmd/bootefi.c
>> +++ b/cmd/bootefi.c
>> @@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>>  {
>>       struct efi_loaded_image loaded_image_info = {};
>>       struct efi_object loaded_image_info_obj = {};
>> +     struct efi_device_path *memdp = NULL;
>>       ulong ret;
>>
>>       ulong (*entry)(void *image_handle, struct efi_system_table *st)
>> @@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>>       const efi_guid_t fdt_guid = EFI_FDT_GUID;
>>       bootm_headers_t img = { 0 };
>>
>> +     /*
>> +      * Special case for efi payload not loaded from disk, such as
>> +      * 'bootefi hello' or for example payload loaded directly into
>> +      * memory via jtag/etc:
>> +      */
>> +     if (!device_path && !image_path) {
>> +             printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
>> +             /* actual addresses filled in after efi_load_pe() */
>> +             memdp = efi_dp_from_mem(0, 0, 0);
>> +             device_path = image_path = memdp;
>> +     } else {
>> +             assert(device_path && image_path);
>> +     }
>> +
>>       /* Initialize and populate EFI object list */
>>       if (!efi_obj_list_initalized)
>>               efi_init_obj_list();
>> @@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>>               goto exit;
>>       }
>>
>> +     if (memdp) {
>> +             struct efi_device_path_memory *mdp = (void *)memdp;
>> +             mdp->memory_type = loaded_image_info.image_code_type;
>> +             mdp->start_address = (uintptr_t)loaded_image_info.image_base;
>> +             mdp->end_address = mdp->start_address +
>> +                             loaded_image_info.image_size;
>> +     }
>> +
>
> memdp gets leaked after bootefi is done. Putting it on the stack would
> at least remove that problem ;). We currently expect to only return from
> bootefi when a payload was successfully quit.
>

dp's that aren't allocated from pool are a bad idea, in some cases
they get free'd by the payload.  (Well not really in this particular
case but it feels like a bad idea to mix/match how we allocate dp's..
also, it needs an /End node.)  I guess it isn't such a critical leak,
but the right solution would be to efi_free_pool() it..

BR,
-R
Alexander Graf Oct. 12, 2017, 3:24 p.m. UTC | #4
> When we don't have a real device/image path, such as 'bootefi hello',
> construct a mem-mapped device-path.
> 
> This fixes 'bootefi hello' after devicepath refactoring.
> 
> Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> Acked-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

Thanks, applied to efi-next

Alex
diff mbox series

Patch

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 24958ada46..18176a1266 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -128,6 +128,7 @@  static unsigned long do_bootefi_exec(void *efi, void *fdt,
 {
 	struct efi_loaded_image loaded_image_info = {};
 	struct efi_object loaded_image_info_obj = {};
+	struct efi_device_path *memdp = NULL;
 	ulong ret;
 
 	ulong (*entry)(void *image_handle, struct efi_system_table *st)
@@ -136,6 +137,20 @@  static unsigned long do_bootefi_exec(void *efi, void *fdt,
 	const efi_guid_t fdt_guid = EFI_FDT_GUID;
 	bootm_headers_t img = { 0 };
 
+	/*
+	 * Special case for efi payload not loaded from disk, such as
+	 * 'bootefi hello' or for example payload loaded directly into
+	 * memory via jtag/etc:
+	 */
+	if (!device_path && !image_path) {
+		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
+		/* actual addresses filled in after efi_load_pe() */
+		memdp = efi_dp_from_mem(0, 0, 0);
+		device_path = image_path = memdp;
+	} else {
+		assert(device_path && image_path);
+	}
+
 	/* Initialize and populate EFI object list */
 	if (!efi_obj_list_initalized)
 		efi_init_obj_list();
@@ -182,6 +197,14 @@  static unsigned long do_bootefi_exec(void *efi, void *fdt,
 		goto exit;
 	}
 
+	if (memdp) {
+		struct efi_device_path_memory *mdp = (void *)memdp;
+		mdp->memory_type = loaded_image_info.image_code_type;
+		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
+		mdp->end_address = mdp->start_address +
+				loaded_image_info.image_size;
+	}
+
 	/* we don't support much: */
 	env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
 		"{ro,boot}(blob)0000000000000000");
diff --git a/include/efi_api.h b/include/efi_api.h
index 9610d03d47..07b2af7020 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -299,8 +299,16 @@  struct efi_mac_addr {
 } __packed;
 
 #define DEVICE_PATH_TYPE_HARDWARE_DEVICE	0x01
+#  define DEVICE_PATH_SUB_TYPE_MEMORY		0x03
 #  define DEVICE_PATH_SUB_TYPE_VENDOR		0x04
 
+struct efi_device_path_memory {
+	struct efi_device_path dp;
+	u32 memory_type;
+	u64 start_address;
+	u64 end_address;
+} __packed;
+
 struct efi_device_path_vendor {
 	struct efi_device_path dp;
 	efi_guid_t guid;
diff --git a/include/efi_loader.h b/include/efi_loader.h
index fa4e1cdb1c..db805e898f 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -269,6 +269,9 @@  struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);
 struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
 					 const char *path);
 struct efi_device_path *efi_dp_from_eth(void);
+struct efi_device_path *efi_dp_from_mem(uint32_t mem_type,
+					uint64_t start_address,
+					uint64_t end_address);
 void efi_dp_split_file_path(struct efi_device_path *full_path,
 			    struct efi_device_path **device_path,
 			    struct efi_device_path **file_path);
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 5d5c3b3464..f6e368e029 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -538,6 +538,30 @@  struct efi_device_path *efi_dp_from_eth(void)
 }
 #endif
 
+/* Construct a device-path for memory-mapped image */
+struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
+					uint64_t start_address,
+					uint64_t end_address)
+{
+	struct efi_device_path_memory *mdp;
+	void *buf, *start;
+
+	start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
+
+	mdp = buf;
+	mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+	mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
+	mdp->dp.length = sizeof(*mdp);
+	mdp->memory_type = memory_type;
+	mdp->start_address = start_address;
+	mdp->end_address = end_address;
+	buf = &mdp[1];
+
+	*((struct efi_device_path *)buf) = END;
+
+	return start;
+}
+
 /*
  * Helper to split a full device path (containing both device and file
  * parts) into it's constituent parts.
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
index 1a5ef3919b..62771338f0 100644
--- a/lib/efi_loader/efi_device_path_to_text.c
+++ b/lib/efi_loader/efi_device_path_to_text.c
@@ -24,6 +24,15 @@  static char *dp_unknown(char *s, struct efi_device_path *dp)
 static char *dp_hardware(char *s, struct efi_device_path *dp)
 {
 	switch (dp->sub_type) {
+	case DEVICE_PATH_SUB_TYPE_MEMORY: {
+		struct efi_device_path_memory *mdp =
+			(struct efi_device_path_memory *)dp;
+		s += sprintf(s, "/MemoryMapped(0x%x,0x%llx,0x%llx)",
+			     mdp->memory_type,
+			     mdp->start_address,
+			     mdp->end_address);
+		break;
+	}
 	case DEVICE_PATH_SUB_TYPE_VENDOR: {
 		struct efi_device_path_vendor *vdp =
 			(struct efi_device_path_vendor *)dp;