]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
OvmfPkg: extract QemuBootOrderLib
[mirror_edk2.git] / OvmfPkg / Library / PlatformBdsLib / BdsPlatform.c
index 0afec23606dfea17982c8e90d64416d523b31197..341f5c15963d2605c5fd2681032657a6636b11f7 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   Platform BDS customizations.\r
 \r
-  Copyright (c) 2004 - 2008, Intel Corporation. <BR>\r
-  All rights reserved. This program and the accompanying materials\r
+  Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>\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
 \r
 #include "BdsPlatform.h"\r
+#include <Library/QemuBootOrderLib.h>\r
 \r
 \r
+//\r
+// Global data\r
+//\r
+\r
+VOID          *mEfiDevPathNotifyReg;\r
+EFI_EVENT     mEfiDevPathEvent;\r
+VOID          *mEmuVariableEventReg;\r
+EFI_EVENT     mEmuVariableEvent;\r
+BOOLEAN       mDetectVgaOnly;\r
+UINT16        mHostBridgeDevId;\r
+\r
+//\r
+// Table of host IRQs matching PCI IRQs A-D\r
+// (for configuring PCI Interrupt Line register)\r
+//\r
+CONST UINT8 PciHostIrqs[] = {\r
+  0x0a, 0x0a, 0x0b, 0x0b\r
+};\r
+\r
+//\r
+// Array Size macro\r
+//\r
+#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))\r
+\r
+//\r
+// Type definitions\r
+//\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(\r
+  IN EFI_HANDLE           Handle,\r
+  IN VOID                 *Instance,\r
+  IN VOID                 *Context\r
+  );\r
+\r
+/**\r
+  @param[in]  Handle - Handle of PCI device instance\r
+  @param[in]  PciIo - PCI IO protocol instance\r
+  @param[in]  Pci - PCI Header register block\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(\r
+  IN EFI_HANDLE           Handle,\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN PCI_TYPE00           *Pci\r
+  );\r
+\r
+\r
+//\r
+// Function prototypes\r
+//\r
+\r
+EFI_STATUS\r
+VisitAllInstancesOfProtocol (\r
+  IN EFI_GUID                    *Id,\r
+  IN PROTOCOL_INSTANCE_CALLBACK  CallBackFunction,\r
+  IN VOID                        *Context\r
+  );\r
+\r
+EFI_STATUS\r
+VisitAllPciInstancesOfProtocol (\r
+  IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
+  );\r
+\r
+VOID\r
+InstallDevicePathCallback (\r
+  VOID\r
+  );\r
+\r
 //\r
 // BDS Platform Functions\r
 //\r
 VOID\r
 EFIAPI\r
 PlatformBdsInit (\r
-  IN EFI_BDS_ARCH_PROTOCOL_INSTANCE  *PrivateData\r
+  VOID\r
   )\r
 /*++\r
 \r
@@ -32,8 +104,6 @@ Routine Description:
 \r
 Arguments:\r
 \r
-  PrivateData  - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance\r
-\r
 Returns:\r
 \r
   None.\r
@@ -41,6 +111,7 @@ Returns:
 --*/\r
 {\r
   DEBUG ((EFI_D_INFO, "PlatformBdsInit\n"));\r
+  InstallDevicePathCallback ();\r
 }\r
 \r
 \r
@@ -151,14 +222,16 @@ Returns:
   // Print Device Path\r
   //\r
   DevPathStr = DevicePathToStr(DevicePath);\r
-  DEBUG((\r
-    EFI_D_INFO,\r
-    "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
-    __LINE__,\r
-    gPnp16550ComPortDeviceNode.UID + 1,\r
-    DevPathStr\r
-    ));\r
-  FreePool(DevPathStr);\r
+  if (DevPathStr != NULL) {\r
+    DEBUG((\r
+      EFI_D_INFO,\r
+      "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
+      __LINE__,\r
+      gPnp16550ComPortDeviceNode.UID + 1,\r
+      DevPathStr\r
+      ));\r
+    FreePool(DevPathStr);\r
+  }\r
 \r
   BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);\r
   BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);\r
@@ -178,14 +251,16 @@ Returns:
   // Print Device Path\r
   //\r
   DevPathStr = DevicePathToStr(DevicePath);\r
