[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] xen/efi: Fix Grub2 boot on arm64


  • To: Stefano Stabellini <sstabellini@xxxxxxxxxx>
  • From: Luca Fancellu <luca.fancellu@xxxxxxx>
  • Date: Wed, 3 Nov 2021 10:29:12 +0000
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CKkxec2y5eVRlPUYhCGBy68zEctWD43MZ0dVrggf8HY=; b=ogY2rlNPmG3z1T6zIoAXrCHjRdWc1IjHUm8mjGoU9qyjBlL+x/GdzFiJ2T52oGedLqE0vy8BDLcVzMmAK2OK0Tc+JYNODWY5j7iQdMgbN5ZOnAOvtBGPE79MbQb6L8dgrLfEhwEqYYfCe5PG5sGNFPDvkd92NQ5wIhy1JicA2oslCGkE4jYVnKOoetG+hY5nx7jHrqggxtSiXRhVJFmxKRn08R/XTPu0ubC34IQGmRLvfTkmL4fUTmWtQnAqXHO8WKAIXUjUYNaNks6tTXzw0dNdZO9BTSrsoGf9xioTIShmP5Hg8NpgaprVvWZPsNRxZA8O1/Y0Cc8sNcbWZSPzAQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=GlwiXOedKrCZoAWJLIpsK1kAV4WAKZIRFJocVUuT75kbcXFG2D5iEmaUF295vHc1N9ZxssTJpZm3NDUay9TG24LH81bjGID1GayIQx1I4gREPMmNqyL0BQGtupNb7FNfFqv4k0kAaTJavRy0WTTYqphFcO2B3wwSDHIWCF/WHNwmFt9SmxI1T3IC7Zyou6xiz2b8ze0iJ7Kxw2PB6uCik2tbaoTE2tpC6pJads3/pqnL59fxiouYJS3YuuvR6JZ9BuZgbXmKhBnCG1kfmae8U1gL8pLgjsjqxdaos/bYBwlC2hI6ZHzWLcnJJL91ZRQ1sU0gzNgHhoRH5Nzsx34SQg==
  • Authentication-results-original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: Xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, wei.chen@xxxxxxx, Julien Grall <julien@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>
  • Delivery-date: Wed, 03 Nov 2021 10:29:49 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Original-authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;


