[v2,1/3] efi_loader: rework fdt handling in distro boot script

Message ID 20181022044007.11796-2-takahiro.akashi@linaro.org
State Superseded
Headers show
Series
  • efi_loader: improve boot sequence in distro_bootcmd
Related show

Commit Message

AKASHI Takahiro Oct. 22, 2018, 4:40 a.m.
The current scenario for default UEFI booting, scan_dev_for_efi, has
several issues:
* load dtb dynamically even if its loacation (device) is not the same
  as BOOTEFI_NAME binary's, (reported by Alex)
* invoke 'bootmgr' only if BOOTEFI_NAME binary does exit even though
  'bootmgr' can and should work independently whether or not the binary
  exist,
* in addition, invoke 'bootmgr' with dynamically-loaded dtb.
  This behavior is not expected. (reported by Alex)
* always assume that a 'fdtfile' variable is defined,
  ("test -e ${devtype} ${devnum}:${distro_bootpart} "${prefix}${efi_fdtfile}"
  always returns true even if fdtfile is NULL with prefix=="/".)
* redundantly check for 'fdt_addr_r' in boot_efi_binary

In this patch, all the issues above are sorted out.
Please note that the default behavior can be customized with:
	fdtfile: a dtb file name
	efi_dtb_prefixes: a list of paths for searching for a dtb file

(this feature does work even without this patch.)

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 include/config_distro_bootcmd.h | 38 +++++++++++++++++----------------
 1 file changed, 20 insertions(+), 18 deletions(-)

Comments

AKASHI Takahiro Oct. 22, 2018, 7:22 a.m. | #1
On Mon, Oct 22, 2018 at 01:40:05PM +0900, AKASHI Takahiro wrote:
> The current scenario for default UEFI booting, scan_dev_for_efi, has
> several issues:
> * load dtb dynamically even if its loacation (device) is not the same
>   as BOOTEFI_NAME binary's, (reported by Alex)
> * invoke 'bootmgr' only if BOOTEFI_NAME binary does exit even though
>   'bootmgr' can and should work independently whether or not the binary
>   exist,
> * in addition, invoke 'bootmgr' with dynamically-loaded dtb.
>   This behavior is not expected. (reported by Alex)
> * always assume that a 'fdtfile' variable is defined,
>   ("test -e ${devtype} ${devnum}:${distro_bootpart} "${prefix}${efi_fdtfile}"
>   always returns true even if fdtfile is NULL with prefix=="/".)
> * redundantly check for 'fdt_addr_r' in boot_efi_binary
> 
> In this patch, all the issues above are sorted out.
> Please note that the default behavior can be customized with:
> 	fdtfile: a dtb file name
> 	efi_dtb_prefixes: a list of paths for searching for a dtb file
> 
> (this feature does work even without this patch.)
> 
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
>  include/config_distro_bootcmd.h | 38 +++++++++++++++++----------------
>  1 file changed, 20 insertions(+), 18 deletions(-)
> 
> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
> index 373fee78a999..256698309eb9 100644
> --- a/include/config_distro_bootcmd.h
> +++ b/include/config_distro_bootcmd.h
> @@ -115,7 +115,7 @@
>   */
>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK                                  \
>  	"if test -z \"${fdtfile}\" -a -n \"${soc}\"; then "               \
> -	  "setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; "           \
> +	  "efi_fdtfile=${soc}-${board}${boardver}.dtb; "           \
>  	"fi; "
>  #else
>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK
> @@ -124,26 +124,20 @@
>  
>  #define BOOTENV_SHARED_EFI                                                \
>  	"boot_efi_binary="                                                \
> -		"if fdt addr ${fdt_addr_r}; then "                        \
> -			"bootefi bootmgr ${fdt_addr_r};"                  \
> -		"else "                                                   \
> -			"bootefi bootmgr ${fdtcontroladdr};"              \
> -		"fi;"                                                     \
>  		"load ${devtype} ${devnum}:${distro_bootpart} "           \
>  			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
> -		"if fdt addr ${fdt_addr_r}; then "                        \
> -			"bootefi ${kernel_addr_r} ${fdt_addr_r};"         \
> -		"else "                                                   \
> -			"bootefi ${kernel_addr_r} ${fdtcontroladdr};"     \
> -		"fi\0"                                                    \
> +		"bootefi ${kernel_addr_r} ${efi_fdt_addr};\0"		  \
>  	\
>  	"load_efi_dtb="                                                   \
> -		"load ${devtype} ${devnum}:${distro_bootpart} "           \
> -			"${fdt_addr_r} ${prefix}${efi_fdtfile}\0"         \
> +		"load ${devtype} ${devnum}:${distro_bootpart} "		  \
> +			"${fdt_addr_r} ${prefix}${efi_fdtfile}; "	  \
> +		"if fdt addr ${fdt_addr_r}; then "			  \
> +			"efi_fdt_addr=${fdt_addr_r}; "			  \
> +		"fi;\0"							  \
>  	\
>  	"efi_dtb_prefixes=/ /dtb/ /dtb/current/\0"                        \
> -	"scan_dev_for_efi="                                               \
> -		"setenv efi_fdtfile ${fdtfile}; "                         \
> +	"set_efi_fdt_addr="						  \
> +		"efi_fdtfile=${fdtfile}; "                         \
>  		BOOTENV_EFI_SET_FDTFILE_FALLBACK                          \
>  		"for prefix in ${efi_dtb_prefixes}; do "                  \
>  			"if test -e ${devtype} "                          \
> @@ -151,19 +145,26 @@
>  					"${prefix}${efi_fdtfile}; then "  \
>  				"run load_efi_dtb; "                      \
>  			"fi;"                                             \
> -		"done;"                                                   \
> +		"done;\0"                                                   \
> +	\
> +	"scan_dev_for_efi="                                               \
>  		"if test -e ${devtype} ${devnum}:${distro_bootpart} "     \
>  					"efi/boot/"BOOTEFI_NAME"; then "  \
>  				"echo Found EFI removable media binary "  \
>  					"efi/boot/"BOOTEFI_NAME"; "       \
> +				"efi_fdt_addr=${fdtcontroladdr}; "	  \
> +				"if test -n \"${fdtfile}\"; then "	  \
> +					"run set_efi_fdt_addr; "	  \
> +				"fi; "					  \
>  				"run boot_efi_binary; "                   \
>  				"echo EFI LOAD FAILED: continuing...; "   \
> -		"fi; "                                                    \
> -		"setenv efi_fdtfile\0"
> +		"fi;\0"
>  #define SCAN_DEV_FOR_EFI "run scan_dev_for_efi;"
> +#define BOOT_EFI_BOOT_MANAGER "bootefi bootmgr;"
>  #else
>  #define BOOTENV_SHARED_EFI
>  #define SCAN_DEV_FOR_EFI
> +#define BOOT_EFI_BOOT_MANAGER
>  #endif
>  
>  #ifdef CONFIG_SATA
> @@ -409,6 +410,7 @@
>  	BOOT_TARGET_DEVICES(BOOTENV_DEV)                                  \
>  	\
>  	"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT                      \
> +		BOOT_EFI_BOOT_MANAGER					  \

