|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH-4.16 v4] xen/efi: Fix Grub2 boot on arm64
Hi Luca,
> On 5 Nov 2021, at 13:07, Luca Fancellu <Luca.Fancellu@xxxxxxx> wrote:
>
> The code introduced by commit a1743fc3a9fe9b68c265c45264dddf214fd9b882
> ("arm/efi: Use dom0less configuration when using EFI boot") is
> introducing a problem to boot Xen using Grub2 on ARM machine using EDK2.
>
> Despite UEFI specification, EDK2+Grub2 is returning a NULL DeviceHandle
> inside the interface given by the LOADED_IMAGE_PROTOCOL service, this
> handle is used later by efi_bs->HandleProtocol(...) inside
> get_parent_handle(...) when requesting the SIMPLE_FILE_SYSTEM_PROTOCOL
> interface, causing Xen to stop the boot because of an EFI_INVALID_PARAMETER
> error.
>
> Before the commit above, the function was never called because the
> logic was skipping the call when there were multiboot modules in the
> DT because the filesystem was never used and the bootloader had
> put in place all the right modules in memory and the addresses
> in the DT.
>
> To fix the problem the old logic is put back in place. Because the handle
> was given to the efi_check_dt_boot(...), but the revert put the handle
> out of scope, the signature of the function is changed to use an
> EFI_LOADED_IMAGE handle and request the EFI_FILE_HANDLE only when
> needed (module found using xen,uefi-binary).
>
> Another problem is found when the UEFI stub tries to check if Dom0
> image or DomUs are present.
> The logic doesn't work when the UEFI stub is not responsible to load
> any modules, so the efi_check_dt_boot(...) return value is modified
> to return the number of multiboot module found and not only the number
> of module loaded by the stub.
> Taking the occasion to update the comment in handle_module_node(...)
> to explain why we return success even if xen,uefi-binary is not found.
>
> Fixes: a1743fc3a9 ("arm/efi: Use dom0less configuration when using EFI boot")
> Signed-off-by: Luca Fancellu <luca.fancellu@xxxxxxx>
> Release-Acked-by: Ian Jackson <iwj@xxxxxxxxxxxxxx>
> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
Reviewed-by: Bertrand Marquis <bertrand.marquis@xxxxxxx>
Cheers
Bertrand
> ---
> Justification for integration in 4.16:
> Upside: allow booting xen from grub on arm64 when the stub doesn't load
> any module.
> Downside: It's affecting the EFI boot path.
> Risk: It's not affecting x86 arch that works the same way as before.
> If something is wrong it creates a problem on early boot and not at
> runtime, so risk is low.
>
> Tested in this configurations:
> - Bootloader loads modules and specify them as multiboot modules in DT:
> * combination of Dom0, DomUs, Dom0 and DomUs
> - DT specifies multiboot modules in DT using xen,uefi-binary property:
> * combination of Dom0, DomUs, Dom0 and DomUs
> - Bootloader loads a Dom0 module and appends it as multiboot module in DT,
> other multiboot modules are listed for DomUs using xen,uefi-binary
> - No multiboot modules in DT and no kernel entry in cfg file:
> * proper error thrown
>
> Changes in v4:
> - dir_handle scope reverted back (Jan)
> Changes in v3:
> - Revert back to the logic that protects get_parent_handle(...) (Jan)
> - Changed efi_check_dt_boot(...) to use a EFI_LOADED_IMAGE handle and
> request, along the call stack, the parent dir handle only when needed.
> Changes in v2:
> - Changed comment on DeviceHandle NULL (Jan)
> - Removed fatal condition on handle NULL (Jan)
> - Add more info about the EDK2+Grub2 issue to the commit msg (Jan)
> - Removed modules_found from function signature and pass everything
> on return (Stefano)
> - Improved comment in handle_module_node
>
> ---
> xen/arch/arm/efi/efi-boot.h | 61 ++++++++++++++++++++++++-------------
> xen/common/efi/boot.c | 18 ++++++-----
> 2 files changed, 50 insertions(+), 29 deletions(-)
>
> diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h
> index 8b88dd26a5..458cfbbed4 100644
> --- a/xen/arch/arm/efi/efi-boot.h
> +++ b/xen/arch/arm/efi/efi-boot.h
> @@ -44,17 +44,17 @@ void __flush_dcache_area(const void *vaddr, unsigned long
> size);
>
> static int get_module_file_index(const char *name, unsigned int name_len);
> static void PrintMessage(const CHAR16 *s);
> -static int allocate_module_file(EFI_FILE_HANDLE dir_handle,
> +static int allocate_module_file(EFI_LOADED_IMAGE *loaded_image,
> const char *name,
> unsigned int name_len);
> -static int handle_module_node(EFI_FILE_HANDLE dir_handle,
> +static int handle_module_node(EFI_LOADED_IMAGE *loaded_image,
> int module_node_offset,
> int reg_addr_cells,
> int reg_size_cells,
> bool is_domu_module);
> -static int handle_dom0less_domain_node(EFI_FILE_HANDLE dir_handle,
> +static int handle_dom0less_domain_node(EFI_LOADED_IMAGE *loaded_image,
> int domain_node);
> -static int efi_check_dt_boot(EFI_FILE_HANDLE dir_handle);
> +static int efi_check_dt_boot(EFI_LOADED_IMAGE *loaded_image);
>
> #define DEVICE_TREE_GUID \
> {0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}}
> @@ -647,11 +647,13 @@ static void __init PrintMessage(const CHAR16 *s)
> * This function allocates a binary and keeps track of its name, it returns
> the
> * index of the file in the modules array or a negative number on error.
> */
> -static int __init allocate_module_file(EFI_FILE_HANDLE dir_handle,
> +static int __init allocate_module_file(EFI_LOADED_IMAGE *loaded_image,
> const char *name,
> unsigned int name_len)
> {
> + EFI_FILE_HANDLE dir_handle;
> module_name *file_name;
> + CHAR16 *fname;
> union string module_name;
> int ret;
>
> @@ -683,9 +685,14 @@ static int __init allocate_module_file(EFI_FILE_HANDLE
> dir_handle,
> strlcpy(file_name->name, name, name_len + 1);
> file_name->name_len = name_len;
>
> + /* Get the file system interface. */
> + dir_handle = get_parent_handle(loaded_image, &fname);
> +
> /* Load the binary in memory */
> read_file(dir_handle, s2w(&module_name), &module_binary, NULL);
>
> + dir_handle->Close(dir_handle);
> +
> /* Save address and size */
> file_name->addr = module_binary.addr;
> file_name->size = module_binary.size;
> @@ -702,8 +709,9 @@ static int __init allocate_module_file(EFI_FILE_HANDLE
> dir_handle,
> * This function checks for the presence of the xen,uefi-binary property in
> the
> * module, if found it loads the binary as module and sets the right address
> * for the reg property into the module DT node.
> + * Returns 1 if module is multiboot,module, 0 if not, < 0 on error
> */
> -static int __init handle_module_node(EFI_FILE_HANDLE dir_handle,
> +static int __init handle_module_node(EFI_LOADED_IMAGE *loaded_image,
> int module_node_offset,
> int reg_addr_cells,
> int reg_size_cells,
> @@ -730,13 +738,13 @@ static int __init handle_module_node(EFI_FILE_HANDLE
> dir_handle,
> &uefi_name_len);
>
> if ( !uefi_name_prop )
> - /* Property not found */
> - return 0;
> + /* Property not found, but signal this is a multiboot,module */
> + return 1;
>
> file_idx = get_module_file_index(uefi_name_prop, uefi_name_len);
> if ( file_idx < 0 )
> {
> - file_idx = allocate_module_file(dir_handle, uefi_name_prop,
> + file_idx = allocate_module_file(loaded_image, uefi_name_prop,
> uefi_name_len);
> if ( file_idx < 0 )
> return file_idx;
> @@ -795,19 +803,20 @@ static int __init handle_module_node(EFI_FILE_HANDLE
> dir_handle,
> }
> }
>
> - return 0;
> + return 1;
> }
>
> /*
> * This function checks for boot modules under the domU guest domain node
> * in the DT.
> - * Returns 0 on success, negative number on error.
> + * Returns number of multiboot,module found or negative number on error.
> */
> -static int __init handle_dom0less_domain_node(EFI_FILE_HANDLE dir_handle,
> +static int __init handle_dom0less_domain_node(EFI_LOADED_IMAGE *loaded_image,
> int domain_node)
> {
> int module_node, addr_cells, size_cells, len;
> const struct fdt_property *prop;
> + unsigned int mb_modules_found = 0;
>
> /* Get #address-cells and #size-cells from domain node */
> prop = fdt_get_property(fdt, domain_node, "#address-cells", &len);
> @@ -833,24 +842,26 @@ static int __init
> handle_dom0less_domain_node(EFI_FILE_HANDLE dir_handle,
> module_node > 0;
> module_node = fdt_next_subnode(fdt, module_node) )
> {
> - int ret = handle_module_node(dir_handle, module_node, addr_cells,
> + int ret = handle_module_node(loaded_image, module_node, addr_cells,
> size_cells, true);
> if ( ret < 0 )
> return ret;
> +
> + mb_modules_found += ret;
> }
>
> - return 0;
> + return mb_modules_found;
> }
>
> /*
> * This function checks for xen domain nodes under the /chosen node for
> possible
> * dom0 and domU guests to be loaded.
> - * Returns the number of modules loaded or a negative number for error.
> + * Returns the number of multiboot modules found or a negative number for
> error.
> */
> -static int __init efi_check_dt_boot(EFI_FILE_HANDLE dir_handle)
> +static int __init efi_check_dt_boot(EFI_LOADED_IMAGE *loaded_image)
> {
> int chosen, node, addr_len, size_len;
> - unsigned int i = 0;
> + unsigned int i = 0, modules_found = 0;
>
> /* Check for the chosen node in the current DTB */
> chosen = setup_chosen_node(fdt, &addr_len, &size_len);
> @@ -865,15 +876,23 @@ static int __init efi_check_dt_boot(EFI_FILE_HANDLE
> dir_handle)
> node > 0;
> node = fdt_next_subnode(fdt, node) )
> {
> + int ret;
> +
> if ( !fdt_node_check_compatible(fdt, node, "xen,domain") )
> {
> /* Found a node with compatible xen,domain; handle this node. */
> - if ( handle_dom0less_domain_node(dir_handle, node) < 0 )
> + ret = handle_dom0less_domain_node(loaded_image, node);
> + if ( ret < 0 )
> return ERROR_DT_MODULE_DOMU;
> }
> - else if ( handle_module_node(dir_handle, node, addr_len, size_len,
> - false) < 0 )
> + else
> + {
> + ret = handle_module_node(loaded_image, node, addr_len, size_len,
> + false);
> + if ( ret < 0 )
> return ERROR_DT_MODULE_DOM0;
> + }
> + modules_found += ret;
> }
>
> /* Free boot modules file names if any */
> @@ -883,7 +902,7 @@ static int __init efi_check_dt_boot(EFI_FILE_HANDLE
> dir_handle)
> efi_bs->FreePool(modules[i].name);
> }
>
> - return modules_idx;
> + return modules_found;
> }
>
> static void __init efi_arch_cpu(void)
> diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c
> index 392ff3ac9b..8fd5e2d078 100644
> --- a/xen/common/efi/boot.c
> +++ b/xen/common/efi/boot.c
> @@ -121,6 +121,8 @@ static char *get_value(const struct file *cfg, const char
> *section,
> static char *split_string(char *s);
> static CHAR16 *s2w(union string *str);
> static char *w2s(const union string *str);
> +static EFI_FILE_HANDLE get_parent_handle(EFI_LOADED_IMAGE *loaded_image,
> + CHAR16 **leaf);
> static bool read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name,
> struct file *file, const char *options);
> static bool read_section(const EFI_LOADED_IMAGE *image, const CHAR16 *name,
> @@ -167,7 +169,7 @@ static void __init PrintErr(const CHAR16 *s)
> }
>
> #ifndef CONFIG_HAS_DEVICE_TREE
> -static int __init efi_check_dt_boot(EFI_FILE_HANDLE dir_handle)
> +static int __init efi_check_dt_boot(EFI_LOADED_IMAGE *loaded_image)
> {
> return 0;
> }
> @@ -1144,7 +1146,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE
> *SystemTable)
> const char *option_str;
> bool use_cfg_file;
> int dt_modules_found;
> - EFI_FILE_HANDLE dir_handle;
>
> __set_bit(EFI_BOOT, &efi_flags);
> __set_bit(EFI_LOADER, &efi_flags);
> @@ -1225,11 +1226,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE
> *SystemTable)
>
> efi_arch_relocate_image(0);
>
> - /* Get the file system interface. */
> - dir_handle = get_parent_handle(loaded_image, &file_name);
> -
> if ( use_cfg_file )
> {
> + EFI_FILE_HANDLE dir_handle;
> UINTN depth, cols, rows, size;
>
> size = cols = rows = depth = 0;
> @@ -1240,6 +1239,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE
> *SystemTable)
>
> gop = efi_get_gop();
>
> + /* Get the file system interface. */
> + dir_handle = get_parent_handle(loaded_image, &file_name);
> +
> /* Read and parse the config file. */
> if ( read_section(loaded_image, L"config", &cfg, NULL) )
> PrintStr(L"Using builtin config file\r\n");
> @@ -1362,14 +1364,14 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE
> *SystemTable)
> efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size));
> cfg.addr = 0;
>
> + dir_handle->Close(dir_handle);
> +
> if ( gop && !base_video )
> gop_mode = efi_find_gop_mode(gop, cols, rows, depth);
> }
>
> /* Get the number of boot modules specified on the DT or an error (<0) */
> - dt_modules_found = efi_check_dt_boot(dir_handle);
> -
> - dir_handle->Close(dir_handle);
> + dt_modules_found = efi_check_dt_boot(loaded_image);
>
> if ( dt_modules_found < 0 )
> /* efi_check_dt_boot throws some error */
> --
> 2.17.1
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |