]> 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 f2ece66817d54c35041138c4e1714aeca7bcbb7b..341f5c15963d2605c5fd2681032657a6636b11f7 100644 (file)
@@ -13,7 +13,7 @@
 **/\r
 \r
 #include "BdsPlatform.h"\r
-#include "QemuBootOrder.h"\r
+#include <Library/QemuBootOrderLib.h>\r
 \r
 \r
 //\r
@@ -25,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
@@ -716,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); // LNKA routing target\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // LNKB routing target\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // LNKC routing target\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // LNKD routing target\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), 0x09);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3d), 0x01); // INTA\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), 0x0a);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3d), 0x01); // INTA (-> LNKC)\r
+        Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
 \r
-  //\r
-  // Bus 0, Device 5, Function 0 - RAM Memory\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3c), 0x0b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3d), 0x01); // INTA (-> LNKA)\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 (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
+  // 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
@@ -938,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
@@ -1062,12 +1186,6 @@ 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
@@ -1116,19 +1234,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
@@ -1155,46 +1261,7 @@ Returns:
   //\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
-    PlatformBdsEnterFrontPage (Timeout, FALSE);\r
-  }\r
+  PlatformBdsEnterFrontPage (Timeout, TRUE);\r
 }\r
 \r
 VOID\r