The last-minute change may have introduced a problem.
By moving "bootmgr" from scan_dev_for_efi" to here,
grub fails to start a grub.cfg menu, saying
  "error: no such device: /.disk/info."

Do you have any ideas?

-Takahiro Akashi


>  		"for target in ${boot_targets}; do "                      \
>  			"run bootcmd_${target}; "                         \
>  		"done\0"
> -- 
> 2.19.0
>
Alexander Graf Oct. 22, 2018, 7:42 a.m. | #2
On 22.10.18 08:22, AKASHI Takahiro wrote:
> On Mon, Oct 22, 2018 at 01:40:05PM +0900, AKASHI Takahiro wrote:
>> The current scenario for default UEFI booting, scan_dev_for_efi, has
>> several issues:
>> * load dtb dynamically even if its loacation (device) is not the same
>>   as BOOTEFI_NAME binary's, (reported by Alex)
>> * invoke 'bootmgr' only if BOOTEFI_NAME binary does exit even though
>>   'bootmgr' can and should work independently whether or not the binary
>>   exist,
>> * in addition, invoke 'bootmgr' with dynamically-loaded dtb.
>>   This behavior is not expected. (reported by Alex)
>> * always assume that a 'fdtfile' variable is defined,
>>   ("test -e ${devtype} ${devnum}:${distro_bootpart} "${prefix}${efi_fdtfile}"
>>   always returns true even if fdtfile is NULL with prefix=="/".)
>> * redundantly check for 'fdt_addr_r' in boot_efi_binary
>>
>> In this patch, all the issues above are sorted out.
>> Please note that the default behavior can be customized with:
>> 	fdtfile: a dtb file name
>> 	efi_dtb_prefixes: a list of paths for searching for a dtb file
>>
>> (this feature does work even without this patch.)
>>
>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>> ---
>>  include/config_distro_bootcmd.h | 38 +++++++++++++++++----------------
>>  1 file changed, 20 insertions(+), 18 deletions(-)
>>
>> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
>> index 373fee78a999..256698309eb9 100644
>> --- a/include/config_distro_bootcmd.h
>> +++ b/include/config_distro_bootcmd.h
>> @@ -115,7 +115,7 @@
>>   */
>>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK                                  \
>>  	"if test -z \"${fdtfile}\" -a -n \"${soc}\"; then "               \
>> -	  "setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; "           \
>> +	  "efi_fdtfile=${soc}-${board}${boardver}.dtb; "           \
>>  	"fi; "
>>  #else
>>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK
>> @@ -124,26 +124,20 @@
>>  
>>  #define BOOTENV_SHARED_EFI                                                \
>>  	"boot_efi_binary="                                                \
>> -		"if fdt addr ${fdt_addr_r}; then "                        \
>> -			"bootefi bootmgr ${fdt_addr_r};"                  \
>> -		"else "                                                   \
>> -			"bootefi bootmgr ${fdtcontroladdr};"              \
>> -		"fi;"                                                     \
>>  		"load ${devtype} ${devnum}:${distro_bootpart} "           \
>>  			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
>> -		"if fdt addr ${fdt_addr_r}; then "                        \
>> -			"bootefi ${kernel_addr_r} ${fdt_addr_r};"         \
>> -		"else "                                                   \
>> -			"bootefi ${kernel_addr_r} ${fdtcontroladdr};"     \
>> -		"fi\0"                                                    \
>> +		"bootefi ${kernel_addr_r} ${efi_fdt_addr};\0"		  \
>>  	\
>>  	"load_efi_dtb="                                                   \
>> -		"load ${devtype} ${devnum}:${distro_bootpart} "           \
>> -			"${fdt_addr_r} ${prefix}${efi_fdtfile}\0"         \
>> +		"load ${devtype} ${devnum}:${distro_bootpart} "		  \
>> +			"${fdt_addr_r} ${prefix}${efi_fdtfile}; "	  \
>> +		"if fdt addr ${fdt_addr_r}; then "			  \
>> +			"efi_fdt_addr=${fdt_addr_r}; "			  \
>> +		"fi;\0"							  \
>>  	\
>>  	"efi_dtb_prefixes=/ /dtb/ /dtb/current/\0"                        \
>> -	"scan_dev_for_efi="                                               \
>> -		"setenv efi_fdtfile ${fdtfile}; "                         \
>> +	"set_efi_fdt_addr="						  \
>> +		"efi_fdtfile=${fdtfile}; "                         \
>>  		BOOTENV_EFI_SET_FDTFILE_FALLBACK                          \
>>  		"for prefix in ${efi_dtb_prefixes}; do "                  \
>>  			"if test -e ${devtype} "                          \
>> @@ -151,19 +145,26 @@
>>  					"${prefix}${efi_fdtfile}; then "  \
>>  				"run load_efi_dtb; "                      \
>>  			"fi;"                                             \
>> -		"done;"                                                   \
>> +		"done;\0"                                                   \
>> +	\
>> +	"scan_dev_for_efi="                                               \
>>  		"if test -e ${devtype} ${devnum}:${distro_bootpart} "     \
>>  					"efi/boot/"BOOTEFI_NAME"; then "  \
>>  				"echo Found EFI removable media binary "  \
>>  					"efi/boot/"BOOTEFI_NAME"; "       \
>> +				"efi_fdt_addr=${fdtcontroladdr}; "	  \
>> +				"if test -n \"${fdtfile}\"; then "	  \
>> +					"run set_efi_fdt_addr; "	  \
>> +				"fi; "					  \
>>  				"run boot_efi_binary; "                   \
>>  				"echo EFI LOAD FAILED: continuing...; "   \
>> -		"fi; "                                                    \
>> -		"setenv efi_fdtfile\0"
>> +		"fi;\0"
>>  #define SCAN_DEV_FOR_EFI "run scan_dev_for_efi;"
>> +#define BOOT_EFI_BOOT_MANAGER "bootefi bootmgr;"
>>  #else
>>  #define BOOTENV_SHARED_EFI
>>  #define SCAN_DEV_FOR_EFI
>> +#define BOOT_EFI_BOOT_MANAGER
>>  #endif
>>  
>>  #ifdef CONFIG_SATA
>> @@ -409,6 +410,7 @@
>>  	BOOT_TARGET_DEVICES(BOOTENV_DEV)                                  \
>>  	\
>>  	"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT                      \
>> +		BOOT_EFI_BOOT_MANAGER					  \
> 
> The last-minute change may have introduced a problem.
> By moving "bootmgr" from scan_dev_for_efi" to here,
> grub fails to start a grub.cfg menu, saying
>   "error: no such device: /.disk/info."
> 
> Do you have any ideas?