> On 2 Nov 2021, at 23:17, Stefano Stabellini <sstabellini@xxxxxxxxxx> wrote:
> 
> On Tue, 2 Nov 2021, Luca Fancellu 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.
>> 
>> The problem comes from the function get_parent_handle(...) that inside
>> uses the HandleProtocol on loaded_image->DeviceHandle, but the last
>> is NULL, making Xen stop the UEFI boot.
>> 
>> 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 we allow the get_parent_handle(...) function to
>> return a NULL handle on error and we check the usage of the function
>> to handle the new use case. The function in fact should not prevent
>> the boot even if the filesystem can't be used, because the DT and
>> the modules could be put in place by the bootloader before running
>> Xen and if xen,uefi-binary property is not used, there is no need
>> for the filesystem.
>> 
>> 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.
>> 
>> Fixes: a1743fc3a9 ("arm/efi: Use dom0less configuration when using EFI boot")
>> Signed-off-by: Luca Fancellu <luca.fancellu@xxxxxxx>
>> ---
>> 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
>> 
>> ---
>> xen/arch/arm/efi/efi-boot.h | 28 ++++++++++++++++++----------
>> xen/common/efi/boot.c       | 15 ++++++++++++++-
>> 2 files changed, 32 insertions(+), 11 deletions(-)
>> 
>> diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h
>> index 8b88dd26a5..e714b2b44c 100644
>> --- a/xen/arch/arm/efi/efi-boot.h
>> +++ b/xen/arch/arm/efi/efi-boot.h
>> @@ -51,9 +51,11 @@ static int handle_module_node(EFI_FILE_HANDLE dir_handle,
>>                               int module_node_offset,
>>                               int reg_addr_cells,
>>                               int reg_size_cells,
>> -                              bool is_domu_module);
>> +                              bool is_domu_module,
>> +                              unsigned int *modules_found);
>> static int handle_dom0less_domain_node(EFI_FILE_HANDLE dir_handle,
>> -                                       int domain_node);
>> +                                       int domain_node,
>> +                                       unsigned int *modules_found);
>> static int efi_check_dt_boot(EFI_FILE_HANDLE dir_handle);
>> 
>> #define DEVICE_TREE_GUID \
>> @@ -707,7 +709,8 @@ static int __init handle_module_node(EFI_FILE_HANDLE 
>> dir_handle,
>>                                      int module_node_offset,
>>                                      int reg_addr_cells,
>>                                      int reg_size_cells,
>> -                                     bool is_domu_module)
>> +                                     bool is_domu_module,
>> +                                     unsigned int *modules_found)
>> {
>>     const void *uefi_name_prop;
>>     char mod_string[24]; /* Placeholder for module@ + a 64-bit number + \0 */
>> @@ -725,6 +728,9 @@ static int __init handle_module_node(EFI_FILE_HANDLE 
>> dir_handle,
>>         /* Module is not a multiboot,module */
>>         return 0;
>> 
>> +    /* Count the multiboot module as found */
>> +    (*modules_found)++;
>> +
>>     /* Read xen,uefi-binary property to get the file name. */
>>     uefi_name_prop = fdt_getprop(fdt, module_node_offset, "xen,uefi-binary",
>>                                  &uefi_name_len);
>> @@ -804,7 +810,8 @@ static int __init handle_module_node(EFI_FILE_HANDLE 
>> dir_handle,
>>  * Returns 0 on success, negative number on error.
>>  */
>> static int __init handle_dom0less_domain_node(EFI_FILE_HANDLE dir_handle,
>> -                                              int domain_node)
>> +                                              int domain_node,
>> +                                              unsigned int *modules_found)
>> {
>>     int module_node, addr_cells, size_cells, len;
>>     const struct fdt_property *prop;
>> @@ -834,7 +841,7 @@ static int __init 
>> handle_dom0less_domain_node(EFI_FILE_HANDLE dir_handle,
>>           module_node = fdt_next_subnode(fdt, module_node) )
>>     {
>>         int ret = handle_module_node(dir_handle, module_node, addr_cells,
>> -                                     size_cells, true);
>> +                                     size_cells, true, modules_found);
>>         if ( ret < 0 )
>>             return ret;
>>     }
>> @@ -845,12 +852,12 @@ static int __init 
>> handle_dom0less_domain_node(EFI_FILE_HANDLE dir_handle,
>> /*
>>  * 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)
>> {
>>     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);
>> @@ -868,11 +875,12 @@ static int __init efi_check_dt_boot(EFI_FILE_HANDLE 
>> dir_handle)
>>         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 )
>> +            if ( handle_dom0less_domain_node(dir_handle, node,
>> +                                             &modules_found) < 0 )
>>                 return ERROR_DT_MODULE_DOMU;
>>         }
>>         else if ( handle_module_node(dir_handle, node, addr_len, size_len,
>> -                                     false) < 0 )
>> +                                     false, &modules_found) < 0 )
>>                  return ERROR_DT_MODULE_DOM0;
> 
> I think there is no need to add modules_found to the parameters of
> handle_dom0less_domain_node and handle_module_node. You could just
> increment modules_found here for every iteration of the loop where
> there is no error.  You would have to change a couple of returns in
> handle_module_node, just to give you the idea:

Yes we could do that but when we handle a xen,domain node we will count
only one module and that defeats the aim to count every multiboot,module.

If we want to continue with your proposal let me know and I will implement it.

> 
> 
> diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h
> index e714b2b44c..7739789c41 100644
> --- a/xen/arch/arm/efi/efi-boot.h
> +++ b/xen/arch/arm/efi/efi-boot.h
> @@ -726,7 +726,7 @@ static int __init handle_module_node(EFI_FILE_HANDLE 
> dir_handle,
> 
>     if ( module_compat != 0 )
>         /* Module is not a multiboot,module */
> -        return 0;
> +        return 1;
> 
>     /* Count the multiboot module as found */
>     (*modules_found)++;
> @@ -737,7 +737,7 @@ static int __init handle_module_node(EFI_FILE_HANDLE 
> dir_handle,
> 
>     if ( !uefi_name_prop )
>         /* Property not found */
> -        return 0;
> +        return 1;
> 
>     file_idx = get_module_file_index(uefi_name_prop, uefi_name_len);
>     if ( file_idx < 0 )
> 
> 
>>     }
>> 
>> @@ -883,7 +891,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..495e7a4096 100644
>> --- a/xen/common/efi/boot.c
>> +++ b/xen/common/efi/boot.c
>> @@ -449,6 +449,13 @@ static EFI_FILE_HANDLE __init 
>> get_parent_handle(EFI_LOADED_IMAGE *loaded_image,
>>     CHAR16 *pathend, *ptr;
>>     EFI_STATUS ret;
>> 
>> +    /*
>> +     * If DeviceHandle is NULL, we can't use the SIMPLE_FILE_SYSTEM_PROTOCOL
>> +     * to have access to the filesystem.
>> +     */
>> +    if ( !loaded_image->DeviceHandle )
>> +        return NULL;
>> +
>>     do {
>>         EFI_FILE_IO_INTERFACE *fio;
>> 
>> @@ -581,6 +588,8 @@ static bool __init read_file(EFI_FILE_HANDLE dir_handle, 
>> CHAR16 *name,
>>     EFI_STATUS ret;
>>     const CHAR16 *what = NULL;
>> 
>> +    if ( !dir_handle )
>> +        blexit(L"Error: No access to the filesystem");
>>     if ( !name )
>>         PrintErrMesg(L"No filename", EFI_OUT_OF_RESOURCES);
>>     ret = dir_handle->Open(dir_handle, &FileHandle, name,
>> @@ -1333,6 +1342,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
>> *SystemTable)
>>             EFI_FILE_HANDLE handle = get_parent_handle(loaded_image,
>>                                                        &file_name);
>> 
>> +            if ( !handle )
>> +                blexit(L"Error retrieving image name: no filesystem 
>> access");
> 
> I think it would be nice to have an other explicit check like this one
> at the beginning of if ( use_cfg_file ) to make sure dir_handle is not
> null in that case. If I am not mistaken, if we take the use_cfg_file
> path, dir_handle has to be valid, right?

Dir_handle could be invalid and we would be able to boot successfully when we 
take everywhere
the path using read_section, for that reason I didn’t stop the boot earlier.
Given Jan suggestion that check could be also modified to be something like “if 
there is no handle, *argv=“xen.efi” "
so the boot can continue without problem if we don’t need to read anything from 
the filesystem.

> 
> 
>>             handle->Close(handle);
>>             *argv = file_name;
>>         }
>> @@ -1369,7 +1381,8 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
>> *SystemTable)
>>     /* 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);
>> +    if ( dir_handle )
>> +        dir_handle->Close(dir_handle);
>> 
>>     if ( dt_modules_found < 0 )
>>         /* efi_check_dt_boot throws some error */
>> -- 
>> 2.17.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.