]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/Bds/BootMenu.c
ArmPkg/BdsLib: Replaced BdsLoadApplication() by LocateEfiApplicationInFv()
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
index b96a1c3f923cc30a69e82974a0e44b526f7af839..a304cc4ce916f39dbe060095d3f5cec06f12013d 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 *\r
-*  Copyright (c) 2011 - 2014, ARM Limited. All rights reserved.\r
+*  Copyright (c) 2011 - 2015, ARM Limited. All rights reserved.\r
 *\r
 *  This program and the accompanying materials\r
 *  are licensed and made available under the terms and conditions of the BSD License\r
@@ -16,8 +16,7 @@
 \r
 #include <Guid/ArmGlobalVariableHob.h>\r
 \r
-extern EFI_HANDLE mImageHandle;\r
-extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;\r
+#include <libfdt.h>\r
 \r
 /**\r
   Worker function that displays the list of boot options that is passed in.\r
@@ -342,6 +341,9 @@ BootMenuAddBootOption (
       if (InitrdPathNodes != NULL) {\r
         // Append the Device Path to the selected device path\r
         InitrdPath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);\r
+        // Free the InitrdPathNodes created by Support->CreateDevicePathNode()\r
+        FreePool (InitrdPathNodes);\r
+\r
         if (InitrdPath == NULL) {\r
           Status = EFI_OUT_OF_RESOURCES;\r
           goto EXIT;\r
@@ -541,6 +543,8 @@ BootMenuUpdateBootOption (
           // Append the Device Path to the selected device path\r
           InitrdPath = AppendDevicePath (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);\r
           FreePool (TempInitrdPath);\r
+          // Free the InitrdPathNodes created by Support->CreateDevicePathNode()\r
+          FreePool (InitrdPathNodes);\r
           if (InitrdPath == NULL) {\r
             Status = EFI_OUT_OF_RESOURCES;\r
             goto EXIT;\r
@@ -556,7 +560,8 @@ BootMenuUpdateBootOption (
 \r
     Print(L"Arguments to pass to the binary: ");\r
     if (CmdLineSize > 0) {\r
-      AsciiStrnCpy(CmdLine, (CONST CHAR8*)(LinuxArguments + 1), CmdLineSize);\r
+      AsciiStrnCpy (CmdLine, (CONST CHAR8*)(LinuxArguments + 1), sizeof (CmdLine));\r
+      CmdLine[sizeof (CmdLine) - 1] = '\0';\r
     } else {\r
       CmdLine[0] = '\0';\r
     }\r
@@ -582,10 +587,29 @@ BootMenuUpdateBootOption (
     if (BootOption->OptionalDataSize > 0) {\r
       IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode);\r
       if (IsPrintable) {\r
+          //\r
+          // The size in bytes of the string, final zero included, should\r
+          // be equal to or at least lower than "BootOption->OptionalDataSize"\r
+          // and the "IsPrintableString()" has already tested that the length\r
+          // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,\r
+          // final '\0' included. We can thus copy the string for editing\r
+          // using "CopyMem()". Furthermore, note that in the case of an Unicode\r
+          // string "StrnCpy()" and "StrCpy()" can not be used to copy the\r
+          // string because the data pointed to by "BootOption->OptionalData"\r
+          // is not necessarily 2-byte aligned.\r
+          //\r
         if (IsUnicode) {\r
-          StrnCpy (UnicodeCmdLine, BootOption->OptionalData, BootOption->OptionalDataSize / 2);\r
+          CopyMem (\r
+            UnicodeCmdLine, BootOption->OptionalData,\r
+            MIN (sizeof (UnicodeCmdLine),\r
+                 BootOption->OptionalDataSize)\r
+            );\r
         } else {\r
-          AsciiStrnCpy (CmdLine, BootOption->OptionalData, BootOption->OptionalDataSize);\r
+          CopyMem (\r
+            CmdLine, BootOption->OptionalData,\r
+            MIN (sizeof (CmdLine),\r
+                 BootOption->OptionalDataSize)\r
+            );\r
         }\r
       }\r
     } else {\r
@@ -692,6 +716,7 @@ BootMenuReorderBootOptions (
     }\r
 \r
     SelectedEntry = &BootOptionEntry->Link;\r
+    SecondEntry = NULL;\r
     // Note down the previous entry in the list to be able to cancel changes\r
     PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry);\r
 \r
@@ -740,7 +765,9 @@ BootMenuReorderBootOptions (
       } while ((!Move) && (!Save) && (!Cancel));\r
 \r
       if (Move) {\r
-        SwapListEntries (SelectedEntry, SecondEntry);\r
+        if ((SelectedEntry != NULL) && (SecondEntry != NULL)) {\r
+          SwapListEntries (SelectedEntry, SecondEntry);\r
+        }\r
       } else {\r
         if (Save) {\r
           Status = GetGlobalEnvironmentVariable (\r
@@ -803,52 +830,143 @@ UpdateFdtPath (
   )\r
 {\r
   EFI_STATUS                Status;\r
-  UINTN                     FdtDevicePathSize;\r
   BDS_SUPPORTED_DEVICE      *SupportedBootDevice;\r
   EFI_DEVICE_PATH_PROTOCOL  *FdtDevicePathNodes;\r
   EFI_DEVICE_PATH_PROTOCOL  *FdtDevicePath;\r
+  CHAR16                    *FdtTextDevicePath;\r
+  EFI_PHYSICAL_ADDRESS      FdtBlobBase;\r
+  UINTN                     FdtBlobSize;\r
+  UINTN                     NumPages;\r
+  EFI_PHYSICAL_ADDRESS      FdtConfigurationTableBase;\r
+\r
+  SupportedBootDevice = NULL;\r
 \r
   Status = SelectBootDevice (&SupportedBootDevice);\r
-  if (EFI_ERROR(Status)) {\r
+  if (EFI_ERROR (Status)) {\r
     Status = EFI_ABORTED;\r
     goto EXIT;\r
   }\r
 \r
   // Create the specific device path node\r
   Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);\r
-  if (EFI_ERROR(Status)) {\r
+  if (EFI_ERROR (Status)) {\r
     Status = EFI_ABORTED;\r
     goto EXIT;\r
   }\r
 \r
   if (FdtDevicePathNodes != NULL) {\r
-    // Append the Device Path node to the select device path\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+\r
     FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);\r
-    FdtDevicePathSize = GetDevicePathSize (FdtDevicePath);\r
+    FreePool (FdtDevicePathNodes);\r
+    if (FdtDevicePath == NULL) {\r
+      goto EXIT;\r
+    }\r
+\r
+    FdtTextDevicePath = ConvertDevicePathToText (FdtDevicePath, TRUE, TRUE);\r
+    if (FdtTextDevicePath == NULL) {\r
+      goto EXIT;\r
+    }\r
+\r
     Status = gRT->SetVariable (\r
                     (CHAR16*)L"Fdt",\r
-                    &gArmGlobalVariableGuid,\r
-                    EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
-                    FdtDevicePathSize,\r
-                    FdtDevicePath\r
+                    &gFdtVariableGuid,\r
+                    EFI_VARIABLE_RUNTIME_ACCESS |\r
+                    EFI_VARIABLE_NON_VOLATILE   |\r
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                    StrSize (FdtTextDevicePath),\r
+                    FdtTextDevicePath\r
                     );\r
-    ASSERT_EFI_ERROR(Status);\r
+    ASSERT_EFI_ERROR (Status);\r
+    FreePool (FdtTextDevicePath);\r
   } else {\r
-    gRT->SetVariable (\r
+    Status = gRT->SetVariable (\r
            (CHAR16*)L"Fdt",\r
-           &gArmGlobalVariableGuid,\r
-           EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+           &gFdtVariableGuid,\r
+           EFI_VARIABLE_RUNTIME_ACCESS |\r
+           EFI_VARIABLE_NON_VOLATILE   |\r
+           EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
            0,\r
            NULL\r
            );\r
-    ASSERT_EFI_ERROR(Status);\r
+    ASSERT_EFI_ERROR (Status);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Try to load FDT from the new EFI Device Path\r
+  //\r
+\r
+  //\r
+  // Load the FDT given its device path.\r
+  // This operation may fail if the device path is not supported.\r
+  //\r
+  FdtBlobBase = 0;\r
+  NumPages    = 0;\r
+  Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
+  FreePool (FdtDevicePath);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT_LOAD_FDT;\r
+  }\r
+\r
+  // Check the FDT header is valid. We only make this check in DEBUG mode in\r
+  // case the FDT header change on production device and this ASSERT() becomes\r
+  // not valid.\r
+  ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);\r
+\r
+  //\r
+  // Ensure the Size of the Device Tree is smaller than the size of the read file\r
+  //\r
+  ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);\r
+\r
+  //\r
+  // Store the FDT as Runtime Service Data to prevent the Kernel from\r
+  // overwritting its data.\r
+  //\r
+  NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);\r
+  Status = gBS->AllocatePages (\r
+                  AllocateAnyPages, EfiRuntimeServicesData,\r
+                  NumPages, &FdtConfigurationTableBase\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT_LOAD_FDT;\r
+  }\r
+  gBS->CopyMem (\r
+    (VOID*)(UINTN)FdtConfigurationTableBase,\r
+    (VOID*)(UINTN)FdtBlobBase,\r
+    FdtBlobSize\r
+    );\r
+\r
+  //\r
+  // Install the FDT into the Configuration Table\r
+  //\r
+  Status = gBS->InstallConfigurationTable (\r
+                  &gFdtTableGuid,\r
+                  (VOID*)(UINTN)FdtConfigurationTableBase\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePages (FdtConfigurationTableBase, NumPages);\r
+  }\r
+\r
+EXIT_LOAD_FDT:\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");\r
+  }\r
+\r
+  if (FdtBlobBase != 0) {\r
+    gBS->FreePages (FdtBlobBase, NumPages);\r
   }\r
 \r
 EXIT:\r
   if (Status == EFI_ABORTED) {\r
-    Print(L"\n");\r
+    Print (L"\n");\r
   }\r
-  FreePool(SupportedBootDevice);\r
+\r
+  if (SupportedBootDevice != NULL) {\r
+    FreePool (SupportedBootDevice);\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
@@ -951,17 +1069,27 @@ BootShell (
   IN LIST_ENTRY *BootOptionsList\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  EFI_STATUS       Status;\r
+  EFI_DEVICE_PATH* EfiShellDevicePath;\r
 \r
-  // Start EFI Shell\r
-  Status = BdsLoadApplication (mImageHandle, L"Shell", 0, NULL);\r
+  // Find the EFI Shell\r
+  Status = LocateEfiApplicationInFvByName (L"Shell", &EfiShellDevicePath);\r
   if (Status == EFI_NOT_FOUND) {\r
     Print (L"Error: EFI Application not found.\n");\r
-  } else if (EFI_ERROR(Status)) {\r
-    Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);\r
-  }\r
+    return Status;\r
+  } else if (EFI_ERROR (Status)) {\r
+    Print (L"Error: Status Code: 0x%X\n", (UINT32)Status);\r
+    return Status;\r
+  } else {\r
+    // Need to connect every drivers to ensure no dependencies are missing for the application\r
+    Status = BdsConnectAllDrivers ();\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n"));\r
+      return Status;\r
+    }\r
 \r
-  return Status;\r
+    return BdsStartEfiApplication (gImageHandle, EfiShellDevicePath, 0, NULL);\r
+  }\r
 }\r
 \r
 struct BOOT_MAIN_ENTRY {\r