I would guess that bootmgr doesn't set the loaded image target correctly
and before it just happened to work because there was a load command
before the bootmgr command?

https://github.com/u-boot/u-boot/blob/master/cmd/fs.c#L26


Alex
AKASHI Takahiro Oct. 23, 2018, 2:08 a.m. | #3
On Mon, Oct 22, 2018 at 08:42:32AM +0100, Alexander Graf wrote:
> 
> 
> On 22.10.18 08:22, AKASHI Takahiro wrote:
> > On Mon, Oct 22, 2018 at 01:40:05PM +0900, AKASHI Takahiro wrote:
> >> The current scenario for default UEFI booting, scan_dev_for_efi, has
> >> several issues:
> >> * load dtb dynamically even if its loacation (device) is not the same
> >>   as BOOTEFI_NAME binary's, (reported by Alex)
> >> * invoke 'bootmgr' only if BOOTEFI_NAME binary does exit even though
> >>   'bootmgr' can and should work independently whether or not the binary
> >>   exist,
> >> * in addition, invoke 'bootmgr' with dynamically-loaded dtb.
> >>   This behavior is not expected. (reported by Alex)
> >> * always assume that a 'fdtfile' variable is defined,
> >>   ("test -e ${devtype} ${devnum}:${distro_bootpart} "${prefix}${efi_fdtfile}"
> >>   always returns true even if fdtfile is NULL with prefix=="/".)
> >> * redundantly check for 'fdt_addr_r' in boot_efi_binary
> >>
> >> In this patch, all the issues above are sorted out.
> >> Please note that the default behavior can be customized with:
> >> 	fdtfile: a dtb file name
> >> 	efi_dtb_prefixes: a list of paths for searching for a dtb file
> >>
> >> (this feature does work even without this patch.)
> >>
> >> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >> ---
> >>  include/config_distro_bootcmd.h | 38 +++++++++++++++++----------------
> >>  1 file changed, 20 insertions(+), 18 deletions(-)
> >>
> >> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
> >> index 373fee78a999..256698309eb9 100644
> >> --- a/include/config_distro_bootcmd.h
> >> +++ b/include/config_distro_bootcmd.h
> >> @@ -115,7 +115,7 @@
> >>   */
> >>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK                                  \
> >>  	"if test -z \"${fdtfile}\" -a -n \"${soc}\"; then "               \
> >> -	  "setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; "           \
> >> +	  "efi_fdtfile=${soc}-${board}${boardver}.dtb; "           \
> >>  	"fi; "
> >>  #else
> >>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK
> >> @@ -124,26 +124,20 @@
> >>  
> >>  #define BOOTENV_SHARED_EFI                                                \
> >>  	"boot_efi_binary="                                                \
> >> -		"if fdt addr ${fdt_addr_r}; then "                        \
> >> -			"bootefi bootmgr ${fdt_addr_r};"                  \
> >> -		"else "                                                   \
> >> -			"bootefi bootmgr ${fdtcontroladdr};"              \
> >> -		"fi;"                                                     \
> >>  		"load ${devtype} ${devnum}:${distro_bootpart} "           \
> >>  			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
> >> -		"if fdt addr ${fdt_addr_r}; then "                        \
> >> -			"bootefi ${kernel_addr_r} ${fdt_addr_r};"         \
> >> -		"else "                                                   \
> >> -			"bootefi ${kernel_addr_r} ${fdtcontroladdr};"     \
> >> -		"fi\0"                                                    \
> >> +		"bootefi ${kernel_addr_r} ${efi_fdt_addr};\0"		  \
> >>  	\
> >>  	"load_efi_dtb="                                                   \
> >> -		"load ${devtype} ${devnum}:${distro_bootpart} "           \
> >> -			"${fdt_addr_r} ${prefix}${efi_fdtfile}\0"         \
> >> +		"load ${devtype} ${devnum}:${distro_bootpart} "		  \
> >> +			"${fdt_addr_r} ${prefix}${efi_fdtfile}; "	  \
> >> +		"if fdt addr ${fdt_addr_r}; then "			  \
> >> +			"efi_fdt_addr=${fdt_addr_r}; "			  \
> >> +		"fi;\0"							  \
> >>  	\
> >>  	"efi_dtb_prefixes=/ /dtb/ /dtb/current/\0"                        \
> >> -	"scan_dev_for_efi="                                               \
> >> -		"setenv efi_fdtfile ${fdtfile}; "                         \
> >> +	"set_efi_fdt_addr="						  \
> >> +		"efi_fdtfile=${fdtfile}; "                         \
> >>  		BOOTENV_EFI_SET_FDTFILE_FALLBACK                          \
> >>  		"for prefix in ${efi_dtb_prefixes}; do "                  \
> >>  			"if test -e ${devtype} "                          \
> >> @@ -151,19 +145,26 @@
> >>  					"${prefix}${efi_fdtfile}; then "  \
> >>  				"run load_efi_dtb; "                      \
> >>  			"fi;"                                             \
> >> -		"done;"                                                   \
> >> +		"done;\0"                                                   \
> >> +	\
> >> +	"scan_dev_for_efi="                                               \
> >>  		"if test -e ${devtype} ${devnum}:${distro_bootpart} "     \
> >>  					"efi/boot/"BOOTEFI_NAME"; then "  \
> >>  				"echo Found EFI removable media binary "  \
> >>  					"efi/boot/"BOOTEFI_NAME"; "       \
> >> +				"efi_fdt_addr=${fdtcontroladdr}; "	  \
> >> +				"if test -n \"${fdtfile}\"; then "	  \
> >> +					"run set_efi_fdt_addr; "	  \
> >> +				"fi; "					  \
> >>  				"run boot_efi_binary; "                   \
> >>  				"echo EFI LOAD FAILED: continuing...; "   \
> >> -		"fi; "                                                    \
> >> -		"setenv efi_fdtfile\0"
> >> +		"fi;\0"
> >>  #define SCAN_DEV_FOR_EFI "run scan_dev_for_efi;"
> >> +#define BOOT_EFI_BOOT_MANAGER "bootefi bootmgr;"
> >>  #else
> >>  #define BOOTENV_SHARED_EFI
> >>  #define SCAN_DEV_FOR_EFI
> >> +#define BOOT_EFI_BOOT_MANAGER
> >>  #endif
> >>  
> >>  #ifdef CONFIG_SATA
> >> @@ -409,6 +410,7 @@
> >>  	BOOT_TARGET_DEVICES(BOOTENV_DEV)                                  \
> >>  	\
> >>  	"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT                      \
> >> +		BOOT_EFI_BOOT_MANAGER					  \
> > 
> > The last-minute change may have introduced a problem.
> > By moving "bootmgr" from scan_dev_for_efi" to here,
> > grub fails to start a grub.cfg menu, saying
> >   "error: no such device: /.disk/info."
> > 
> > Do you have any ideas?
> 
> I would guess that bootmgr doesn't set the loaded image target correctly
> and before it just happened to work because there was a load command
> before the bootmgr command?

