]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/Bds/Bds.c
ArmPlatformPkg/Bds: Early Console Initialization
[mirror_edk2.git] / ArmPlatformPkg / Bds / Bds.c
index 176311e8a28b48dd445caf5ea602f299e23f8375..4cea3cd531bbdc46e95625b4abe281d3dbc6168b 100644 (file)
@@ -1,14 +1,14 @@
 /** @file\r
 *\r
-*  Copyright (c) 2011, 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
-*  which accompanies this distribution.  The full text of the license may be found at        \r
-*  http://opensource.org/licenses/bsd-license.php                                            \r
+*  Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
 *\r
-*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 *\r
 **/\r
 \r
@@ -19,9 +19,9 @@
 \r
 #include <Protocol/Bds.h>\r
 \r
-#define EFI_SET_TIMER_TO_SECOND   10000000\r
+#include <Guid/EventGroup.h>\r
 \r
-EFI_HANDLE mImageHandle;\r
+#define EFI_SET_TIMER_TO_SECOND   10000000\r
 \r
 STATIC\r
 EFI_STATUS\r
@@ -39,7 +39,7 @@ GetConsoleDevicePathFromVariable (
   CHAR16*                   NextDevicePathStr;\r
   EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;\r
 \r
-  Status = GetEnvironmentVariable (ConsoleVarName, NULL, NULL, (VOID**)&DevicePathInstances);\r
+  Status = GetGlobalEnvironmentVariable (ConsoleVarName, NULL, NULL, (VOID**)&DevicePathInstances);\r
   if (EFI_ERROR(Status)) {\r
     // In case no default console device path has been defined we assume a driver handles the console (eg: SimpleTextInOutSerial)\r
     if ((DefaultConsolePaths == NULL) || (DefaultConsolePaths[0] == L'\0')) {\r
@@ -124,7 +124,7 @@ InitializeConsolePipe (
         EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
         CHAR16* DevicePathTxt;\r
         EFI_STATUS Status;\r
-       \r
+\r
         Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
         if (!EFI_ERROR(Status)) {\r
           DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE);\r
@@ -155,8 +155,8 @@ InitializeConsolePipe (
       *Handle = Buffer[0];\r
       Status = gBS->HandleProtocol (*Handle, Protocol, Interface);\r
       ASSERT_EFI_ERROR(Status);\r
+      FreePool (Buffer);\r
     }\r
-    FreePool (Buffer);\r
   } else {\r
     Status = EFI_SUCCESS;\r
   }\r
@@ -181,7 +181,7 @@ InitializeConsole (
   ASSERT_EFI_ERROR (Status);\r
   Status = GetConsoleDevicePathFromVariable (L"ConIn", (CHAR16*)PcdGetPtr(PcdDefaultConInPaths), &ConInDevicePaths);\r
   ASSERT_EFI_ERROR (Status);\r
-  Status = GetConsoleDevicePathFromVariable (L"ConErr", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths), &ConErrDevicePaths);\r
+  Status = GetConsoleDevicePathFromVariable (L"ErrOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths), &ConErrDevicePaths);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   // Initialize the Consoles\r
@@ -196,6 +196,17 @@ InitializeConsole (
     gST->StdErr = gST->ConOut;\r
   }\r
 \r
+  // Free Memory allocated for reading the UEFI Variables\r
+  if (ConOutDevicePaths) {\r
+    FreePool (ConOutDevicePaths);\r
+  }\r
+  if (ConInDevicePaths) {\r
+    FreePool (ConInDevicePaths);\r
+  }\r
+  if (ConErrDevicePaths) {\r
+    FreePool (ConErrDevicePaths);\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -209,11 +220,10 @@ DefineDefaultBootEntries (
   EFI_STATUS                          Status;\r
   EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;\r
   EFI_DEVICE_PATH*                    BootDevicePath;\r
-  ARM_BDS_LOADER_ARGUMENTS*           BootArguments;\r
-  ARM_BDS_LOADER_TYPE                 BootType;\r
-  EFI_DEVICE_PATH*                    InitrdPath;\r
   UINTN                               CmdLineSize;\r
-  UINTN                               InitrdSize;\r
+  UINTN                               CmdLineAsciiSize;\r
+  CHAR16*                             DefaultBootArgument;\r
+  CHAR8*                              AsciiDefaultBootArgument;\r
 \r
   //\r
   // If Boot Order does not exist then create a default entry\r
@@ -242,44 +252,74 @@ DefineDefaultBootEntries (
       ASSERT_EFI_ERROR(Status);\r
       DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootDevicePath, TRUE, TRUE);\r
 \r
-      ASSERT (StrCmp ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath), DevicePathTxt) == 0);\r
+      if (StrCmp ((CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath), DevicePathTxt) != 0) {\r
+        DEBUG ((EFI_D_ERROR, "Device Path given: '%s' Device Path expected: '%s'\n",\r
+            (CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath), DevicePathTxt));\r
+        ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+      }\r
 \r
       FreePool (DevicePathTxt);\r
     DEBUG_CODE_END();\r
 \r
     // Create the entry is the Default values are correct\r
     if (BootDevicePath != NULL) {\r
-      BootType = (ARM_BDS_LOADER_TYPE)PcdGet32 (PcdDefaultBootType);\r
-\r
-      if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
-        CmdLineSize = AsciiStrSize ((CHAR8*)PcdGetPtr(PcdDefaultBootArgument));\r
-        InitrdPath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootInitrdPath));\r
-        InitrdSize = GetDevicePathSize (InitrdPath);\r
-\r
-        BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize);\r
-        BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;\r
-        BootArguments->LinuxArguments.InitrdSize = InitrdSize;\r
-\r
-        CopyMem ((VOID*)(BootArguments + 1), (CHAR8*)PcdGetPtr(PcdDefaultBootArgument), CmdLineSize);\r
-        CopyMem ((VOID*)((UINTN)(BootArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);\r
+      // We do not support NULL pointer\r
+      ASSERT (PcdGetPtr (PcdDefaultBootArgument) != NULL);\r
+\r
+      //\r
+      // Logic to handle ASCII or Unicode default parameters\r
+      //\r
+      if (*(CHAR8*)PcdGetPtr (PcdDefaultBootArgument) == '\0') {\r
+        CmdLineSize = 0;\r
+        CmdLineAsciiSize = 0;\r
+        DefaultBootArgument = NULL;\r
+        AsciiDefaultBootArgument = NULL;\r
+      } else if (IsUnicodeString ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument))) {\r
+        // The command line is a Unicode string\r
+        DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument);\r
+        CmdLineSize = StrSize (DefaultBootArgument);\r
+\r
+        // Initialize ASCII variables\r
+        CmdLineAsciiSize = CmdLineSize / 2;\r
+        AsciiDefaultBootArgument = AllocatePool (CmdLineAsciiSize);\r
+        if (AsciiDefaultBootArgument == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+        UnicodeStrToAsciiStr ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument), AsciiDefaultBootArgument);\r
       } else {\r
-        BootArguments = NULL;\r
+        // The command line is a ASCII string\r
+        AsciiDefaultBootArgument = (CHAR8*)PcdGetPtr (PcdDefaultBootArgument);\r
+        CmdLineAsciiSize = AsciiStrSize (AsciiDefaultBootArgument);\r
+\r
+        // Initialize ASCII variables\r
+        CmdLineSize = CmdLineAsciiSize * 2;\r
+        DefaultBootArgument = AllocatePool (CmdLineSize);\r
+        if (DefaultBootArgument == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+        AsciiStrToUnicodeStr (AsciiDefaultBootArgument, DefaultBootArgument);\r
       }\r
 \r
       BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,\r
-        (CHAR16*)PcdGetPtr(PcdDefaultBootDescription),\r
+        (CHAR16*)PcdGetPtr (PcdDefaultBootDescription),\r
         BootDevicePath,\r
-        BootType,\r
-        BootArguments,\r
+        (UINT8 *)DefaultBootArgument, // OptionalData\r
+        CmdLineSize,                  // OptionalDataSize\r
         &BdsLoadOption\r
         );\r
       FreePool (BdsLoadOption);\r
