]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
OvmfPkg: consolidate POWER_MGMT_REGISTER_PIIX4() on "I440FxPiix4.h" macros
[mirror_edk2.git] / OvmfPkg / Library / PlatformBdsLib / BdsPlatform.c
index c960c6cdbfa6b40feb6b4c9b2d2363b07fa5a5a8..1eb2a8b91e0b4923f08e5a1177c82626fca09ea4 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Platform BDS customizations.\r
 \r
-  Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\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
@@ -13,6 +13,7 @@
 **/\r
 \r
 #include "BdsPlatform.h"\r
+#include <Library/QemuBootOrderLib.h>\r
 \r
 \r
 //\r
@@ -24,7 +25,20 @@ EFI_EVENT     mEfiDevPathEvent;
 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
@@ -208,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
@@ -235,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
@@ -362,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
@@ -710,64 +729,176 @@ Returns:
 }\r
 \r
 \r
-VOID\r
-PciInitialization (\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
-  //\r
-  // Bus 0, Device 0, Function 0 - Host to PCI Bridge\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 0, 0, 0x3c), 0x00);\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;\r
+  UINTN                     RootSlot;\r
+  UINTN                     Idx;\r
+  UINT8                     IrqLine;\r
+  EFI_STATUS                Status;\r
 \r
-  //\r
-  // Bus 0, Device 1, Function 0 - PCI to ISA Bridge\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x3c), 0x00);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x09);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x09);\r
+  Status = EFI_SUCCESS;\r
 \r
-  //\r
-  // Bus 0, Device 1, Function 1 - IDE Controller\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x3c), 0x00);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x0d), 0x40);\r
+  if (PciHdr->Device.InterruptPin != 0) {\r
 \r
-  //\r
-  // Bus 0, Device 1, Function 3 - Power Managment Controller\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3c), 0x0b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3d), 0x01);\r
+    DevPathNode = DevicePathFromHandle (Handle);\r
+    ASSERT (DevPathNode != NULL);\r
 \r
-  //\r
-  // Bus 0, Device 2, Function 0 - Video Controller\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 2, 0, 0x3c), 0x00);\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
-  //\r
-  // Bus 0, Device 3, Function 0 - Network Controller\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3d), 0x01);\r
+        Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
 \r
-  //\r
-  // Bus 0, Device 4, Function 0 - RAM Memory\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3c), 0x09);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 4, 0, 0x3d), 0x01);\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
-AcpiInitialization (\r
-  VOID\r
+PciAcpiInitialization (\r
   )\r
 {\r
+  UINTN  Pmba;\r
+\r
+  //\r
+  // Query Host Bridge DID to determine platform type\r
+  //\r
+  mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
+  switch (mHostBridgeDevId) {\r
+    case INTEL_82441_DEVICE_ID:\r
+      Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\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 (ICH9_PMBASE);\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
+  // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
+  //\r
+  VisitAllPciInstances (SetPciIntLine);\r
+\r
   //\r
   // Set ACPI SCI_EN bit in PMCNTRL\r
   //\r
-  IoOr16 ((PciRead32 (PCI_LIB_ADDRESS (0, 1, 3, 0x40)) & ~BIT0) + 4, BIT0);\r
+  IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
 }\r
 \r
 \r
@@ -798,12 +929,14 @@ ConnectRecursivelyIfPciMassStorage (
     // Print Device Path\r
     //\r
     DevPathStr = DevicePathToStr (DevicePath);\r
-    DEBUG((\r
-      EFI_D_INFO,\r
-      "Found Mass Storage device: %s\n",\r
-      DevPathStr\r
-      ));\r
-    FreePool(DevPathStr);\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
@@ -930,8 +1063,7 @@ Returns:
   //\r
   BdsLibConnectAll ();\r
 \r
-  PciInitialization ();\r
-  AcpiInitialization ();\r
+  PciAcpiInitialization ();\r
 \r
   //\r
   // Clear the logo after all devices are connected.\r
@@ -1053,29 +1185,22 @@ Returns:
 --*/\r
 {\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
-  //\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
-  // Init the time out value\r
-  //\r
-  Timeout = PcdGet16 (PcdPlatformBootTimeOut);\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
   // Load the driver option as the driver option list\r
@@ -1103,19 +1228,7 @@ 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
@@ -1127,79 +1240,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
-\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
+  BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");\r
 \r
-  return ;\r
+  PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE);\r
 }\r
 \r
 VOID\r