]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmVirtPkg: duplicate PlatformIntelBdsLib to PlatformBootManagerLib
authorLaszlo Ersek <lersek@redhat.com>
Thu, 5 May 2016 13:12:09 +0000 (15:12 +0200)
committerLaszlo Ersek <lersek@redhat.com>
Fri, 6 May 2016 08:04:49 +0000 (10:04 +0200)
Create a copy of PlatformIntelBdsLib under the name
PlatformBootManagerLib, with the following initial changes:
- replace PlatformBdsLib references with PlatformBootManagerLib in
  comments,
- replace "IntelBdsPlatform" with "PlatformBm" in file names and their
  references,
- generate a new FILE_GUID.

PlatformBootManagerLib will be linked into the BDS driver from
MdeModulePkg.

This patch parallels OvmfPkg commit 305418818959.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Ruiyu Ni <ruiyu.ni@Intel.com>
ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c [new file with mode: 0644]
ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.h [new file with mode: 0644]
ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf [new file with mode: 0644]
ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c [new file with mode: 0644]

diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
new file mode 100644 (file)
index 0000000..f841d7c
--- /dev/null
@@ -0,0 +1,491 @@
+/** @file\r
+  Implementation for PlatformBootManagerLib library class interfaces.\r
+\r
+  Copyright (C) 2015-2016, Red Hat, Inc.\r
+  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>\r
+  Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  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, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Pci22.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PlatformBdsLib.h>\r
+#include <Library/QemuBootOrderLib.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/GraphicsOutput.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/PciRootBridgeIo.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/RootBridgesConnectedEventGroup.h>\r
+\r
+#include "PlatformBm.h"\r
+\r
+#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }\r
+\r
+\r
+#pragma pack (1)\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH         SerialDxe;\r
+  UART_DEVICE_PATH           Uart;\r
+  VENDOR_DEFINED_DEVICE_PATH TermType;\r
+  EFI_DEVICE_PATH_PROTOCOL   End;\r
+} PLATFORM_SERIAL_CONSOLE;\r
+#pragma pack ()\r
+\r
+#define SERIAL_DXE_FILE_GUID { \\r
+          0xD3987D4B, 0x971A, 0x435F, \\r
+          { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \\r
+          }\r
+\r
+STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {\r
+  //\r
+  // VENDOR_DEVICE_PATH SerialDxe\r
+  //\r
+  {\r
+    { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },\r
+    SERIAL_DXE_FILE_GUID\r
+  },\r
+\r
+  //\r
+  // UART_DEVICE_PATH Uart\r
+  //\r
+  {\r
+    { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },\r
+    0,                                      // Reserved\r
+    FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate\r
+    FixedPcdGet8 (PcdUartDefaultDataBits),  // DataBits\r
+    FixedPcdGet8 (PcdUartDefaultParity),    // Parity\r
+    FixedPcdGet8 (PcdUartDefaultStopBits)   // StopBits\r
+  },\r
+\r
+  //\r
+  // VENDOR_DEFINED_DEVICE_PATH TermType\r
+  //\r
+  {\r
+    {\r
+      MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,\r
+      DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)\r
+    }\r
+    //\r
+    // Guid to be filled in dynamically\r
+    //\r
+  },\r
+\r
+  //\r
+  // EFI_DEVICE_PATH_PROTOCOL End\r
+  //\r
+  {\r
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)\r
+  }\r
+};\r
+\r
+\r
+#pragma pack (1)\r
+typedef struct {\r
+  USB_CLASS_DEVICE_PATH    Keyboard;\r
+  EFI_DEVICE_PATH_PROTOCOL End;\r
+} PLATFORM_USB_KEYBOARD;\r
+#pragma pack ()\r
+\r
+STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {\r
+  //\r
+  // USB_CLASS_DEVICE_PATH Keyboard\r
+  //\r
+  {\r
+    {\r
+      MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,\r
+      DP_NODE_LEN (USB_CLASS_DEVICE_PATH)\r
+    },\r
+    0xFFFF, // VendorId: any\r
+    0xFFFF, // ProductId: any\r
+    3,      // DeviceClass: HID\r
+    1,      // DeviceSubClass: boot\r
+    1       // DeviceProtocol: keyboard\r
+  },\r
+\r
+  //\r
+  // EFI_DEVICE_PATH_PROTOCOL End\r
+  //\r
+  {\r
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)\r
+  }\r
+};\r
+\r
+//\r
+// BDS Platform Functions\r
+//\r
+/**\r
+  Platform Bds init. Include the platform firmware vendor, revision\r
+  and so crc check.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBdsInit (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // Signal EndOfDxe PI Event\r
+  //\r
+  EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
+}\r
+\r
+\r
+/**\r
+  Check if the handle satisfies a particular condition.\r
+\r
+  @param[in] Handle      The handle to check.\r
+  @param[in] ReportText  A caller-allocated string passed in for reporting\r
+                         purposes. It must never be NULL.\r
+\r
+  @retval TRUE   The condition is satisfied.\r
+  @retval FALSE  Otherwise. This includes the case when the condition could not\r
+                 be fully evaluated due to an error.\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *FILTER_FUNCTION) (\r
+  IN EFI_HANDLE   Handle,\r
+  IN CONST CHAR16 *ReportText\r
+  );\r
+\r
+\r
+/**\r
+  Process a handle.\r
+\r
+  @param[in] Handle      The handle to process.\r
+  @param[in] ReportText  A caller-allocated string passed in for reporting\r
+                         purposes. It must never be NULL.\r
+**/\r
+typedef\r
+VOID\r
+(EFIAPI *CALLBACK_FUNCTION)  (\r
+  IN EFI_HANDLE   Handle,\r
+  IN CONST CHAR16 *ReportText\r
+  );\r
+\r
+/**\r
+  Locate all handles that carry the specified protocol, filter them with a\r
+  callback function, and pass each handle that passes the filter to another\r
+  callback.\r
+\r
+  @param[in] ProtocolGuid  The protocol to look for.\r
+\r
+  @param[in] Filter        The filter function to pass each handle to. If this\r
+                           parameter is NULL, then all handles are processed.\r
+\r
+  @param[in] Process       The callback function to pass each handle to that\r
+                           clears the filter.\r
+**/\r
+STATIC\r
+VOID\r
+FilterAndProcess (\r
+  IN EFI_GUID          *ProtocolGuid,\r
+  IN FILTER_FUNCTION   Filter         OPTIONAL,\r
+  IN CALLBACK_FUNCTION Process\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  EFI_HANDLE *Handles;\r
+  UINTN      NoHandles;\r
+  UINTN      Idx;\r
+\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,\r
+                  NULL /* SearchKey */, &NoHandles, &Handles);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // This is not an error, just an informative condition.\r
+    //\r
+    DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,\r
+      Status));\r
+    return;\r
+  }\r
+\r
+  ASSERT (NoHandles > 0);\r
+  for (Idx = 0; Idx < NoHandles; ++Idx) {\r
+    CHAR16        *DevicePathText;\r
+    STATIC CHAR16 Fallback[] = L"<device path unavailable>";\r
+\r
+    //\r
+    // The ConvertDevicePathToText() function handles NULL input transparently.\r
+    //\r
+    DevicePathText = ConvertDevicePathToText (\r
+                       DevicePathFromHandle (Handles[Idx]),\r
+                       FALSE, // DisplayOnly\r
+                       FALSE  // AllowShortcuts\r
+                       );\r
+    if (DevicePathText == NULL) {\r
+      DevicePathText = Fallback;\r
+    }\r
+\r
+    if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {\r
+      Process (Handles[Idx], DevicePathText);\r
+    }\r
+\r
+    if (DevicePathText != Fallback) {\r
+      FreePool (DevicePathText);\r
+    }\r
+  }\r
+  gBS->FreePool (Handles);\r
+}\r
+\r
+\r
+/**\r
+  This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsPciDisplay (\r
+  IN EFI_HANDLE   Handle,\r
+  IN CONST CHAR16 *ReportText\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  PCI_TYPE00          Pci;\r
+\r
+  Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
+                  (VOID**)&PciIo);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // This is not an error worth reporting.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,\r
+                        sizeof Pci / sizeof (UINT32), &Pci);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
+    return FALSE;\r
+  }\r
+\r
+  return IS_PCI_DISPLAY (&Pci);\r
+}\r
+\r
+\r
+/**\r
+  This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
+  the matching driver to produce all first-level child handles.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Connect (\r
+  IN EFI_HANDLE   Handle,\r
+  IN CONST CHAR16 *ReportText\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  Status = gBS->ConnectController (\r
+                  Handle, // ControllerHandle\r
+                  NULL,   // DriverImageHandle\r
+                  NULL,   // RemainingDevicePath -- produce all children\r
+                  FALSE   // Recursive\r
+                  );\r
+  DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",\r
+    __FUNCTION__, ReportText, Status));\r
+}\r
+\r
+\r
+/**\r
+  This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the\r
+  handle, and adds it to ConOut and ErrOut.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+AddOutput (\r
+  IN EFI_HANDLE   Handle,\r
+  IN CONST CHAR16 *ReportText\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+  DevicePath = DevicePathFromHandle (Handle);\r
+  if (DevicePath == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",\r
+      __FUNCTION__, ReportText, Handle));\r
+    return;\r
+  }\r
+\r
+  Status = BdsLibUpdateConsoleVariable (L"ConOut", DevicePath, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,\r
+      ReportText, Status));\r
+    return;\r
+  }\r
+\r
+  Status = BdsLibUpdateConsoleVariable (L"ErrOut", DevicePath, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,\r
+      ReportText, Status));\r
+    return;\r
+  }\r
+\r
+  DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,\r
+    ReportText));\r
+}\r
+\r
+\r
+/**\r
+  The function will execute with as the platform policy, current policy\r
+  is driven by boot mode. IBV/OEM can customize this code for their specific\r
+  policy action.\r
+\r
+  @param  DriverOptionList        The header of the driver option link list\r
+  @param  BootOptionList          The header of the boot option link list\r
+  @param  ProcessCapsules         A pointer to ProcessCapsules()\r
+  @param  BaseMemoryTest          A pointer to BaseMemoryTest()\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBdsPolicyBehavior (\r
+  IN LIST_ENTRY                      *DriverOptionList,\r
+  IN LIST_ENTRY                      *BootOptionList,\r
+  IN PROCESS_CAPSULES                ProcessCapsules,\r
+  IN BASEM_MEMORY_TEST               BaseMemoryTest\r
+  )\r
+{\r
+  //\r
+  // Locate the PCI root bridges and make the PCI bus driver connect each,\r
+  // non-recursively. This will produce a number of child handles with PciIo on\r
+  // them.\r
+  //\r
+  FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);\r
+\r
+  //\r
+  // Signal the ACPI platform driver that it can download QEMU ACPI tables.\r
+  //\r
+  EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);\r
+\r
+  //\r
+  // Find all display class PCI devices (using the handles from the previous\r
+  // step), and connect them non-recursively. This should produce a number of\r
+  // child handles with GOPs on them.\r
+  //\r
+  FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);\r
+\r
+  //\r
+  // Now add the device path of all handles with GOP on them to ConOut and\r
+  // ErrOut.\r
+  //\r
+  FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
+\r
+  //\r
+  // Add the hardcoded short-form USB keyboard device path to ConIn.\r
+  //\r
+  BdsLibUpdateConsoleVariable (L"ConIn",\r
+    (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);\r
+\r
+  //\r
+  // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
+  //\r
+  CopyGuid (&mSerialConsole.TermType.Guid,\r
+    PcdGetPtr (PcdTerminalTypeGuidBuffer));\r
+  BdsLibUpdateConsoleVariable (L"ConIn",\r
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
+  BdsLibUpdateConsoleVariable (L"ConOut",\r
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
+  BdsLibUpdateConsoleVariable (L"ErrOut",\r
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);\r
+\r
+  //\r
+  // Connect the consoles based on the above variables.\r
+  //\r
+  BdsLibConnectAllDefaultConsoles ();\r
+\r
+  //\r
+  // Show the splash screen.\r
+  //\r
+  EnableQuietBoot (PcdGetPtr (PcdLogoFile));\r
+\r
+  //\r
+  // Connect the rest of the devices.\r
+  //\r
+  BdsLibConnectAll ();\r
+\r
+  //\r
+  // Process QEMU's -kernel command line option. Note that the kernel booted\r
+  // this way should receive ACPI tables, which is why we connect all devices\r
+  // first (see above) -- PCI enumeration blocks ACPI table installation, if\r
+  // there is a PCI host.\r
+  //\r
+  TryRunningQemuKernel ();\r
+\r
+  BdsLibEnumerateAllBootOption (BootOptionList);\r
+  SetBootOrderFromQemu (BootOptionList);\r
+  //\r
+  // The BootOrder variable may have changed, reload the in-memory list with\r
+  // it.\r
+  //\r
+  BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");\r
+\r
+  PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE);\r
+}\r
+\r
+/**\r
+  Hook point after a boot attempt succeeds. We don't expect a boot option to\r
+  return, so the UEFI 2.0 specification defines that you will default to an\r
+  interactive mode and stop processing the BootOrder list in this case. This\r
+  is also a platform implementation and can be customized by IBV/OEM.\r
+\r
+  @param  Option                  Pointer to Boot Option that succeeded to boot.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBdsBootSuccess (\r
+  IN  BDS_COMMON_OPTION *Option\r
+  )\r
+{\r
+}\r
+\r
+/**\r
+  Hook point after a boot attempt fails.\r
+\r
+  @param  Option                  Pointer to Boot Option that failed to boot.\r
+  @param  Status                  Status returned from failed boot.\r
+  @param  ExitData                Exit data returned from failed boot.\r
+  @param  ExitDataSize            Exit data size returned from failed boot.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBdsBootFail (\r
+  IN  BDS_COMMON_OPTION  *Option,\r
+  IN  EFI_STATUS         Status,\r
+  IN  CHAR16             *ExitData,\r
+  IN  UINTN              ExitDataSize\r
+  )\r
+{\r
+}\r
+\r
+/**\r
+  This function locks platform flash that is not allowed to be updated during normal boot path.\r
+  The flash layout is platform specific.\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBdsLockNonUpdatableFlash (\r
+  VOID\r
+  )\r
+{\r
+  return;\r
+}\r
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.h b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.h
new file mode 100644 (file)
index 0000000..410c309
--- /dev/null
@@ -0,0 +1,57 @@
+/** @file\r
+  Head file for BDS Platform specific code\r
+\r
+  Copyright (C) 2015-2016, Red Hat, Inc.\r
+  Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  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, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PLATFORM_BM_H_\r
+#define _PLATFORM_BM_H_\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+VOID\r
+PlatformBdsEnterFrontPage (\r
+  IN UINT16                 TimeoutDefault,\r
+  IN BOOLEAN                ConnectAllHappened\r
+  );\r
+\r
+/**\r
+  Download the kernel, the initial ramdisk, and the kernel command line from\r
+  QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two\r
+  image files, and load and start the kernel from it.\r
+\r
+  The kernel will be instructed via its command line to load the initrd from\r
+  the same Simple FileSystem.\r
+\r
+  @retval EFI_NOT_FOUND         Kernel image was not found.\r
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
+  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.\r
+\r
+  @return                       Error codes from any of the underlying\r
+                                functions. On success, the function doesn't\r
+                                return.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TryRunningQemuKernel (\r
+  VOID\r
+  );\r
+\r
+#endif // _PLATFORM_BM_H_\r
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
new file mode 100644 (file)
index 0000000..1ad4c6f
--- /dev/null
@@ -0,0 +1,81 @@
+## @file\r
+#  Implementation for PlatformBootManagerLib library class interfaces.\r
+#\r
+#  Copyright (C) 2015-2016, Red Hat, Inc.\r
+#  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>\r
+#  Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials are licensed and made available\r
+#  under the terms and conditions of the BSD License which accompanies this\r
+#  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\r
+#  IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PlatformIntelBdsLib\r
+  FILE_GUID                      = 469184E8-FADA-41E4-8823-012CA19B40D4\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = PlatformBdsLib|DXE_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = ARM AARCH64\r
+#\r
+\r
+[Sources]\r
+  PlatformBm.c\r
+  QemuKernel.c\r
+\r
+[Packages]\r
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  MdePkg/MdePkg.dec\r
+  OvmfPkg/OvmfPkg.dec\r
+  ArmVirtPkg/ArmVirtPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  DevicePathLib\r
+  GenericBdsLib\r
+  MemoryAllocationLib\r
+  PcdLib\r
+  PrintLib\r
+  QemuBootOrderLib\r
+  QemuFwCfgLib\r
+  UefiBootServicesTableLib\r
+  UefiLib\r
+  UefiRuntimeServicesTableLib\r
+\r
+[FixedPcd]\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile\r
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate\r
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits\r
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity\r
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits\r
+\r
+[Pcd]\r
+  gArmVirtTokenSpaceGuid.PcdTerminalTypeGuidBuffer\r
+\r
+[Guids]\r
+  gEfiFileInfoGuid\r
+  gEfiFileSystemInfoGuid\r
+  gEfiFileSystemVolumeLabelInfoIdGuid\r
+  gEfiEndOfDxeEventGroupGuid\r
+  gRootBridgesConnectedEventGroupGuid\r
+\r
+[Protocols]\r
+  gEfiDevicePathProtocolGuid\r
+  gEfiGraphicsOutputProtocolGuid\r
+  gEfiLoadedImageProtocolGuid\r
+  gEfiPciRootBridgeIoProtocolGuid\r
+  gEfiSimpleFileSystemProtocolGuid\r
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c b/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
new file mode 100644 (file)
index 0000000..ac47d21
--- /dev/null
@@ -0,0 +1,1115 @@
+/** @file\r
+  Try to load an EFI-stubbed ARM Linux kernel from QEMU's fw_cfg.\r
+\r
+  This implementation differs from OvmfPkg/Library/LoadLinuxLib. An EFI\r
+  stub in the subject kernel is a hard requirement here.\r
+\r
+  Copyright (C) 2014-2016, Red Hat, Inc.\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  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, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/FileSystemInfo.h>\r
+#include <Guid/FileSystemVolumeLabelInfo.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/QemuFwCfgLib.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+\r
+#include "PlatformBm.h"\r
+\r
+//\r
+// Static data that hosts the fw_cfg blobs and serves file requests.\r
+//\r
+typedef enum {\r
+  KernelBlobTypeKernel,\r
+  KernelBlobTypeInitrd,\r
+  KernelBlobTypeCommandLine,\r
+  KernelBlobTypeMax\r
+} KERNEL_BLOB_TYPE;\r
+\r
+typedef struct {\r
+  FIRMWARE_CONFIG_ITEM CONST SizeKey;\r
+  FIRMWARE_CONFIG_ITEM CONST DataKey;\r
+  CONST CHAR16 *       CONST Name;\r
+  UINT32                     Size;\r
+  UINT8                      *Data;\r
+} KERNEL_BLOB;\r
+\r
+STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {\r
+  { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      L"kernel"  },\r
+  { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      L"initrd"  },\r
+  { QemuFwCfgItemCommandLineSize, QemuFwCfgItemCommandLineData, L"cmdline" }\r
+};\r
+\r
+STATIC UINT64 mTotalBlobBytes;\r
+\r
+//\r
+// Device path for the handle that incorporates our "EFI stub filesystem". The\r
+// GUID is arbitrary and need not be standardized or advertized.\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH       VenHwNode;\r
+  EFI_DEVICE_PATH_PROTOCOL EndNode;\r
+} SINGLE_VENHW_NODE_DEVPATH;\r
+#pragma pack()\r
+\r
+STATIC CONST SINGLE_VENHW_NODE_DEVPATH mFileSystemDevicePath = {\r
+  {\r
+    { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH) } },\r
+    {\r
+      0xb0fae7e7, 0x6b07, 0x49d0,\r
+      { 0x9e, 0x5b, 0x3b, 0xde, 0xc8, 0x3b, 0x03, 0x9d }\r
+    }\r
+  },\r
+\r
+  {\r
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }\r
+  }\r
+};\r
+\r
+//\r
+// The "file in the EFI stub filesystem" abstraction.\r
+//\r
+STATIC EFI_TIME mInitTime;\r
+\r
+#define STUB_FILE_SIG SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')\r
+\r
+typedef struct {\r
+  UINT64            Signature; // Carries STUB_FILE_SIG.\r
+\r
+  KERNEL_BLOB_TYPE  BlobType;  // Index into mKernelBlob. KernelBlobTypeMax\r
+                               // denotes the root directory of the filesystem.\r
+\r
+  UINT64            Position;  // Byte position for regular files;\r
+                               // next directory entry to return for the root\r
+                               // directory.\r
+\r
+  EFI_FILE_PROTOCOL File;      // Standard protocol interface.\r
+} STUB_FILE;\r
+\r
+#define STUB_FILE_FROM_FILE(FilePointer) \\r
+        CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)\r
+\r
+//\r
+// Tentative definition of the file protocol template. The initializer\r
+// (external definition) will be provided later.\r
+//\r
+STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate;\r
+\r
+\r
+//\r
+// Protocol member functions for File.\r
+//\r
+\r
+/**\r
+  Opens a new file relative to the source file's location.\r
+\r
+  @param[in]  This        A pointer to the EFI_FILE_PROTOCOL instance that is\r
+                          the file handle to the source location. This would\r
+                          typically be an open handle to a directory.\r
+\r
+  @param[out] NewHandle   A pointer to the location to return the opened handle\r
+                          for the new file.\r
+\r
+  @param[in]  FileName    The Null-terminated string of the name of the file to\r
+                          be opened. The file name may contain the following\r
+                          path modifiers: "\", ".", and "..".\r
+\r
+  @param[in]  OpenMode    The mode to open the file. The only valid\r
+                          combinations that the file may be opened with are:\r
+                          Read, Read/Write, or Create/Read/Write.\r
+\r
+  @param[in]  Attributes  Only valid for EFI_FILE_MODE_CREATE, in which case\r
+                          these are the attribute bits for the newly created\r
+                          file.\r
+\r
+  @retval EFI_SUCCESS           The file was opened.\r
+  @retval EFI_NOT_FOUND         The specified file could not be found on the\r
+                                device.\r
+  @retval EFI_NO_MEDIA          The device has no medium.\r
+  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the\r
+                                medium is no longer supported.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED   An attempt was made to create a file, or open a\r
+                                file for write when the media is\r
+                                write-protected.\r
+  @retval EFI_ACCESS_DENIED     The service denied access to the file.\r
+  @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the\r
+                                file.\r
+  @retval EFI_VOLUME_FULL       The volume is full.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileOpen (\r
+  IN EFI_FILE_PROTOCOL  *This,\r
+  OUT EFI_FILE_PROTOCOL **NewHandle,\r
+  IN CHAR16             *FileName,\r
+  IN UINT64             OpenMode,\r
+  IN UINT64             Attributes\r
+  )\r
+{\r
+  CONST STUB_FILE *StubFile;\r
+  UINTN           BlobType;\r
+  STUB_FILE       *NewStubFile;\r
+\r
+  //\r
+  // We're read-only.\r
+  //\r
+  switch (OpenMode) {\r
+    case EFI_FILE_MODE_READ:\r
+      break;\r
+\r
+    case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:\r
+    case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:\r
+      return EFI_WRITE_PROTECTED;\r
+\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Only the root directory supports opening files in it.\r
+  //\r
+  StubFile = STUB_FILE_FROM_FILE (This);\r
+  if (StubFile->BlobType != KernelBlobTypeMax) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Locate the file.\r
+  //\r
+  for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {\r
+    if (StrCmp (FileName, mKernelBlob[BlobType].Name) == 0) {\r
+      break;\r
+    }\r
+  }\r
+  if (BlobType == KernelBlobTypeMax) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Found it.\r
+  //\r
+  NewStubFile = AllocatePool (sizeof *NewStubFile);\r
+  if (NewStubFile == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewStubFile->Signature = STUB_FILE_SIG;\r
+  NewStubFile->BlobType  = (KERNEL_BLOB_TYPE)BlobType;\r
+  NewStubFile->Position  = 0;\r
+  CopyMem (&NewStubFile->File, &mEfiFileProtocolTemplate,\r
+    sizeof mEfiFileProtocolTemplate);\r
+  *NewHandle = &NewStubFile->File;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Closes a specified file handle.\r
+\r
+  @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
+                   handle to close.\r
+\r
+  @retval EFI_SUCCESS  The file was closed.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileClose (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  )\r
+{\r
+  FreePool (STUB_FILE_FROM_FILE (This));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Close and delete the file handle.\r
+\r
+  @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the\r
+                   handle to the file to delete.\r
+\r
+  @retval EFI_SUCCESS              The file was closed and deleted, and the\r
+                                   handle was closed.\r
+  @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not\r
+                                   deleted.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileDelete (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  )\r
+{\r
+  FreePool (STUB_FILE_FROM_FILE (This));\r
+  return EFI_WARN_DELETE_FAILURE;\r
+}\r
+\r
+\r
+/**\r
+  Helper function that formats an EFI_FILE_INFO structure into the\r
+  user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including\r
+  KernelBlobTypeMax, which stands for the root directory).\r
+\r
+  The interface follows the EFI_FILE_GET_INFO -- and for directories, the\r
+  EFI_FILE_READ -- interfaces.\r
+\r
+  @param[in]     BlobType     The KERNEL_BLOB_TYPE value identifying the fw_cfg\r
+                              blob backing the STUB_FILE that information is\r
+                              being requested about. If BlobType equals\r
+                              KernelBlobTypeMax, then information will be\r
+                              provided about the root directory of the\r
+                              filesystem.\r
+\r
+  @param[in,out] BufferSize  On input, the size of Buffer. On output, the\r
+                             amount of data returned in Buffer. In both cases,\r
+                             the size is measured in bytes.\r
+\r
+  @param[out]    Buffer      A pointer to the data buffer to return. The\r
+                             buffer's type is EFI_FILE_INFO.\r
+\r
+  @retval EFI_SUCCESS           The information was returned.\r
+  @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small to store the\r
+                                EFI_FILE_INFO structure. BufferSize has been\r
+                                updated with the size needed to complete the\r
+                                request.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ConvertKernelBlobTypeToFileInfo (\r
+  IN KERNEL_BLOB_TYPE BlobType,\r
+  IN OUT UINTN        *BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+{\r
+  CONST CHAR16  *Name;\r
+  UINT64        FileSize;\r
+  UINT64        Attribute;\r
+\r
+  UINTN         NameSize;\r
+  UINTN         FileInfoSize;\r
+  EFI_FILE_INFO *FileInfo;\r
+  UINTN         OriginalBufferSize;\r
+\r
+  if (BlobType == KernelBlobTypeMax) {\r
+    //\r
+    // getting file info about the root directory\r
+    //\r
+    Name      = L"\\";\r
+    FileSize  = KernelBlobTypeMax;\r
+    Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
+  } else {\r
+    CONST KERNEL_BLOB *Blob;\r
+\r
+    Blob      = &mKernelBlob[BlobType];\r
+    Name      = Blob->Name;\r
+    FileSize  = Blob->Size;\r
+    Attribute = EFI_FILE_READ_ONLY;\r
+  }\r
+\r
+  NameSize     = (StrLen(Name) + 1) * 2;\r
+  FileInfoSize = OFFSET_OF (EFI_FILE_INFO, FileName) + NameSize;\r
+  ASSERT (FileInfoSize >= sizeof *FileInfo);\r
+\r
+  OriginalBufferSize = *BufferSize;\r
+  *BufferSize        = FileInfoSize;\r
+  if (OriginalBufferSize < *BufferSize) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  FileInfo               = (EFI_FILE_INFO *)Buffer;\r
+  FileInfo->Size         = FileInfoSize;\r
+  FileInfo->FileSize     = FileSize;\r
+  FileInfo->PhysicalSize = FileSize;\r
+  FileInfo->Attribute    = Attribute;\r
+\r
+  CopyMem (&FileInfo->CreateTime,       &mInitTime, sizeof mInitTime);\r
+  CopyMem (&FileInfo->LastAccessTime,   &mInitTime, sizeof mInitTime);\r
+  CopyMem (&FileInfo->ModificationTime, &mInitTime, sizeof mInitTime);\r
+  CopyMem (FileInfo->FileName,          Name,       NameSize);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Reads data from a file, or continues scanning a directory.\r
+\r
+  @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that\r
+                             is the file handle to read data from.\r
+\r
+  @param[in,out] BufferSize  On input, the size of the Buffer. On output, the\r
+                             amount of data returned in Buffer. In both cases,\r
+                             the size is measured in bytes. If the read goes\r
+                             beyond the end of the file, the read length is\r
+                             truncated to the end of the file.\r
+\r
+                             If This is a directory, the function reads the\r
+                             directory entry at the current position and\r
+                             returns the entry (as EFI_FILE_INFO) in Buffer. If\r
+                             there are no more directory entries, the\r
+                             BufferSize is set to zero on output.\r
+\r
+  @param[out]    Buffer      The buffer into which the data is read.\r
+\r
+  @retval EFI_SUCCESS           Data was read.\r
+  @retval EFI_NO_MEDIA          The device has no medium.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error.\r
+  @retval EFI_DEVICE_ERROR      An attempt was made to read from a deleted\r
+                                file.\r
+  @retval EFI_DEVICE_ERROR      On entry, the current file position is beyond\r
+                                the end of the file.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the\r
+                                current directory entry as a EFI_FILE_INFO\r
+                                structure. BufferSize has been updated with the\r
+                                size needed to complete the request, and the\r
+                                directory position has not been advanced.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileRead (\r
+  IN EFI_FILE_PROTOCOL *This,\r
+  IN OUT UINTN         *BufferSize,\r
+  OUT VOID             *Buffer\r
+  )\r
+{\r
+  STUB_FILE         *StubFile;\r
+  CONST KERNEL_BLOB *Blob;\r
+  UINT64            Left;\r
+\r
+  StubFile = STUB_FILE_FROM_FILE (This);\r
+\r
+  //\r
+  // Scanning the root directory?\r
+  //\r
+  if (StubFile->BlobType == KernelBlobTypeMax) {\r
+    EFI_STATUS Status;\r
+\r
+    if (StubFile->Position == KernelBlobTypeMax) {\r
+      //\r
+      // Scanning complete.\r
+      //\r
+      *BufferSize = 0;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    Status = ConvertKernelBlobTypeToFileInfo (\r
+               (KERNEL_BLOB_TYPE)StubFile->Position,\r
+               BufferSize,\r
+               Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    ++StubFile->Position;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Reading a file.\r
+  //\r
+  Blob = &mKernelBlob[StubFile->BlobType];\r
+  if (StubFile->Position > Blob->Size) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Left = Blob->Size - StubFile->Position;\r
+  if (*BufferSize > Left) {\r
+    *BufferSize = (UINTN)Left;\r
+  }\r
+  if (Blob->Data != NULL) {\r
+    CopyMem (Buffer, Blob->Data + StubFile->Position, *BufferSize);\r
+  }\r
+  StubFile->Position += *BufferSize;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Writes data to a file.\r
+\r
+  @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that\r
+                             is the file handle to write data to.\r
+\r
+  @param[in,out] BufferSize  On input, the size of the Buffer. On output, the\r
+                             amount of data actually written. In both cases,\r
+                             the size is measured in bytes.\r
+\r
+  @param[in]     Buffer      The buffer of data to write.\r
+\r
+  @retval EFI_SUCCESS           Data was written.\r
+  @retval EFI_UNSUPPORTED       Writes to open directory files are not\r
+                                supported.\r
+  @retval EFI_NO_MEDIA          The device has no medium.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error.\r
+  @retval EFI_DEVICE_ERROR      An attempt was made to write to a deleted file.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.\r
+  @retval EFI_ACCESS_DENIED     The file was opened read only.\r
+  @retval EFI_VOLUME_FULL       The volume is full.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileWrite (\r
+  IN EFI_FILE_PROTOCOL *This,\r
+  IN OUT UINTN         *BufferSize,\r
+  IN VOID              *Buffer\r
+  )\r
+{\r
+  STUB_FILE *StubFile;\r
+\r
+  StubFile = STUB_FILE_FROM_FILE (This);\r
+  return (StubFile->BlobType == KernelBlobTypeMax) ?\r
+         EFI_UNSUPPORTED :\r
+         EFI_WRITE_PROTECTED;\r
+}\r
+\r
+\r
+/**\r
+  Returns a file's current position.\r
+\r
+  @param[in]  This      A pointer to the EFI_FILE_PROTOCOL instance that is the\r
+                        file handle to get the current position on.\r
+\r
+  @param[out] Position  The address to return the file's current position\r
+                        value.\r
+\r
+  @retval EFI_SUCCESS      The position was returned.\r
+  @retval EFI_UNSUPPORTED  The request is not valid on open directories.\r
+  @retval EFI_DEVICE_ERROR An attempt was made to get the position from a\r
+                           deleted file.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileGetPosition (\r
+  IN EFI_FILE_PROTOCOL *This,\r
+  OUT UINT64           *Position\r
+  )\r
+{\r
+  STUB_FILE *StubFile;\r
+\r
+  StubFile = STUB_FILE_FROM_FILE (This);\r
+  if (StubFile->BlobType == KernelBlobTypeMax) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  *Position = StubFile->Position;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Sets a file's current position.\r
+\r
+  @param[in] This      A pointer to the EFI_FILE_PROTOCOL instance that is the\r
+                       file handle to set the requested position on.\r
+\r
+  @param[in] Position  The byte position from the start of the file to set. For\r
+                       regular files, MAX_UINT64 means "seek to end". For\r
+                       directories, zero means "rewind directory scan".\r
+\r
+  @retval EFI_SUCCESS       The position was set.\r
+  @retval EFI_UNSUPPORTED   The seek request for nonzero is not valid on open\r
+                            directories.\r
+  @retval EFI_DEVICE_ERROR  An attempt was made to set the position of a\r
+                            deleted file.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileSetPosition (\r
+  IN EFI_FILE_PROTOCOL *This,\r
+  IN UINT64            Position\r
+  )\r
+{\r
+  STUB_FILE   *StubFile;\r
+  KERNEL_BLOB *Blob;\r
+\r
+  StubFile = STUB_FILE_FROM_FILE (This);\r
+\r
+  if (StubFile->BlobType == KernelBlobTypeMax) {\r
+    if (Position == 0) {\r
+      //\r
+      // rewinding a directory scan is allowed\r
+      //\r
+      StubFile->Position = 0;\r
+      return EFI_SUCCESS;\r
+    }\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // regular file seek\r
+  //\r
+  Blob = &mKernelBlob[StubFile->BlobType];\r
+  if (Position == MAX_UINT64) {\r
+    //\r
+    // seek to end\r
+    //\r
+    StubFile->Position = Blob->Size;\r
+  } else {\r
+    //\r
+    // absolute seek from beginning -- seeking past the end is allowed\r
+    //\r
+    StubFile->Position = Position;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Returns information about a file.\r
+\r
+  @param[in]     This             A pointer to the EFI_FILE_PROTOCOL instance\r
+                                  that is the file handle the requested\r
+                                  information is for.\r
+\r
+  @param[in]     InformationType  The type identifier GUID for the information\r
+                                  being requested. The following information\r
+                                  types are supported, storing the\r
+                                  corresponding structures in Buffer:\r
+\r
+                                  - gEfiFileInfoGuid: EFI_FILE_INFO\r
+\r
+                                  - gEfiFileSystemInfoGuid:\r
+                                    EFI_FILE_SYSTEM_INFO\r
+\r
+                                  - gEfiFileSystemVolumeLabelInfoIdGuid:\r
+                                    EFI_FILE_SYSTEM_VOLUME_LABEL\r
+\r
+  @param[in,out] BufferSize       On input, the size of Buffer. On output, the\r
+                                  amount of data returned in Buffer. In both\r
+                                  cases, the size is measured in bytes.\r
+\r
+  @param[out]    Buffer           A pointer to the data buffer to return. The\r
+                                  buffer's type is indicated by\r
+                                  InformationType.\r
+\r
+  @retval EFI_SUCCESS           The information was returned.\r
+  @retval EFI_UNSUPPORTED       The InformationType is not known.\r
+  @retval EFI_NO_MEDIA          The device has no medium.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the\r
+                                information structure requested by\r
+                                InformationType. BufferSize has been updated\r
+                                with the size needed to complete the request.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileGetInfo (\r
+  IN EFI_FILE_PROTOCOL *This,\r
+  IN EFI_GUID          *InformationType,\r
+  IN OUT UINTN         *BufferSize,\r
+  OUT VOID             *Buffer\r
+  )\r
+{\r
+  CONST STUB_FILE *StubFile;\r
+  UINTN           OriginalBufferSize;\r
+\r
+  StubFile = STUB_FILE_FROM_FILE (This);\r
+\r
+  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
+    return ConvertKernelBlobTypeToFileInfo (StubFile->BlobType, BufferSize,\r
+             Buffer);\r
+  }\r
+\r
+  OriginalBufferSize = *BufferSize;\r
+\r
+  if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
+    EFI_FILE_SYSTEM_INFO *FileSystemInfo;\r
+\r
+    *BufferSize = sizeof *FileSystemInfo;\r
+    if (OriginalBufferSize < *BufferSize) {\r
+      return EFI_BUFFER_TOO_SMALL;\r
+    }\r
+\r
+    FileSystemInfo                 = (EFI_FILE_SYSTEM_INFO *)Buffer;\r
+    FileSystemInfo->Size           = sizeof *FileSystemInfo;\r
+    FileSystemInfo->ReadOnly       = TRUE;\r
+    FileSystemInfo->VolumeSize     = mTotalBlobBytes;\r
+    FileSystemInfo->FreeSpace      = 0;\r
+    FileSystemInfo->BlockSize      = 1;\r
+    FileSystemInfo->VolumeLabel[0] = L'\0';\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+    EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;\r
+\r
+    *BufferSize = sizeof *FileSystemVolumeLabel;\r
+    if (OriginalBufferSize < *BufferSize) {\r
+      return EFI_BUFFER_TOO_SMALL;\r
+    }\r
+\r
+    FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;\r
+    FileSystemVolumeLabel->VolumeLabel[0] = L'\0';\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Sets information about a file.\r
+\r
+  @param[in] File             A pointer to the EFI_FILE_PROTOCOL instance that\r
+                              is the file handle the information is for.\r
+\r
+  @param[in] InformationType  The type identifier for the information being\r
+                              set.\r
+\r
+  @param[in] BufferSize       The size, in bytes, of Buffer.\r
+\r
+  @param[in] Buffer           A pointer to the data buffer to write. The\r
+                              buffer's type is indicated by InformationType.\r
+\r
+  @retval EFI_SUCCESS           The information was set.\r
+  @retval EFI_UNSUPPORTED       The InformationType is not known.\r
+  @retval EFI_NO_MEDIA          The device has no medium.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED   InformationType is EFI_FILE_INFO_ID and the\r
+                                media is read-only.\r
+  @retval EFI_WRITE_PROTECTED   InformationType is\r
+                                EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media\r
+                                is read only.\r
+  @retval EFI_WRITE_PROTECTED   InformationType is\r
+                                EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media\r
+                                is read-only.\r
+  @retval EFI_ACCESS_DENIED     An attempt is made to change the name of a file\r
+                                to a file that is already present.\r
+  @retval EFI_ACCESS_DENIED     An attempt is being made to change the\r
+                                EFI_FILE_DIRECTORY Attribute.\r
+  @retval EFI_ACCESS_DENIED     An attempt is being made to change the size of\r
+                                a directory.\r
+  @retval EFI_ACCESS_DENIED     InformationType is EFI_FILE_INFO_ID and the\r
+                                file was opened read-only and an attempt is\r
+                                being made to modify a field other than\r
+                                Attribute.\r
+  @retval EFI_VOLUME_FULL       The volume is full.\r
+  @retval EFI_BAD_BUFFER_SIZE   BufferSize is smaller than the size of the type\r
+                                indicated by InformationType.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileSetInfo (\r
+  IN EFI_FILE_PROTOCOL *This,\r
+  IN EFI_GUID          *InformationType,\r
+  IN UINTN             BufferSize,\r
+  IN VOID              *Buffer\r
+  )\r
+{\r
+  return EFI_WRITE_PROTECTED;\r
+}\r
+\r
+\r
+/**\r
+  Flushes all modified data associated with a file to a device.\r
+\r
+  @param [in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the\r
+                    file handle to flush.\r
+\r
+  @retval EFI_SUCCESS           The data was flushed.\r
+  @retval EFI_NO_MEDIA          The device has no medium.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.\r
+  @retval EFI_ACCESS_DENIED     The file was opened read-only.\r
+  @retval EFI_VOLUME_FULL       The volume is full.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileFlush (\r
+  IN EFI_FILE_PROTOCOL *This\r
+  )\r
+{\r
+  return EFI_WRITE_PROTECTED;\r
+}\r
+\r
+//\r
+// External definition of the file protocol template.\r
+//\r
+STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = {\r
+  EFI_FILE_PROTOCOL_REVISION, // revision 1\r
+  StubFileOpen,\r
+  StubFileClose,\r
+  StubFileDelete,\r
+  StubFileRead,\r
+  StubFileWrite,\r
+  StubFileGetPosition,\r
+  StubFileSetPosition,\r
+  StubFileGetInfo,\r
+  StubFileSetInfo,\r
+  StubFileFlush,\r
+  NULL,                       // OpenEx, revision 2\r
+  NULL,                       // ReadEx, revision 2\r
+  NULL,                       // WriteEx, revision 2\r
+  NULL                        // FlushEx, revision 2\r
+};\r
+\r
+\r
+//\r
+// Protocol member functions for SimpleFileSystem.\r
+//\r
+\r
+/**\r
+  Open the root directory on a volume.\r
+\r
+  @param[in]  This  A pointer to the volume to open the root directory on.\r
+\r
+  @param[out] Root  A pointer to the location to return the opened file handle\r
+                    for the root directory in.\r
+\r
+  @retval EFI_SUCCESS           The device was opened.\r
+  @retval EFI_UNSUPPORTED       This volume does not support the requested file\r
+                                system type.\r
+  @retval EFI_NO_MEDIA          The device has no medium.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
+  @retval EFI_ACCESS_DENIED     The service denied access to the file.\r
+  @retval EFI_OUT_OF_RESOURCES  The volume was not opened due to lack of\r
+                                resources.\r
+  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the\r
+                                medium is no longer supported. Any existing\r
+                                file handles for this volume are no longer\r
+                                valid. To access the files on the new medium,\r
+                                the volume must be reopened with OpenVolume().\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+StubFileSystemOpenVolume (\r
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
+  OUT EFI_FILE_PROTOCOL              **Root\r
+  )\r
+{\r
+  STUB_FILE *StubFile;\r
+\r
+  StubFile = AllocatePool (sizeof *StubFile);\r
+  if (StubFile == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  StubFile->Signature = STUB_FILE_SIG;\r
+  StubFile->BlobType  = KernelBlobTypeMax;\r
+  StubFile->Position  = 0;\r
+  CopyMem (&StubFile->File, &mEfiFileProtocolTemplate,\r
+    sizeof mEfiFileProtocolTemplate);\r
+  *Root = &StubFile->File;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,\r
+  StubFileSystemOpenVolume\r
+};\r
+\r
+\r
+//\r
+// Utility functions.\r
+//\r
+\r
+/**\r
+  Populate a blob in mKernelBlob.\r
+\r
+  param[in,out] Blob  Pointer to the KERNEL_BLOB element in mKernelBlob that is\r
+                      to be filled from fw_cfg.\r
+\r
+  @retval EFI_SUCCESS           Blob has been populated. If fw_cfg reported a\r
+                                size of zero for the blob, then Blob->Data has\r
+                                been left unchanged.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for Blob->Data.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+FetchBlob (\r
+  IN OUT KERNEL_BLOB *Blob\r
+  )\r
+{\r
+  UINT32 Left;\r
+\r
+  //\r
+  // Read blob size.\r
+  //\r
+  QemuFwCfgSelectItem (Blob->SizeKey);\r
+  Blob->Size = QemuFwCfgRead32 ();\r
+  if (Blob->Size == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Read blob.\r
+  //\r
+  Blob->Data = AllocatePool (Blob->Size);\r
+  if (Blob->Data == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "%a: failed to allocate %Ld bytes for \"%s\"\n",\r
+      __FUNCTION__, (INT64)Blob->Size, Blob->Name));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__,\r
+    (INT64)Blob->Size, Blob->Name));\r
+  QemuFwCfgSelectItem (Blob->DataKey);\r
+\r
+  Left = Blob->Size;\r
+  do {\r
+    UINT32 Chunk;\r
+\r
+    Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;\r
+    QemuFwCfgReadBytes (Chunk, Blob->Data + (Blob->Size - Left));\r
+    Left -= Chunk;\r
+    DEBUG ((EFI_D_VERBOSE, "%a: %Ld bytes remaining for \"%s\"\n",\r
+      __FUNCTION__, (INT64)Left, Blob->Name));\r
+  } while (Left > 0);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+//\r
+// The entry point of the feature.\r
+//\r
+\r
+/**\r
+  Download the kernel, the initial ramdisk, and the kernel command line from\r
+  QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two\r
+  image files, and load and start the kernel from it.\r
+\r
+  The kernel will be instructed via its command line to load the initrd from\r
+  the same Simple FileSystem.\r
+\r
+  @retval EFI_NOT_FOUND         Kernel image was not found.\r
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
+  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.\r
+\r
+  @return                       Error codes from any of the underlying\r
+                                functions. On success, the function doesn't\r
+                                return.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TryRunningQemuKernel (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                     BlobType;\r
+  KERNEL_BLOB               *CurrentBlob;\r
+  KERNEL_BLOB               *KernelBlob, *InitrdBlob, *CommandLineBlob;\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                FileSystemHandle;\r
+  EFI_DEVICE_PATH_PROTOCOL  *KernelDevicePath;\r
+  EFI_HANDLE                KernelImageHandle;\r
+  EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;\r
+\r
+  Status = gRT->GetTime (&mInitTime, NULL /* Capabilities */);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a: GetTime(): %r\n", __FUNCTION__, Status));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Fetch all blobs.\r
+  //\r
+  for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {\r
+    CurrentBlob = &mKernelBlob[BlobType];\r
+    Status = FetchBlob (CurrentBlob);\r
+    if (EFI_ERROR (Status)) {\r
+      goto FreeBlobs;\r
+    }\r
+    mTotalBlobBytes += CurrentBlob->Size;\r
+  }\r
+  KernelBlob      = &mKernelBlob[KernelBlobTypeKernel];\r
+  InitrdBlob      = &mKernelBlob[KernelBlobTypeInitrd];\r
+  CommandLineBlob = &mKernelBlob[KernelBlobTypeCommandLine];\r
+\r
+  if (KernelBlob->Data == NULL) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto FreeBlobs;\r
+  }\r
+\r
+  //\r
+  // Create a new handle with a single VenHw() node device path protocol on it,\r
+  // plus a custom SimpleFileSystem protocol on it.\r
+  //\r
+  FileSystemHandle = NULL;\r
+  Status = gBS->InstallMultipleProtocolInterfaces (&FileSystemHandle,\r
+                  &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,\r
+                  &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,\r
+                  NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a: InstallMultipleProtocolInterfaces(): %r\n",\r
+      __FUNCTION__, Status));\r
+    goto FreeBlobs;\r
+  }\r
+\r
+  //\r
+  // Create a device path for the kernel image to be loaded from that will call\r
+  // back into our file system.\r
+  //\r
+  KernelDevicePath = FileDevicePath (FileSystemHandle, KernelBlob->Name);\r
+  if (KernelDevicePath == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "%a: failed to allocate kernel device path\n",\r
+      __FUNCTION__));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto UninstallProtocols;\r
+  }\r
+\r
+  //\r
+  // Load the image. This should call back into our file system.\r
+  //\r
+  Status = gBS->LoadImage (\r
+                  FALSE,             // BootPolicy: exact match required\r
+                  gImageHandle,      // ParentImageHandle\r
+                  KernelDevicePath,\r
+                  NULL,              // SourceBuffer\r
+                  0,                 // SourceSize\r
+                  &KernelImageHandle\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status));\r
+    goto FreeKernelDevicePath;\r
+  }\r
+\r
+  //\r
+  // Construct the kernel command line.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  KernelImageHandle,\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  (VOID **)&KernelLoadedImage,\r
+                  gImageHandle,                  // AgentHandle\r
+                  NULL,                          // ControllerHandle\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (CommandLineBlob->Data == NULL) {\r
+    KernelLoadedImage->LoadOptionsSize = 0;\r
+  } else {\r
+    //\r
+    // Verify NUL-termination of the command line.\r
+    //\r
+    if (CommandLineBlob->Data[CommandLineBlob->Size - 1] != '\0') {\r
+      DEBUG ((EFI_D_ERROR, "%a: kernel command line is not NUL-terminated\n",\r
+        __FUNCTION__));\r
+      Status = EFI_PROTOCOL_ERROR;\r
+      goto UnloadKernelImage;\r
+    }\r
+\r
+    //\r
+    // Drop the terminating NUL, convert to UTF-16.\r
+    //\r
+    KernelLoadedImage->LoadOptionsSize = (CommandLineBlob->Size - 1) * 2;\r
+  }\r
+\r
+  if (InitrdBlob->Data != NULL) {\r
+    //\r
+    // Append ' initrd=<name>' in UTF-16.\r
+    //\r
+    KernelLoadedImage->LoadOptionsSize +=\r
+                                        (8 + StrLen(InitrdBlob->Name)) * 2;\r
+  }\r
+\r
+  if (KernelLoadedImage->LoadOptionsSize == 0) {\r
+    KernelLoadedImage->LoadOptions = NULL;\r
+  } else {\r
+    //\r
+    // NUL-terminate in UTF-16.\r
+    //\r
+    KernelLoadedImage->LoadOptionsSize += 2;\r
+\r
+    KernelLoadedImage->LoadOptions = AllocatePool (\r
+                                       KernelLoadedImage->LoadOptionsSize);\r
+    if (KernelLoadedImage->LoadOptions == NULL) {\r
+      KernelLoadedImage->LoadOptionsSize = 0;\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto UnloadKernelImage;\r
+    }\r
+\r
+    UnicodeSPrintAsciiFormat (\r
+      KernelLoadedImage->LoadOptions,\r
+      KernelLoadedImage->LoadOptionsSize,\r
+      "%a%a%s",\r
+      (CommandLineBlob->Data == NULL) ?  "" : (CHAR8 *)CommandLineBlob->Data,\r
+      (InitrdBlob->Data      == NULL) ?  "" : " initrd=",\r
+      (InitrdBlob->Data      == NULL) ? L"" : InitrdBlob->Name\r
+      );\r
+    DEBUG ((EFI_D_INFO, "%a: command line: \"%s\"\n", __FUNCTION__,\r
+      (CHAR16 *)KernelLoadedImage->LoadOptions));\r
+  }\r
+\r
+  //\r
+  // Signal the EFI_EVENT_GROUP_READY_TO_BOOT event.\r
+  //\r
+  EfiSignalEventReadyToBoot();\r
+\r
+  //\r
+  // Start the image.\r
+  //\r
+  Status = gBS->StartImage (\r
+                KernelImageHandle,\r
+                NULL,              // ExitDataSize\r
+                NULL               // ExitData\r
+                );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a: StartImage(): %r\n", __FUNCTION__, Status));\r
+  }\r
+\r
+  if (KernelLoadedImage->LoadOptions != NULL) {\r
+    FreePool (KernelLoadedImage->LoadOptions);\r
+  }\r
+  KernelLoadedImage->LoadOptionsSize = 0;\r
+\r
+UnloadKernelImage:\r
+  gBS->UnloadImage (KernelImageHandle);\r
+\r
+FreeKernelDevicePath:\r
+  FreePool (KernelDevicePath);\r
+\r
+UninstallProtocols:\r
+  gBS->UninstallMultipleProtocolInterfaces (FileSystemHandle,\r
+         &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,\r
+         &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,\r
+         NULL);\r
+\r
+FreeBlobs:\r
+  while (BlobType > 0) {\r
+    CurrentBlob = &mKernelBlob[--BlobType];\r
+    if (CurrentBlob->Data != NULL) {\r
+      FreePool (CurrentBlob->Data);\r
+      CurrentBlob->Size = 0;\r
+      CurrentBlob->Data = NULL;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r