The root cause was that efi_init_obj_list(), particularly efi_disk_register(),
is executed only once.
In my case, efi bootmgr is called before "usb start" in scan_dev_for_efi,
and any USB devices will not be added to efi object list forever.
Therefore, later on, grub itself can start but cannot detect/access its own
boot device (USB mass storage) via efi interface.

I think we can fix this problem in several ways:
1. run all 'device-scanning' commands, like "usb start" and "scsi scan,"
   before calling bootmgr in distro_bootcmd,
2. modify efi_obj_init_list() to check and register newly-detected devices,
3. add a device to efi object list dynamically whenever a 'device-scanning'
   command detects one,
4. search and check for a device on-the-fly with each efi device path
   (or handle?) specified in efi interface

What do you think?

-Takahiro Akashi

> https://github.com/u-boot/u-boot/blob/master/cmd/fs.c#L26
> 
> 
> Alex
Alexander Graf Oct. 23, 2018, 7:36 a.m. | #4
On 23.10.18 03:08, AKASHI Takahiro wrote:
> On Mon, Oct 22, 2018 at 08:42:32AM +0100, Alexander Graf wrote:
>>
>>
>> On 22.10.18 08:22, AKASHI Takahiro wrote:
>>> On Mon, Oct 22, 2018 at 01:40:05PM +0900, AKASHI Takahiro wrote:
>>>> The current scenario for default UEFI booting, scan_dev_for_efi, has
>>>> several issues:
>>>> * load dtb dynamically even if its loacation (device) is not the same
>>>>   as BOOTEFI_NAME binary's, (reported by Alex)
>>>> * invoke 'bootmgr' only if BOOTEFI_NAME binary does exit even though
>>>>   'bootmgr' can and should work independently whether or not the binary
>>>>   exist,
>>>> * in addition, invoke 'bootmgr' with dynamically-loaded dtb.
>>>>   This behavior is not expected. (reported by Alex)
>>>> * always assume that a 'fdtfile' variable is defined,
>>>>   ("test -e ${devtype} ${devnum}:${distro_bootpart} "${prefix}${efi_fdtfile}"
>>>>   always returns true even if fdtfile is NULL with prefix=="/".)
>>>> * redundantly check for 'fdt_addr_r' in boot_efi_binary
>>>>
>>>> In this patch, all the issues above are sorted out.
>>>> Please note that the default behavior can be customized with:
>>>> 	fdtfile: a dtb file name
>>>> 	efi_dtb_prefixes: a list of paths for searching for a dtb file
>>>>
>>>> (this feature does work even without this patch.)
>>>>
>>>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>>>> ---
>>>>  include/config_distro_bootcmd.h | 38 +++++++++++++++++----------------
>>>>  1 file changed, 20 insertions(+), 18 deletions(-)
>>>>
>>>> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
>>>> index 373fee78a999..256698309eb9 100644
>>>> --- a/include/config_distro_bootcmd.h
>>>> +++ b/include/config_distro_bootcmd.h
>>>> @@ -115,7 +115,7 @@
>>>>   */
>>>>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK                                  \
>>>>  	"if test -z \"${fdtfile}\" -a -n \"${soc}\"; then "               \
>>>> -	  "setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; "           \
>>>> +	  "efi_fdtfile=${soc}-${board}${boardver}.dtb; "           \
>>>>  	"fi; "
>>>>  #else
>>>>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK
>>>> @@ -124,26 +124,20 @@
>>>>  
>>>>  #define BOOTENV_SHARED_EFI                                                \
>>>>  	"boot_efi_binary="                                                \
>>>> -		"if fdt addr ${fdt_addr_r}; then "                        \
>>>> -			"bootefi bootmgr ${fdt_addr_r};"                  \
>>>> -		"else "                                                   \
>>>> -			"bootefi bootmgr ${fdtcontroladdr};"              \
>>>> -		"fi;"                                                     \
>>>>  		"load ${devtype} ${devnum}:${distro_bootpart} "           \
>>>>  			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
>>>> -		"if fdt addr ${fdt_addr_r}; then "                        \
>>>> -			"bootefi ${kernel_addr_r} ${fdt_addr_r};"         \
>>>> -		"else "                                                   \
>>>> -			"bootefi ${kernel_addr_r} ${fdtcontroladdr};"     \
>>>> -		"fi\0"                                                    \
>>>> +		"bootefi ${kernel_addr_r} ${efi_fdt_addr};\0"		  \
>>>>  	\
>>>>  	"load_efi_dtb="                                                   \
>>>> -		"load ${devtype} ${devnum}:${distro_bootpart} "           \
>>>> -			"${fdt_addr_r} ${prefix}${efi_fdtfile}\0"         \
>>>> +		"load ${devtype} ${devnum}:${distro_bootpart} "		  \
>>>> +			"${fdt_addr_r} ${prefix}${efi_fdtfile}; "	  \
>>>> +		"if fdt addr ${fdt_addr_r}; then "			  \
>>>> +			"efi_fdt_addr=${fdt_addr_r}; "			  \
>>>> +		"fi;\0"							  \
>>>>  	\
>>>>  	"efi_dtb_prefixes=/ /dtb/ /dtb/current/\0"                        \
>>>> -	"scan_dev_for_efi="                                               \
>>>> -		"setenv efi_fdtfile ${fdtfile}; "                         \
>>>> +	"set_efi_fdt_addr="						  \
>>>> +		"efi_fdtfile=${fdtfile}; "                         \
>>>>  		BOOTENV_EFI_SET_FDTFILE_FALLBACK                          \
>>>>  		"for prefix in ${efi_dtb_prefixes}; do "                  \
>>>>  			"if test -e ${devtype} "                          \
>>>> @@ -151,19 +145,26 @@
>>>>  					"${prefix}${efi_fdtfile}; then "  \
>>>>  				"run load_efi_dtb; "                      \
>>>>  			"fi;"                                             \
>>>> -		"done;"                                                   \
>>>> +		"done;\0"                                                   \
>>>> +	\
>>>> +	"scan_dev_for_efi="                                               \
>>>>  		"if test -e ${devtype} ${devnum}:${distro_bootpart} "     \
>>>>  					"efi/boot/"BOOTEFI_NAME"; then "  \
>>>>  				"echo Found EFI removable media binary "  \
>>>>  					"efi/boot/"BOOTEFI_NAME"; "       \
>>>> +				"efi_fdt_addr=${fdtcontroladdr}; "	  \
>>>> +				"if test -n \"${fdtfile}\"; then "	  \
>>>> +					"run set_efi_fdt_addr; "	  \
>>>> +				"fi; "					  \
>>>>  				"run boot_efi_binary; "                   \
>>>>  				"echo EFI LOAD FAILED: continuing...; "   \
>>>> -		"fi; "                                                    \
>>>> -		"setenv efi_fdtfile\0"
>>>> +		"fi;\0"
>>>>  #define SCAN_DEV_FOR_EFI "run scan_dev_for_efi;"
>>>> +#define BOOT_EFI_BOOT_MANAGER "bootefi bootmgr;"
>>>>  #else
>>>>  #define BOOTENV_SHARED_EFI
>>>>  #define SCAN_DEV_FOR_EFI
>>>> +#define BOOT_EFI_BOOT_MANAGER
>>>>  #endif
>>>>  
>>>>  #ifdef CONFIG_SATA
>>>> @@ -409,6 +410,7 @@
>>>>  	BOOT_TARGET_DEVICES(BOOTENV_DEV)                                  \
>>>>  	\
>>>>  	"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT                      \
>>>> +		BOOT_EFI_BOOT_MANAGER					  \
>>>
>>> The last-minute change may have introduced a problem.
>>> By moving "bootmgr" from scan_dev_for_efi" to here,
>>> grub fails to start a grub.cfg menu, saying
>>>   "error: no such device: /.disk/info."
>>>
>>> Do you have any ideas?
>>
>> I would guess that bootmgr doesn't set the loaded image target correctly
>> and before it just happened to work because there was a load command
>> before the bootmgr command?
> 
> The root cause was that efi_init_obj_list(), particularly efi_disk_register(),
> is executed only once.
> In my case, efi bootmgr is called before "usb start" in scan_dev_for_efi,
> and any USB devices will not be added to efi object list forever.
> Therefore, later on, grub itself can start but cannot detect/access its own
> boot device (USB mass storage) via efi interface.
> 
> I think we can fix this problem in several ways:
> 1. run all 'device-scanning' commands, like "usb start" and "scsi scan,"
>    before calling bootmgr in distro_bootcmd,