-  DEBUG((\r
-    EFI_D_INFO,\r
-    "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
-    __LINE__,\r
-    gPnp16550ComPortDeviceNode.UID + 1,\r
-    DevPathStr\r
-    ));\r
-  FreePool(DevPathStr);\r
+  if (DevPathStr != NULL) {\r
+    DEBUG((\r
+      EFI_D_INFO,\r
+      "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
+      __LINE__,\r
+      gPnp16550ComPortDeviceNode.UID + 1,\r
+      DevPathStr\r
+      ));\r
+    FreePool(DevPathStr);\r
+  }\r
 \r
   BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);\r
   BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);\r
@@ -305,7 +380,8 @@ Returns:
   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
   EFI_DEVICE_PATH_PROTOCOL  *GopDevicePath;\r
 \r
-  DevicePath = NULL;\r
+  DevicePath    = NULL;\r
+  GopDevicePath = NULL;\r
   Status = gBS->HandleProtocol (\r
                   DeviceHandle,\r
                   &gEfiDevicePathProtocolGuid,\r
@@ -369,32 +445,17 @@ Returns:
 }\r
 \r
 EFI_STATUS\r
-DetectAndPreparePlatformPciDevicePath (\r
-  BOOLEAN DetectVgaOnly\r
+VisitAllInstancesOfProtocol (\r
+  IN EFI_GUID                    *Id,\r
+  IN PROTOCOL_INSTANCE_CALLBACK  CallBackFunction,\r
+  IN VOID                        *Context\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut\r
-\r
-Arguments:\r
-\r
-  DetectVgaOnly           - Only detect VGA device if it's TRUE.\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS             - PCI Device check and Console variable update successfully.\r
-  EFI_STATUS              - PCI Device check or Console variable update fail.\r
-\r
---*/\r
 {\r
   EFI_STATUS                Status;\r
   UINTN                     HandleCount;\r
   EFI_HANDLE                *HandleBuffer;\r
   UINTN                     Index;\r
-  EFI_PCI_IO_PROTOCOL       *PciIo;\r
-  PCI_TYPE00                Pci;\r
+  VOID                      *Instance;\r
 \r
   //\r
   // Start to check all the PciIo to find all possible device\r
@@ -403,7 +464,7 @@ Returns:
   HandleBuffer = NULL;\r
   Status = gBS->LocateHandleBuffer (\r
                   ByProtocol,\r
-                  &gEfiPciIoProtocolGuid,\r
+                  Id,\r
                   NULL,\r
                   &HandleCount,\r
                   &HandleBuffer\r
@@ -413,89 +474,168 @@ Returns:
   }\r
 \r
   for (Index = 0; Index < HandleCount; Index++) {\r
-    Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID*)&PciIo);\r
+    Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);\r
     if (EFI_ERROR (Status)) {\r
       continue;\r
     }\r
 \r
+    Status = (*CallBackFunction) (\r
+               HandleBuffer[Index],\r
+               Instance,\r
+               Context\r
+               );\r
+  }\r
+\r
+  gBS->FreePool (HandleBuffer);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VisitingAPciInstance (\r
+  IN EFI_HANDLE  Handle,\r
+  IN VOID        *Instance,\r
+  IN VOID        *Context\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  PCI_TYPE00                Pci;\r
+\r
+  PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;\r
+\r
+  //\r
+  // Check for all PCI device\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                    PciIo,\r
+                    EfiPciIoWidthUint32,\r
+                    0,\r
+                    sizeof (Pci) / sizeof (UINT32),\r
+                    &Pci\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (\r
+           Handle,\r
+           PciIo,\r
+           &Pci\r
+           );\r
+\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+VisitAllPciInstances (\r
+  IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
+  )\r
+{\r
+  return VisitAllInstancesOfProtocol (\r
+           &gEfiPciIoProtocolGuid,\r
+           VisitingAPciInstance,\r
+           (VOID*)(UINTN) CallBackFunction\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Do platform specific PCI Device check and add them to\r
+  ConOut, ConIn, ErrOut.\r
+\r
+  @param[in]  Handle - Handle of PCI device instance\r
+  @param[in]  PciIo - PCI IO protocol instance\r
+  @param[in]  Pci - PCI Header register block\r
+\r
+  @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.\r
+  @retval EFI_STATUS - PCI Device check or Console variable update fail.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DetectAndPreparePlatformPciDevicePath (\r
+  IN EFI_HANDLE           Handle,\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN PCI_TYPE00           *Pci\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  Status = PciIo->Attributes (\r
+    PciIo,\r
+    EfiPciIoAttributeOperationEnable,\r
+    EFI_PCI_DEVICE_ENABLE,\r
+    NULL\r
+    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (!mDetectVgaOnly) {\r
     //\r
-    // Check for all PCI device\r
+    // Here we decide whether it is LPC Bridge\r
     //\r
-    Status = PciIo->Pci.Read (\r
-                      PciIo,\r
-                      EfiPciIoWidthUint32,\r
-                      0,\r
-                      sizeof (Pci) / sizeof (UINT32),\r
-                      &Pci\r
-                      );\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-\r
-    if (!DetectVgaOnly) {\r
-      //\r
-      // Here we decide whether it is LPC Bridge\r
-      //\r
-      if ((IS_PCI_LPC (&Pci)) ||\r
-          ((IS_PCI_ISA_PDECODE (&Pci)) &&\r
-           (Pci.Hdr.VendorId == 0x8086) &&\r
-           (Pci.Hdr.DeviceId == 0x7000)\r
-          )\r
-         ) {\r
-        Status = PciIo->Attributes (\r
-          PciIo,\r
-          EfiPciIoAttributeOperationEnable,\r
-          EFI_PCI_DEVICE_ENABLE,\r
-          NULL\r
-          );\r
-        //\r
-        // Add IsaKeyboard to ConIn,\r
-        // add IsaSerial to ConOut, ConIn, ErrOut\r
-        //\r
-        DEBUG ((EFI_D_INFO, "Find the LPC Bridge device\n"));\r
-        PrepareLpcBridgeDevicePath (HandleBuffer[Index]);\r
-        continue;\r
-      }\r
+    if ((IS_PCI_LPC (Pci)) ||\r
+        ((IS_PCI_ISA_PDECODE (Pci)) &&\r
+         (Pci->Hdr.VendorId == 0x8086) &&\r
+         (Pci->Hdr.DeviceId == 0x7000)\r
+        )\r
+       ) {\r
       //\r
-      // Here we decide which Serial device to enable in PCI bus\r
+      // Add IsaKeyboard to ConIn,\r
+      // add IsaSerial to ConOut, ConIn, ErrOut\r
       //\r
-      if (IS_PCI_16550SERIAL (&Pci)) {\r
-        //\r
-        // Add them to ConOut, ConIn, ErrOut.\r
-        //\r
-        DEBUG ((EFI_D_INFO, "Find the 16550 SERIAL device\n"));\r
-        PreparePciSerialDevicePath (HandleBuffer[Index]);\r
-        continue;\r
-      }\r
+      DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));\r
+      PrepareLpcBridgeDevicePath (Handle);\r
+      return EFI_SUCCESS;\r
     }\r
-\r
-    if ((Pci.Hdr.VendorId == 0x8086) &&\r
-        (Pci.Hdr.DeviceId == 0x7010)\r
-       ) {\r
-      Status = PciIo->Attributes (\r
-        PciIo,\r
-        EfiPciIoAttributeOperationEnable,\r
-        EFI_PCI_DEVICE_ENABLE,\r
-        NULL\r
-        );\r
-     }\r
-\r
     //\r
-    // Here we decide which VGA device to enable in PCI bus\r
+    // Here we decide which Serial device to enable in PCI bus\r
     //\r
-    if (IS_PCI_VGA (&Pci)) {\r
+    if (IS_PCI_16550SERIAL (Pci)) {\r
       //\r
-      // Add them to ConOut.\r
+      // Add them to ConOut, ConIn, ErrOut.\r
       //\r
-      DEBUG ((EFI_D_INFO, "Find the VGA device\n"));\r
-      PreparePciVgaDevicePath (HandleBuffer[Index]);\r
-      continue;\r
+      DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));\r
+      PreparePciSerialDevicePath (Handle);\r
+      return EFI_SUCCESS;\r
     }\r
   }\r
 \r
-  gBS->FreePool (HandleBuffer);\r
+  //\r
+  // Here we decide which VGA device to enable in PCI bus\r
+  //\r
+  if (IS_PCI_VGA (Pci)) {\r
+    //\r
+    // Add them to ConOut.\r
+    //\r
+    DEBUG ((EFI_D_INFO, "Found PCI VGA device\n"));\r
+    PreparePciVgaDevicePath (Handle);\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut\r
+\r
+  @param[in]  DetectVgaOnly - Only detect VGA device if it's TRUE.\r
+\r
+  @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.\r
+  @retval EFI_STATUS - PCI Device check or Console variable update fail.\r
+\r
+**/\r
+EFI_STATUS\r
+DetectAndPreparePlatformPciDevicePaths (\r
+  BOOLEAN DetectVgaOnly\r
+  )\r
+{\r
+  mDetectVgaOnly = DetectVgaOnly;\r
+  return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);\r
 }\r
 \r
 \r
@@ -534,8 +674,6 @@ Returns:
   //\r
   // Connect RootBridge\r
   //\r
-  ConnectRootBridge ();\r
-\r
   VarConout = BdsLibGetVariableAndSize (\r
                 VarConsoleOut,\r
                 &gEfiGlobalVariableGuid,\r
@@ -551,7 +689,7 @@ Returns:
     //\r
     // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut\r
     //\r
-    DetectAndPreparePlatformPciDevicePath (FALSE);\r
+    DetectAndPreparePlatformPciDevicePaths (FALSE);\r
 \r
     //\r
     // Have chance to connect the platform default console,\r
@@ -576,7 +714,7 @@ Returns:
     //\r
     // Only detect VGA device and add them to ConOut\r
     //\r
-    DetectAndPreparePlatformPciDevicePath (TRUE);\r
+    DetectAndPreparePlatformPciDevicePaths (TRUE);\r
   }\r
 \r
   //\r
@@ -591,47 +729,292 @@ Returns:
 }\r
 \r
 \r
+/**\r
+  Configure PCI Interrupt Line register for applicable devices\r
+  Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()\r
+\r
+  @param[in]  Handle - Handle of PCI device instance\r
+  @param[in]  PciIo - PCI IO protocol instance\r
+  @param[in]  PciHdr - PCI Header register block\r
+\r
+  @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetPciIntLine (\r
+  IN EFI_HANDLE           Handle,\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN PCI_TYPE00           *PciHdr\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;\r
+  UINTN                     RootSlot;\r
+  UINTN                     Idx;\r
+  UINT8                     IrqLine;\r
+  EFI_STATUS                Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (PciHdr->Device.InterruptPin != 0) {\r
+\r
+    DevPathNode = DevicePathFromHandle (Handle);\r
+    ASSERT (DevPathNode != NULL);\r
+\r
+    //\r
+    // Compute index into PciHostIrqs[] table by walking\r
+    // the device path and adding up all device numbers\r
+    //\r
+    Status = EFI_NOT_FOUND;\r
+    RootSlot = 0;\r
+    Idx = PciHdr->Device.InterruptPin - 1;\r
+    while (!IsDevicePathEnd (DevPathNode)) {\r
+      if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&\r
+          DevicePathSubType (DevPathNode) == HW_PCI_DP) {\r
+\r
+        Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
+\r
+        //\r
+        // Unlike SeaBIOS, which starts climbing from the leaf device\r
+        // up toward the root, we traverse the device path starting at\r
+        // the root moving toward the leaf node.\r
+        // The slot number of the top-level parent bridge is needed for\r
+        // Q35 cases with more than 24 slots on the root bus.\r
+        //\r
+        if (Status != EFI_SUCCESS) {\r
+          Status = EFI_SUCCESS;\r
+          RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
+        }\r
+      }\r
+\r
+      DevPathNode = NextDevicePathNode (DevPathNode);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    if (RootSlot == 0) {\r
+      DEBUG((\r
+        EFI_D_ERROR,\r
+        "%a: PCI host bridge (00:00.0) should have no interrupts!\n",\r
+        __FUNCTION__\r
+        ));\r
+      ASSERT (FALSE);\r
+    }\r
+\r
+    //\r
+    // Final PciHostIrqs[] index calculation depends on the platform\r
+    // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()\r
+    //\r
+    switch (mHostBridgeDevId) {\r
+      case INTEL_82441_DEVICE_ID:\r
+        Idx -= 1;\r
+        break;\r
+      case INTEL_Q35_MCH_DEVICE_ID:\r
+        //\r
+        // SeaBIOS contains the following comment:\r
+        // "Slots 0-24 rotate slot:pin mapping similar to piix above, but\r
+        //  with a different starting index - see q35-acpi-dsdt.dsl.\r
+        //\r
+        //  Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"\r
+        //\r
+        if (RootSlot > 24) {\r
+          //\r
+          // in this case, subtract back out RootSlot from Idx\r
+          // (SeaBIOS never adds it to begin with, but that would make our\r
+          //  device path traversal loop above too awkward)\r
+          //\r
+          Idx -= RootSlot;\r
+        }\r
+        break;\r
+      default:\r
+        ASSERT (FALSE); // should never get here\r
+    }\r
+    Idx %= ARRAY_SIZE (PciHostIrqs);\r
+    IrqLine = PciHostIrqs[Idx];\r
+\r
+    //\r
+    // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]\r
+    //\r
+    Status = PciIo->Pci.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               PCI_INT_LINE_OFFSET,\r
+               1,\r
+               &IrqLine\r
+               );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
 VOID\r
-PciInitialization (\r
+PciAcpiInitialization (\r
   )\r
 {\r
-  //\r
-  // Device 0 Function 0\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,0,0,0x3c), 0x00);\r
+  UINTN  Pmba;\r
 \r
   //\r
-  // Device 1 Function 0\r
+  // Query Host Bridge DID to determine platform type\r
   //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,0,0x3c), 0x00);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,0,0x60), 0x8b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,0,0x61), 0x89);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,0,0x62), 0x0a);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,0,0x63), 0x89);\r
-  //PciWrite8 (PCI_LIB_ADDRESS (0,1,0,0x82), 0x02);\r
+  mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
+  switch (mHostBridgeDevId) {\r
+    case INTEL_82441_DEVICE_ID:\r
+      Pmba = POWER_MGMT_REGISTER_PIIX4 (0x40);\r
+      //\r
+      // 00:01.0 ISA Bridge (PIIX4) LNK routing targets\r
+      //\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D\r
+      break;\r
+    case INTEL_Q35_MCH_DEVICE_ID:\r
+      Pmba = POWER_MGMT_REGISTER_Q35 (0x40);\r
+      //\r
+      // 00:1f.0 LPC Bridge (Q35) LNK routing targets\r
+      //\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H\r
+      break;\r
+    default:\r
+      DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
+        __FUNCTION__, mHostBridgeDevId));\r
+      ASSERT (FALSE);\r
+      return;\r
+  }\r
 \r
   //\r
-  // Device 1 Function 1\r
+  // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
   //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,1,0x3c), 0x00);\r
+  VisitAllPciInstances (SetPciIntLine);\r
 \r
   //\r
-  // Device 1 Function 3\r
+  // Set ACPI SCI_EN bit in PMCNTRL\r
   //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,3,0x3c), 0x0b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,3,0x3d), 0x01);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,1,3,0x5f), 0x90);\r
+  IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
+}\r
 \r
-  //\r
-  // Device 2 Function 0\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,2,0,0x3c), 0x00);\r
 \r
-  //\r
-  // Device 3 Function 0\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,3,0,0x3c), 0x0b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0,3,0,0x3d), 0x01);\r
+EFI_STATUS\r
+EFIAPI\r
+ConnectRecursivelyIfPciMassStorage (\r
+  IN EFI_HANDLE           Handle,\r
+  IN EFI_PCI_IO_PROTOCOL  *Instance,\r
+  IN PCI_TYPE00           *PciHeader\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  CHAR16                    *DevPathStr;\r
+\r
+  if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {\r
+    DevicePath = NULL;\r
+    Status = gBS->HandleProtocol (\r
+                    Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    (VOID*)&DevicePath\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Print Device Path\r
+    //\r
+    DevPathStr = DevicePathToStr (DevicePath);\r
+    if (DevPathStr != NULL) {\r
+      DEBUG((\r
+        EFI_D_INFO,\r
+        "Found Mass Storage device: %s\n",\r
+        DevPathStr\r
+        ));\r
+      FreePool(DevPathStr);\r
+    }\r
+\r
+    Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This notification function is invoked when the\r
+  EMU Variable FVB has been changed.\r
+\r
+  @param  Event                 The event that occured\r
+  @param  Context               For EFI compatiblity.  Not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EmuVariablesUpdatedCallback (\r
+  IN  EFI_EVENT Event,\r
+  IN  VOID      *Context\r
+  )\r
+{\r
+  DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));\r
+  UpdateNvVarsOnFileSystem ();\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VisitingFileSystemInstance (\r
+  IN EFI_HANDLE  Handle,\r
+  IN VOID        *Instance,\r
+  IN VOID        *Context\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  STATIC BOOLEAN  ConnectedToFileSystem = FALSE;\r
+\r
+  if (ConnectedToFileSystem) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  Status = ConnectNvVarsToFileSystem (Handle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ConnectedToFileSystem = TRUE;\r
+  mEmuVariableEvent =\r
+    EfiCreateProtocolNotifyEvent (\r
+      &gEfiDevicePathProtocolGuid,\r
+      TPL_CALLBACK,\r
+      EmuVariablesUpdatedCallback,\r
+      NULL,\r
+      &mEmuVariableEventReg\r
+      );\r
+  PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+VOID\r
+PlatformBdsRestoreNvVarsFromHardDisk (\r
+  )\r
+{\r
+  VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);\r
+  VisitAllInstancesOfProtocol (\r
+    &gEfiSimpleFileSystemProtocolGuid,\r
+    VisitingFileSystemInstance,\r
+    NULL\r
+    );\r
+\r
 }\r
 \r
 \r
@@ -680,7 +1063,12 @@ Returns:
   //\r
   BdsLibConnectAll ();\r
 \r
-  PciInitialization ();\r
+  PciAcpiInitialization ();\r
+\r
+  //\r
+  // Clear the logo after all devices are connected.\r
+  //\r
+  gST->ConOut->ClearScreen (gST->ConOut);\r
 }\r
 \r
 VOID\r
@@ -711,7 +1099,8 @@ Returns:
 VOID\r
 PlatformBdsDiagnostics (\r
   IN EXTENDMEM_COVERAGE_LEVEL    MemoryTestLevel,\r
-  IN BOOLEAN                     QuietBoot\r
+  IN BOOLEAN                     QuietBoot,\r
+  IN BASEM_MEMORY_TEST           BaseMemoryTest\r
   )\r
 /*++\r
 \r
@@ -726,6 +1115,8 @@ Arguments:
 \r
   QuietBoot        - Indicate if need to enable the quiet boot\r
 \r
+  BaseMemoryTest   - A pointer to BaseMemoryTest()\r
+\r
 Returns:\r
 \r
   None.\r
@@ -743,11 +1134,11 @@ Returns:
   // from the graphic lib\r
   //\r
   if (QuietBoot) {\r
-    EnableQuietBoot (&gEfiDefaultBmpLogoGuid);\r
+    EnableQuietBoot (PcdGetPtr(PcdLogoFile));\r
     //\r
     // Perform system diagnostic\r
     //\r
-    Status = BdsMemoryTest (MemoryTestLevel);\r
+    Status = BaseMemoryTest (MemoryTestLevel);\r
     if (EFI_ERROR (Status)) {\r
       DisableQuietBoot ();\r
     }\r
@@ -757,16 +1148,17 @@ Returns:
   //\r
   // Perform system diagnostic\r
   //\r
-  Status = BdsMemoryTest (MemoryTestLevel);\r
+  Status = BaseMemoryTest (MemoryTestLevel);\r
 }\r
 \r
 \r
 VOID\r
 EFIAPI\r
 PlatformBdsPolicyBehavior (\r
-  IN EFI_BDS_ARCH_PROTOCOL_INSTANCE  *PrivateData,\r
   IN OUT LIST_ENTRY                  *DriverOptionList,\r
-  IN OUT LIST_ENTRY                  *BootOptionList\r
+  IN OUT LIST_ENTRY                  *BootOptionList,\r
+  IN PROCESS_CAPSULES                ProcessCapsules,\r
+  IN BASEM_MEMORY_TEST               BaseMemoryTest\r
   )\r
 /*++\r
 \r
@@ -778,12 +1170,14 @@ Routine Description:
 \r
 Arguments:\r
 \r
-  PrivateData      - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance\r
-\r
   DriverOptionList - The header of the driver option link list\r
 \r
   BootOptionList   - The header of the boot option link list\r
 \r
+  ProcessCapsules  - A pointer to ProcessCapsules()\r
+\r
+  BaseMemoryTest   - A pointer to BaseMemoryTest()\r
+\r
 Returns:\r
 \r
   None.\r
@@ -792,15 +1186,23 @@ Returns:
 {\r
   EFI_STATUS                         Status;\r
   UINT16                             Timeout;\r
-  EFI_EVENT                          UserInputDurationTime;\r
-  LIST_ENTRY                     *Link;\r
-  BDS_COMMON_OPTION                  *BootOption;\r
-  UINTN                              Index;\r
-  EFI_INPUT_KEY                      Key;\r
-  EFI_TPL                            OldTpl;\r
+  EFI_BOOT_MODE                      BootMode;\r
 \r
   DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n"));\r
 \r
+  ConnectRootBridge ();\r
+\r
+  if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {\r
+    DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "\r
+      "from disk since flash variables appear to be supported.\n"));\r
+  } else {\r
+    //\r
+    // Try to restore variables from the hard disk early so\r
+    // they can be used for the other BDS connect operations.\r
+    //\r
+    PlatformBdsRestoreNvVarsFromHardDisk ();\r
+  }\r
+\r
   //\r
   // Init the time out value\r
   //\r
@@ -814,14 +1216,14 @@ Returns:
   //\r
   // Get current Boot Mode\r
   //\r
-  Status = BdsLibGetBootMode (&PrivateData->BootMode);\r
-  DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", PrivateData->BootMode));\r
+  Status = BdsLibGetBootMode (&BootMode);\r
+  DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));\r
 \r
   //\r
   // Go the different platform policy with different boot mode\r
   // Notes: this part code can be change with the table policy\r
   //\r
-  ASSERT (PrivateData->BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
+  ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
   //\r
   // Connect platform console\r
   //\r
@@ -832,23 +1234,11 @@ Returns:
     //\r
     PlatformBdsNoConsoleAction ();\r
   }\r
-  //\r
-  // Create a 300ms duration event to ensure user has enough input time to enter Setup\r
-  //\r
-  Status = gBS->CreateEvent (\r
-                  EVT_TIMER,\r
-                  0,\r
-                  NULL,\r
-                  NULL,\r
-                  &UserInputDurationTime\r
-                  );\r
-  ASSERT (Status == EFI_SUCCESS);\r
-  Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000);\r
-  ASSERT (Status == EFI_SUCCESS);\r
+\r
   //\r
   // Memory test and Logo show\r
   //\r
-  PlatformBdsDiagnostics (IGNORE, TRUE);\r
+  PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest);\r
 \r
   //\r
   // Perform some platform specific connect sequence\r
@@ -856,79 +1246,22 @@ Returns:
   PlatformBdsConnectSequence ();\r
 \r
   //\r
-  // Give one chance to enter the setup if we\r
-  // have the time out\r
+  // Process QEMU's -kernel command line option\r
   //\r
-  if (Timeout != 0) {\r
-    //PlatformBdsEnterFrontPage (Timeout, FALSE);\r
-  }\r
+  TryRunningQemuKernel ();\r
 \r
   DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n"));\r
   BdsLibConnectAll ();\r
   BdsLibEnumerateAllBootOption (BootOptionList);\r
 \r
+  SetBootOrderFromQemu (BootOptionList);\r
   //\r
-  // Please uncomment above ConnectAll and EnumerateAll code and remove following first boot\r
-  // checking code in real production tip.\r
-  //\r
-  // In BOOT_WITH_FULL_CONFIGURATION boot mode, should always connect every device\r
-  // and do enumerate all the default boot options. But in development system board, the boot mode\r
-  // cannot be BOOT_ASSUMING_NO_CONFIGURATION_CHANGES because the machine box\r
-  // is always open. So the following code only do the ConnectAll and EnumerateAll at first boot.\r
+  // The BootOrder variable may have changed, reload the in-memory list with\r
+  // it.\r
   //\r
-  Status = BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");\r
-  if (EFI_ERROR(Status)) {\r
-    //\r
-    // If cannot find "BootOrder" variable,  it may be first boot.\r
-    // Try to connect all devices and enumerate all boot options here.\r
-    //\r
-    BdsLibConnectAll ();\r
-    BdsLibEnumerateAllBootOption (BootOptionList);\r
-  }\r
+  BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");\r
 \r
-  //\r
-  // To give the User a chance to enter Setup here, if user set TimeOut is 0.\r
-  // BDS should still give user a chance to enter Setup\r
-  //\r
-  // Connect first boot option, and then check user input before exit\r
-  //\r
-  for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) {\r
-    BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
-    if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {\r
-      //\r
-      // skip the header of the link list, becuase it has no boot option\r
-      //\r
-      continue;\r
-    } else {\r
-      //\r
-      // Make sure the boot option device path connected, but ignore the BBS device path\r
-      //\r
-      if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {\r
-        BdsLibConnectDevicePath (BootOption->DevicePath);\r
-      }\r
-      break;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Check whether the user input after the duration time has expired\r
-  //\r
-  OldTpl = EfiGetCurrentTpl();\r
-  gBS->RestoreTPL (TPL_APPLICATION);\r
-  gBS->WaitForEvent (1, &UserInputDurationTime, &Index);\r
-  gBS->CloseEvent (UserInputDurationTime);\r
-  Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-  gBS->RaiseTPL (OldTpl);\r
-\r
-  if (!EFI_ERROR (Status)) {\r
-    //\r
-    // Enter Setup if user input\r
-    //\r
-    Timeout = 0xffff;\r
-    PlatformBdsEnterFrontPage (Timeout, FALSE);\r
-  }\r
-\r
-  return ;\r
+  PlatformBdsEnterFrontPage (Timeout, TRUE);\r
 }\r
 \r
 VOID\r
@@ -1039,12 +1372,134 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
+VOID\r
 EFIAPI\r
 PlatformBdsLockNonUpdatableFlash (\r
   VOID\r
   )\r
 {\r
   DEBUG ((EFI_D_INFO, "PlatformBdsLockNonUpdatableFlash\n"));\r
-  return EFI_SUCCESS;\r
+  return;\r
 }\r
+\r
+\r
+/**\r
+  This notification function is invoked when an instance of the\r
+  EFI_DEVICE_PATH_PROTOCOL is produced.\r
+\r
+  @param  Event                 The event that occured\r
+  @param  Context               For EFI compatiblity.  Not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+NotifyDevPath (\r
+  IN  EFI_EVENT Event,\r
+  IN  VOID      *Context\r
+  )\r
+{\r
+  EFI_HANDLE                            Handle;\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 BufferSize;\r
+  EFI_DEVICE_PATH_PROTOCOL             *DevPathNode;\r
+  ATAPI_DEVICE_PATH                    *Atapi;\r
+\r
+  //\r
+  // Examine all new handles\r
+  //\r
+  for (;;) {\r
+    //\r
+    // Get the next handle\r
+    //\r
+    BufferSize = sizeof (Handle);\r
+    Status = gBS->LocateHandle (\r
+              ByRegisterNotify,\r
+              NULL,\r
+              mEfiDevPathNotifyReg,\r
+              &BufferSize,\r
+              &Handle\r
+              );\r
+\r
+    //\r
+    // If not found, we're done\r
+    //\r
+    if (EFI_NOT_FOUND == Status) {\r
+      break;\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Get the DevicePath protocol on that handle\r
+    //\r
+    Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    while (!IsDevicePathEnd (DevPathNode)) {\r
+      //\r
+      // Find the handler to dump this device path node\r
+      //\r
+      if (\r
+           (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
+           (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)\r
+         ) {\r
+        Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;\r
+        PciOr16 (\r
+          PCI_LIB_ADDRESS (\r
+            0,\r
+            1,\r
+            1,\r
+            (Atapi->PrimarySecondary == 1) ? 0x42: 0x40\r
+            ),\r
+          BIT15\r
+          );\r
+      }\r
+\r
+      //\r
+      // Next device path node\r
+      //\r
+      DevPathNode = NextDevicePathNode (DevPathNode);\r
+    }\r
+  }\r
+\r
+  return;\r
+}\r
+\r
+\r
+VOID\r
+InstallDevicePathCallback (\r
+  VOID\r
+  )\r
+{\r
+  DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));\r
+  mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (\r
+                          &gEfiDevicePathProtocolGuid,\r
+                          TPL_CALLBACK,\r
+                          NotifyDevPath,\r
+                          NULL,\r
+                          &mEfiDevPathNotifyReg\r
+                          );\r
+}\r
+\r
+/**\r
+  Lock the ConsoleIn device in system table. All key\r
+  presses will be ignored until the Password is typed in. The only way to\r
+  disable the password is to type it in to a ConIn device.\r
+\r
+  @param  Password        Password used to lock ConIn device.\r
+\r
+  @retval EFI_SUCCESS     lock the Console In Spliter virtual handle successfully.\r
+  @retval EFI_UNSUPPORTED Password not found\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LockKeyboards (\r
+  IN  CHAR16    *Password\r
+  )\r
+{\r
+    return EFI_UNSUPPORTED;\r
+}\r
+\r