**/\r
\r
#include "BdsPlatform.h"\r
-#include "QemuBootOrder.h"\r
+#include <Library/QemuBootOrderLib.h>\r
\r
\r
//\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
\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
//\r
BdsLibConnectAll ();\r
\r
- PciInitialization ();\r
- AcpiInitialization ();\r
+ PciAcpiInitialization ();\r
\r
//\r
// Clear the logo after all devices are connected.\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
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
//\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