This would work, though it's slightly complicated - hm :/.

> 2. modify efi_obj_init_list() to check and register newly-detected devices,

That won't work, because then efibootmgr won't be able to boot from USB, no?

> 3. add a device to efi object list dynamically whenever a 'device-scanning'
>    command detects one,

Same here I assume.

> 4. search and check for a device on-the-fly with each efi device path
>    (or handle?) specified in efi interface

That won't work either, because we simply don't initialize USB in the
efibootmgr case, so there won't be anything on the fly ;).

> 
> What do you think?

I guess one of your options above mentions this and I just missed it,
but I think we'll have to find out what to initialize in the efibootmgr
command based on the device path we're trying to execute and then
initialize that respective subsystem.

So if we see that the device path involves USB, we need to run "usb
start" from within the efibootmgr code.


Alex
AKASHI Takahiro Oct. 23, 2018, 8:01 a.m. | #5
On Tue, Oct 23, 2018 at 08:36:58AM +0100, Alexander Graf wrote:
> 
> 
> On 23.10.18 03:08, AKASHI Takahiro wrote:
> > On Mon, Oct 22, 2018 at 08:42:32AM +0100, Alexander Graf wrote:
> >>
> >>
> >> On 22.10.18 08:22, AKASHI Takahiro wrote:
> >>> On Mon, Oct 22, 2018 at 01:40:05PM +0900, AKASHI Takahiro wrote:
> >>>> The current scenario for default UEFI booting, scan_dev_for_efi, has
> >>>> several issues:
> >>>> * load dtb dynamically even if its loacation (device) is not the same
> >>>>   as BOOTEFI_NAME binary's, (reported by Alex)
> >>>> * invoke 'bootmgr' only if BOOTEFI_NAME binary does exit even though
> >>>>   'bootmgr' can and should work independently whether or not the binary
> >>>>   exist,
> >>>> * in addition, invoke 'bootmgr' with dynamically-loaded dtb.
> >>>>   This behavior is not expected. (reported by Alex)
> >>>> * always assume that a 'fdtfile' variable is defined,
> >>>>   ("test -e ${devtype} ${devnum}:${distro_bootpart} "${prefix}${efi_fdtfile}"
> >>>>   always returns true even if fdtfile is NULL with prefix=="/".)
> >>>> * redundantly check for 'fdt_addr_r' in boot_efi_binary
> >>>>
> >>>> In this patch, all the issues above are sorted out.
> >>>> Please note that the default behavior can be customized with:
> >>>> 	fdtfile: a dtb file name
> >>>> 	efi_dtb_prefixes: a list of paths for searching for a dtb file
> >>>>
> >>>> (this feature does work even without this patch.)
> >>>>
> >>>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >>>> ---
> >>>>  include/config_distro_bootcmd.h | 38 +++++++++++++++++----------------
> >>>>  1 file changed, 20 insertions(+), 18 deletions(-)
> >>>>
> >>>> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
> >>>> index 373fee78a999..256698309eb9 100644
> >>>> --- a/include/config_distro_bootcmd.h
> >>>> +++ b/include/config_distro_bootcmd.h
> >>>> @@ -115,7 +115,7 @@
> >>>>   */
> >>>>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK                                  \
> >>>>  	"if test -z \"${fdtfile}\" -a -n \"${soc}\"; then "               \
> >>>> -	  "setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; "           \
> >>>> +	  "efi_fdtfile=${soc}-${board}${boardver}.dtb; "           \
> >>>>  	"fi; "
> >>>>  #else
> >>>>  #define BOOTENV_EFI_SET_FDTFILE_FALLBACK
> >>>> @@ -124,26 +124,20 @@
> >>>>  
> >>>>  #define BOOTENV_SHARED_EFI                                                \
> >>>>  	"boot_efi_binary="                                                \
> >>>> -		"if fdt addr ${fdt_addr_r}; then "                        \
> >>>> -			"bootefi bootmgr ${fdt_addr_r};"                  \
> >>>> -		"else "                                                   \
> >>>> -			"bootefi bootmgr ${fdtcontroladdr};"              \
> >>>> -		"fi;"                                                     \
> >>>>  		"load ${devtype} ${devnum}:${distro_bootpart} "           \
> >>>>  			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
> >>>> -		"if fdt addr ${fdt_addr_r}; then "                        \
> >>>> -			"bootefi ${kernel_addr_r} ${fdt_addr_r};"         \
> >>>> -		"else "                                                   \
> >>>> -			"bootefi ${kernel_addr_r} ${fdtcontroladdr};"     \
> >>>> -		"fi\0"                                                    \
> >>>> +		"bootefi ${kernel_addr_r} ${efi_fdt_addr};\0"		  \
> >>>>  	\
> >>>>  	"load_efi_dtb="                                                   \
> >>>> -		"load ${devtype} ${devnum}:${distro_bootpart} "           \
> >>>> -			"${fdt_addr_r} ${prefix}${efi_fdtfile}\0"         \
> >>>> +		"load ${devtype} ${devnum}:${distro_bootpart} "		  \
> >>>> +			"${fdt_addr_r} ${prefix}${efi_fdtfile}; "	  \
> >>>> +		"if fdt addr ${fdt_addr_r}; then "			  \
> >>>> +			"efi_fdt_addr=${fdt_addr_r}; "			  \
> >>>> +		"fi;\0"							  \
> >>>>  	\
> >>>>  	"efi_dtb_prefixes=/ /dtb/ /dtb/current/\0"                        \
> >>>> -	"scan_dev_for_efi="                                               \
> >>>> -		"setenv efi_fdtfile ${fdtfile}; "                         \
> >>>> +	"set_efi_fdt_addr="						  \
> >>>> +		"efi_fdtfile=${fdtfile}; "                         \
> >>>>  		BOOTENV_EFI_SET_FDTFILE_FALLBACK                          \
> >>>>  		"for prefix in ${efi_dtb_prefixes}; do "                  \
> >>>>  			"if test -e ${devtype} "                          \
> >>>> @@ -151,19 +145,26 @@
> >>>>  					"${prefix}${efi_fdtfile}; then "  \
> >>>>  				"run load_efi_dtb; "                      \
> >>>>  			"fi;"                                             \
> >>>> -		"done;"                                                   \
> >>>> +		"done;\0"                                                   \
> >>>> +	\
> >>>> +	"scan_dev_for_efi="                                               \
> >>>>  		"if test -e ${devtype} ${devnum}:${distro_bootpart} "     \
> >>>>  					"efi/boot/"BOOTEFI_NAME"; then "  \
> >>>>  				"echo Found EFI removable media binary "  \
> >>>>  					"efi/boot/"BOOTEFI_NAME"; "       \
> >>>> +				"efi_fdt_addr=${fdtcontroladdr}; "	  \
> >>>> +				"if test -n \"${fdtfile}\"; then "	  \
> >>>> +					"run set_efi_fdt_addr; "	  \
> >>>> +				"fi; "					  \
> >>>>  				"run boot_efi_binary; "                   \
> >>>>  				"echo EFI LOAD FAILED: continuing...; "   \
> >>>> -		"fi; "                                                    \
> >>>> -		"setenv efi_fdtfile\0"
> >>>> +		"fi;\0"
> >>>>  #define SCAN_DEV_FOR_EFI "run scan_dev_for_efi;"
> >>>> +#define BOOT_EFI_BOOT_MANAGER "bootefi bootmgr;"
> >>>>  #else
> >>>>  #define BOOTENV_SHARED_EFI
> >>>>  #define SCAN_DEV_FOR_EFI
> >>>> +#define BOOT_EFI_BOOT_MANAGER
> >>>>  #endif
> >>>>  
> >>>>  #ifdef CONFIG_SATA
> >>>> @@ -409,6 +410,7 @@
> >>>>  	BOOT_TARGET_DEVICES(BOOTENV_DEV)                                  \
> >>>>  	\
> >>>>  	"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT                      \
> >>>> +		BOOT_EFI_BOOT_MANAGER					  \
> >>>
> >>> The last-minute change may have introduced a problem.
> >>> By moving "bootmgr" from scan_dev_for_efi" to here,
> >>> grub fails to start a grub.cfg menu, saying
> >>>   "error: no such device: /.disk/info."
> >>>
> >>> Do you have any ideas?
> >>
> >> I would guess that bootmgr doesn't set the loaded image target correctly
> >> and before it just happened to work because there was a load command
> >> before the bootmgr command?
> > 
> > The root cause was that efi_init_obj_list(), particularly efi_disk_register(),
> > is executed only once.
> > In my case, efi bootmgr is called before "usb start" in scan_dev_for_efi,
> > and any USB devices will not be added to efi object list forever.
> > Therefore, later on, grub itself can start but cannot detect/access its own
> > boot device (USB mass storage) via efi interface.
> > 
> > I think we can fix this problem in several ways:
> > 1. run all 'device-scanning' commands, like "usb start" and "scsi scan,"
> >    before calling bootmgr in distro_bootcmd,
> 
> This would work, though it's slightly complicated - hm :/.
> 
> > 2. modify efi_obj_init_list() to check and register newly-detected devices,
> 
> That won't work, because then efibootmgr won't be able to boot from USB, no?
> 
> > 3. add a device to efi object list dynamically whenever a 'device-scanning'
> >    command detects one,
> 
> Same here I assume.
> 
> > 4. search and check for a device on-the-fly with each efi device path
> >    (or handle?) specified in efi interface
> 
> That won't work either, because we simply don't initialize USB in the
> efibootmgr case, so there won't be anything on the fly ;).
> 
> > 
> > What do you think?
> 
> I guess one of your options above mentions this and I just missed it,
> but I think we'll have to find out what to initialize in the efibootmgr
> command based on the device path we're trying to execute and then
> initialize that respective subsystem.
> 
> So if we see that the device path involves USB, we need to run "usb
> start" from within the efibootmgr code.