+\r
+      if (DefaultBootArgument == (CHAR16*)PcdGetPtr (PcdDefaultBootArgument)) {\r
+        FreePool (AsciiDefaultBootArgument);\r
+      } else if (DefaultBootArgument != NULL) {\r
+        FreePool (DefaultBootArgument);\r
+      }\r
     } else {\r
       Status = EFI_UNSUPPORTED;\r
     }\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
 EFI_STATUS\r
@@ -296,13 +336,16 @@ StartDefaultBootOnTimeout (
   UINTN               BootOrderSize;\r
   UINTN               Index;\r
   CHAR16              BootVariableName[9];\r
-  EFI_STATUS           Status;\r
-  EFI_INPUT_KEY   Key;\r
+  EFI_STATUS          Status;\r
+  EFI_INPUT_KEY       Key;\r
 \r
   Size = sizeof(UINT16);\r
   Timeout = (UINT16)PcdGet16 (PcdPlatformBootTimeOut);\r
-  TimeoutPtr = &Timeout;\r
-  GetEnvironmentVariable (L"Timeout", &Timeout, &Size, (VOID**)&TimeoutPtr);\r
+  Status = GetGlobalEnvironmentVariable (L"Timeout", &Timeout, &Size, (VOID**)&TimeoutPtr);\r
+  if (!EFI_ERROR (Status)) {\r
+    Timeout = *TimeoutPtr;\r
+    FreePool (TimeoutPtr);\r
+  }\r
 \r
   if (Timeout != 0xFFFF) {\r
     if (Timeout > 0) {\r
@@ -324,7 +367,7 @@ StartDefaultBootOnTimeout (
       }\r
       // Discard key in the buffer\r
       do {\r
-       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
       } while(!EFI_ERROR(Status));\r
       gBS->CloseEvent (WaitList[0]);\r
       Print(L"\n\r");\r
@@ -333,36 +376,55 @@ StartDefaultBootOnTimeout (
     // In case of Timeout we start the default boot selection\r
     if (Timeout == 0) {\r
       // Get the Boot Option Order from the environment variable (a default value should have been created)\r
-      GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
+      GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
 \r
       for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
         UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOrder[Index]);\r
         Status = BdsStartBootOption (BootVariableName);\r
         if(!EFI_ERROR(Status)){\r
-               // Boot option returned successfully, hence don't need to start next boot option\r
-               break;\r
+          // Boot option returned successfully, hence don't need to start next boot option\r
+          break;\r
         }\r
         // In case of success, we should not return from this call.\r
       }\r
+      FreePool (BootOrder);\r
     }\r
   }\r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  This function uses policy data from the platform to determine what operating \r
-  system or system utility should be loaded and invoked.  This function call \r
-  also optionally make the use of user input to determine the operating system \r
-  or system utility to be loaded and invoked.  When the DXE Core has dispatched \r
-  all the drivers on the dispatch queue, this function is called.  This \r
-  function will attempt to connect the boot devices required to load and invoke \r
-  the selected operating system or system utility.  During this process, \r
-  additional firmware volumes may be discovered that may contain addition DXE \r
-  drivers that can be dispatched by the DXE Core.   If a boot device cannot be \r
-  fully connected, this function calls the DXE Service Dispatch() to allow the \r
-  DXE drivers from any newly discovered firmware volumes to be dispatched.  \r
-  Then the boot device connection can be attempted again.  If the same boot \r
-  device connection operation fails twice in a row, then that boot device has \r
+  An empty function to pass error checking of CreateEventEx ().\r
+\r
+  @param  Event                 Event whose notification function is being invoked.\r
+  @param  Context               Pointer to the notification function's context,\r
+                                which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EmptyCallbackFunction (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  return;\r
+}\r
+\r
+/**\r
+  This function uses policy data from the platform to determine what operating\r
+  system or system utility should be loaded and invoked.  This function call\r
+  also optionally make the use of user input to determine the operating system\r
+  or system utility to be loaded and invoked.  When the DXE Core has dispatched\r
+  all the drivers on the dispatch queue, this function is called.  This\r
+  function will attempt to connect the boot devices required to load and invoke\r
+  the selected operating system or system utility.  During this process,\r
+  additional firmware volumes may be discovered that may contain addition DXE\r
+  drivers that can be dispatched by the DXE Core.   If a boot device cannot be\r
+  fully connected, this function calls the DXE Service Dispatch() to allow the\r
+  DXE drivers from any newly discovered firmware volumes to be dispatched.\r
+  Then the boot device connection can be attempted again.  If the same boot\r
+  device connection operation fails twice in a row, then that boot device has\r
   failed, and should be skipped.  This function should never return.\r
 \r
   @param  This             The EFI_BDS_ARCH_PROTOCOL instance.\r
@@ -378,6 +440,25 @@ BdsEntry (
 {\r
   UINTN               Size;\r
   EFI_STATUS          Status;\r
+  UINT16             *BootNext;\r
+  UINTN               BootNextSize;\r
+  CHAR16              BootVariableName[9];\r
+  EFI_EVENT           EndOfDxeEvent;\r
+\r
+  //\r
+  // Signal EndOfDxe PI Event\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+      EVT_NOTIFY_SIGNAL,\r
+      TPL_NOTIFY,\r
+      EmptyCallbackFunction,\r
+      NULL,\r
+      &gEfiEndOfDxeEventGroupGuid,\r
+      &EndOfDxeEvent\r
+      );\r
+  if (!EFI_ERROR (Status)) {\r
+    gBS->SignalEvent (EndOfDxeEvent);\r
+  }\r
 \r
   PERF_END   (NULL, "DXE", NULL, 0);\r
 \r
@@ -391,25 +472,61 @@ BdsEntry (
     UnicodeSPrint (gST->FirmwareVendor, Size, L"%a EFI %a %a", PcdGetPtr(PcdFirmwareVendor), __DATE__, __TIME__);\r
   }\r
 \r
+  //\r
+  // Fixup Table CRC after we updated Firmware Vendor\r
+  //\r
+  gST->Hdr.CRC32 = 0;\r
+  Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  // Now we need to setup the EFI System Table with information about the console devices.\r
+  InitializeConsole ();\r
+\r
   // If BootNext environment variable is defined then we just load it !\r
-  Status = BdsStartBootOption (L"BootNext");\r
-  if (Status != EFI_NOT_FOUND) {\r
-    // BootNext has not been succeeded launched\r
-    if (EFI_ERROR(Status)) {\r
-      Print(L"Fail to start BootNext.\n");\r
+  BootNextSize = sizeof(UINT16);\r
+  Status = GetGlobalEnvironmentVariable (L"BootNext", NULL, &BootNextSize, (VOID**)&BootNext);\r
+  if (!EFI_ERROR(Status)) {\r
+    ASSERT(BootNextSize == sizeof(UINT16));\r
+\r
+    // Generate the requested Boot Entry variable name\r
+    UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", *BootNext);\r
+\r
+    // Set BootCurrent variable\r
+    gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,\r
+              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+              BootNextSize, BootNext);\r
+\r
+    FreePool (BootNext);\r
+\r
+    // Start the requested Boot Entry\r
+    Status = BdsStartBootOption (BootVariableName);\r
+    if (Status != EFI_NOT_FOUND) {\r
+      // BootNext has not been succeeded launched\r
+      if (EFI_ERROR(Status)) {\r
+        Print(L"Fail to start BootNext.\n");\r
+      }\r
+\r
+      // Delete the BootNext environment variable\r
+      gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid,\r
+          EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+          0, NULL);\r
     }\r
 \r
-    // Delete the BootNext environment variable\r
-    gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid,\r
-        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+    // Clear BootCurrent variable\r
+    gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,\r
+        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
         0, NULL);\r
   }\r
 \r
   // If Boot Order does not exist then create a default entry\r
   DefineDefaultBootEntries ();\r
 \r
-  // Now we need to setup the EFI System Table with information about the console devices.\r
-  InitializeConsole ();\r
+  //\r
+  // Update the CRC32 in the EFI System Table header\r
+  //\r
+  gST->Hdr.CRC32 = 0;\r
+  Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32);\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
   // Timer before initiating the default boot selection\r
   StartDefaultBootOnTimeout ();\r
@@ -433,8 +550,6 @@ BdsInitialize (
 {\r
   EFI_STATUS  Status;\r
 \r
-  mImageHandle = ImageHandle;\r
-\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &ImageHandle,\r
                   &gEfiBdsArchProtocolGuid, &gBdsProtocol,\r