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

[Xen-changelog] [xen stable-4.4] EFI: allow retry of ExitBootServices() call



commit fa0e8fead76fd4974cee221bc42943c0e42fe8cf
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Wed Dec 10 12:26:56 2014 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Wed Dec 10 12:26:56 2014 +0100

    EFI: allow retry of ExitBootServices() call
    
    The specification is kind of vague under what conditions
    ExitBootServices() may legitimately fail, requiring the OS loader to
    retry:
    
    "If MapKey value is incorrect, ExitBootServices() returns
     EFI_INVALID_PARAMETER and GetMemoryMap() with ExitBootServices() must
     be called again. Firmware implementation may choose to do a partial
     shutdown of the boot services during the first call to
     ExitBootServices(). EFI OS loader should not make calls to any boot
     service function other then GetMemoryMap() after the first call to
     ExitBootServices()."
    
    While our code guarantees the map key to be valid, there are systems
    where a firmware internal notification sent while processing
    ExitBootServices() reportedly results in changes to the memory map.
    In that case, make a best effort second try: Avoid any boot service
    calls other than the two named above, with the possible exception of
    error paths. Those aren't a problem, since if we end up needing to
    retry, we're hosed when something goes wrong as much as if we didn't
    make the retry attempt.
    
    For x86, a minimal adjustment to efi_arch_process_memory_map() is
    needed for it to cope with potentially being called a second time.
    
    For arm64, while efi_process_memory_map_bootinfo() is easy to verify
    that it can safely be called more than once without violating spec
    constraints, it's not so obvious for fdt_add_uefi_nodes(), hence a
    step by step approach:
    - deletion of memory nodes and memory reserve map entries: the 2nd pass
      shouldn't find any as the 1st one deleted them all,
    - a "chosen" node should be found as it got added in the 1st pass,
    - the various "linux,uefi-*" nodes all got added during the 1st pass
      and hence only their contents may get updated.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Roy Franz <roy.franz@xxxxxxxxxx>
    master commit: 0540b854f6733759593e829bc3f13c9b45974e32
    master date: 2014-11-17 15:07:03 +0100
---
 xen/arch/x86/efi/boot.c |  121 +++++++++++++++++++++++++----------------------
 1 files changed, 65 insertions(+), 56 deletions(-)

diff --git a/xen/arch/x86/efi/boot.c b/xen/arch/x86/efi/boot.c
index a14d1b1..de240f8 100644
--- a/xen/arch/x86/efi/boot.c
+++ b/xen/arch/x86/efi/boot.c
@@ -782,9 +782,8 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
*SystemTable)
     EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info;
     EFI_FILE_HANDLE dir_handle;
     union string section = { NULL }, name;
-    struct e820entry *e;
     u64 efer;
-    bool_t base_video = 0;
+    bool_t base_video = 0, retry;
 
     efi_ih = ImageHandle;
     efi_bs = SystemTable->BootServices;
@@ -1387,68 +1386,78 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
*SystemTable)
     if ( mbi.mem_upper < xen_phys_start )
         blexit(L"Out of static memory");
     efi_memmap = (void *)(long)mbi.mem_upper;
-    status = efi_bs->GetMemoryMap(&efi_memmap_size, efi_memmap, &map_key,
-                                  &efi_mdesc_size, &mdesc_ver);
-    if ( EFI_ERROR(status) )
-        blexit(L"Cannot obtain memory map");
-
-    /* Populate E820 table and check trampoline area availability. */
-    e = e820map - 1;
-    for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
+    for ( retry = 0; ; retry = 1 )
     {
-        EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
-        u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
-        u32 type;
+        struct e820entry *e;
+
+        status = efi_bs->GetMemoryMap(&efi_memmap_size, efi_memmap, &map_key,
+                                      &efi_mdesc_size, &mdesc_ver);
+        if ( EFI_ERROR(status) )
+            PrintErrMesg(L"Cannot obtain memory map", status);
 
-        switch ( desc->Type )
+        /* Populate E820 table and check trampoline area availability. */
+        e = e820map - 1;
+        for ( e820nr = i = 0; i < efi_memmap_size; i += efi_mdesc_size )
         {
-        default:
-            type = E820_RESERVED;
-            break;
-        case EfiConventionalMemory:
-        case EfiBootServicesCode:
-        case EfiBootServicesData:
-            if ( !trampoline_phys && desc->PhysicalStart + len <= 0x100000 &&
-                 len >= cfg.size && desc->PhysicalStart + len > cfg.addr )
-                cfg.addr = (desc->PhysicalStart + len - cfg.size) & PAGE_MASK;
-            /* fall through */
-        case EfiLoaderCode:
-        case EfiLoaderData:
-            if ( desc->Attribute & EFI_MEMORY_WB )
-                type = E820_RAM;
+            EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+            u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
+            u32 type;
+
+            switch ( desc->Type )
+            {
+            default:
+               type = E820_RESERVED;
+               break;
+            case EfiConventionalMemory:
+            case EfiBootServicesCode:
+            case EfiBootServicesData:
+                if ( !trampoline_phys &&
+                     desc->PhysicalStart + len <= 0x100000 &&
+                     len >= cfg.size &&
+                     desc->PhysicalStart + len > cfg.addr )
+                    cfg.addr = (desc->PhysicalStart + len - cfg.size) &
+                               PAGE_MASK;
+                /* fall through */
+            case EfiLoaderCode:
+            case EfiLoaderData:
+                if ( desc->Attribute & EFI_MEMORY_WB )
+                    type = E820_RAM;
+                else
+            case EfiUnusableMemory:
+                    type = E820_UNUSABLE;
+                break;
+            case EfiACPIReclaimMemory:
+                type = E820_ACPI;
+                break;
+            case EfiACPIMemoryNVS:
+                type = E820_NVS;
+                break;
+            }
+            if ( e820nr && type == e->type &&
+                 desc->PhysicalStart == e->addr + e->size )
+                e->size += len;
+            else if ( !len || e820nr >= E820MAX )
+                continue;
             else
-        case EfiUnusableMemory:
-                type = E820_UNUSABLE;
-            break;
-        case EfiACPIReclaimMemory:
-            type = E820_ACPI;
-            break;
-        case EfiACPIMemoryNVS:
-            type = E820_NVS;
-            break;
+            {
+                ++e;
+                e->addr = desc->PhysicalStart;
+                e->size = len;
+                e->type = type;
+                ++e820nr;
+            }
         }
-        if ( e820nr && type == e->type &&
-             desc->PhysicalStart == e->addr + e->size )
-            e->size += len;
-        else if ( !len || e820nr >= E820MAX )
-            continue;
-        else
+        if ( !trampoline_phys )
         {
-            ++e;
-            e->addr = desc->PhysicalStart;
-            e->size = len;
-            e->type = type;
-            ++e820nr;
+            if ( !cfg.addr )
+                blexit(L"No memory for trampoline");
+            relocate_trampoline(cfg.addr);
         }
-    }
-    if ( !trampoline_phys )
-    {
-        if ( !cfg.addr )
-            blexit(L"No memory for trampoline");
-        relocate_trampoline(cfg.addr);
-    }
 
-    status = efi_bs->ExitBootServices(ImageHandle, map_key);
+        status = efi_bs->ExitBootServices(ImageHandle, map_key);
+        if ( status != EFI_INVALID_PARAMETER || retry )
+            break;
+    }
     if ( EFI_ERROR(status) )
         PrintErrMesg(L"Cannot exit boot services", status);
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.4

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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