I don't think that this behavior is consistent with other U-boot commands.
For example, "load usb 0:1 ..." doesn't work unless we run "usb start"
first. Efi bootmgr should not be an exception.

-Takahiro Akashi

> 
> Alex

Patch

diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index 373fee78a999..256698309eb9 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -115,7 +115,7 @@ 
  */
 #define BOOTENV_EFI_SET_FDTFILE_FALLBACK                                  \
 	"if test -z \"${fdtfile}\" -a -n \"${soc}\"; then "               \
-	  "setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; "           \
+	  "efi_fdtfile=${soc}-${board}${boardver}.dtb; "           \
 	"fi; "
 #else
 #define BOOTENV_EFI_SET_FDTFILE_FALLBACK
@@ -124,26 +124,20 @@ 
 
 #define BOOTENV_SHARED_EFI                                                \
 	"boot_efi_binary="                                                \
-		"if fdt addr ${fdt_addr_r}; then "                        \
-			"bootefi bootmgr ${fdt_addr_r};"                  \
-		"else "                                                   \
-			"bootefi bootmgr ${fdtcontroladdr};"              \
-		"fi;"                                                     \
 		"load ${devtype} ${devnum}:${distro_bootpart} "           \
 			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
-		"if fdt addr ${fdt_addr_r}; then "                        \
-			"bootefi ${kernel_addr_r} ${fdt_addr_r};"         \
-		"else "                                                   \
-			"bootefi ${kernel_addr_r} ${fdtcontroladdr};"     \
-		"fi\0"                                                    \
+		"bootefi ${kernel_addr_r} ${efi_fdt_addr};\0"		  \
 	\
 	"load_efi_dtb="                                                   \
-		"load ${devtype} ${devnum}:${distro_bootpart} "           \
-			"${fdt_addr_r} ${prefix}${efi_fdtfile}\0"         \
+		"load ${devtype} ${devnum}:${distro_bootpart} "		  \
+			"${fdt_addr_r} ${prefix}${efi_fdtfile}; "	  \
+		"if fdt addr ${fdt_addr_r}; then "			  \
+			"efi_fdt_addr=${fdt_addr_r}; "			  \
+		"fi;\0"							  \
 	\
 	"efi_dtb_prefixes=/ /dtb/ /dtb/current/\0"                        \
-	"scan_dev_for_efi="                                               \
-		"setenv efi_fdtfile ${fdtfile}; "                         \
+	"set_efi_fdt_addr="						  \
+		"efi_fdtfile=${fdtfile}; "                         \
 		BOOTENV_EFI_SET_FDTFILE_FALLBACK                          \
 		"for prefix in ${efi_dtb_prefixes}; do "                  \
 			"if test -e ${devtype} "                          \
@@ -151,19 +145,26 @@ 
 					"${prefix}${efi_fdtfile}; then "  \
 				"run load_efi_dtb; "                      \
 			"fi;"                                             \
-		"done;"                                                   \
+		"done;\0"                                                   \
+	\
+	"scan_dev_for_efi="                                               \
 		"if test -e ${devtype} ${devnum}:${distro_bootpart} "     \
 					"efi/boot/"BOOTEFI_NAME"; then "  \
 				"echo Found EFI removable media binary "  \
 					"efi/boot/"BOOTEFI_NAME"; "       \
+				"efi_fdt_addr=${fdtcontroladdr}; "	  \
+				"if test -n \"${fdtfile}\"; then "	  \
+					"run set_efi_fdt_addr; "	  \
+				"fi; "					  \
 				"run boot_efi_binary; "                   \
 				"echo EFI LOAD FAILED: continuing...; "   \
-		"fi; "                                                    \
-		"setenv efi_fdtfile\0"
+		"fi;\0"
 #define SCAN_DEV_FOR_EFI "run scan_dev_for_efi;"
+#define BOOT_EFI_BOOT_MANAGER "bootefi bootmgr;"
 #else
 #define BOOTENV_SHARED_EFI
 #define SCAN_DEV_FOR_EFI
+#define BOOT_EFI_BOOT_MANAGER
 #endif
 
 #ifdef CONFIG_SATA
@@ -409,6 +410,7 @@ 
 	BOOT_TARGET_DEVICES(BOOTENV_DEV)                                  \
 	\
 	"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT                      \
+		BOOT_EFI_BOOT_MANAGER					  \
 		"for target in ${boot_targets}; do "                      \
 			"run bootcmd_${target}; "                         \
 		"done\0"