2 Platform BDS customizations.
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "BdsPlatform.h"
16 #include <Guid/XenInfo.h>
17 #include <Guid/RootBridgesConnectedEventGroup.h>
24 VOID
*mEfiDevPathNotifyReg
;
25 EFI_EVENT mEfiDevPathEvent
;
26 VOID
*mEmuVariableEventReg
;
27 EFI_EVENT mEmuVariableEvent
;
28 BOOLEAN mDetectVgaOnly
;
29 UINT16 mHostBridgeDevId
;
32 // Table of host IRQs matching PCI IRQs A-D
33 // (for configuring PCI Interrupt Line register)
35 CONST UINT8 PciHostIrqs
[] = {
36 0x0a, 0x0a, 0x0b, 0x0b
42 #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
50 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
57 @param[in] Handle - Handle of PCI device instance
58 @param[in] PciIo - PCI IO protocol instance
59 @param[in] Pci - PCI Header register block
63 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
65 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
71 // Function prototypes
75 VisitAllInstancesOfProtocol (
77 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
82 VisitAllPciInstancesOfProtocol (
83 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
87 InstallDevicePathCallback (
92 PlatformRegisterFvBootOption (
100 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
101 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
102 UINTN BootOptionCount
;
103 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
104 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
105 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
107 Status
= gBS
->HandleProtocol (
109 &gEfiLoadedImageProtocolGuid
,
110 (VOID
**) &LoadedImage
112 ASSERT_EFI_ERROR (Status
);
114 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
115 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
116 ASSERT (DevicePath
!= NULL
);
117 DevicePath
= AppendDevicePathNode (
119 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
121 ASSERT (DevicePath
!= NULL
);
123 Status
= EfiBootManagerInitializeLoadOption (
125 LoadOptionNumberUnassigned
,
133 ASSERT_EFI_ERROR (Status
);
134 FreePool (DevicePath
);
136 BootOptions
= EfiBootManagerGetLoadOptions (
137 &BootOptionCount
, LoadOptionTypeBoot
140 OptionIndex
= EfiBootManagerFindLoadOption (
141 &NewOption
, BootOptions
, BootOptionCount
144 if (OptionIndex
== -1) {
145 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
146 ASSERT_EFI_ERROR (Status
);
148 EfiBootManagerFreeLoadOption (&NewOption
);
149 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
153 PlatformRegisterOptionsAndKeys (
161 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
164 // Register ENTER as CONTINUE key
166 Enter
.ScanCode
= SCAN_NULL
;
167 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
168 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
169 ASSERT_EFI_ERROR (Status
);
172 // Map F2 to Boot Manager Menu
174 F2
.ScanCode
= SCAN_F2
;
175 F2
.UnicodeChar
= CHAR_NULL
;
176 Esc
.ScanCode
= SCAN_ESC
;
177 Esc
.UnicodeChar
= CHAR_NULL
;
178 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
179 ASSERT_EFI_ERROR (Status
);
180 Status
= EfiBootManagerAddKeyOptionVariable (
181 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
183 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
184 Status
= EfiBootManagerAddKeyOptionVariable (
185 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
187 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
193 IN EFI_HANDLE RootBridgeHandle
,
205 // BDS Platform Functions
209 PlatformBootManagerBeforeConsole (
216 Platform Bds init. Incude the platform firmware vendor, revision
230 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
231 InstallDevicePathCallback ();
233 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
234 ConnectRootBridge
, NULL
);
237 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
239 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
242 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
243 // the preparation of S3 system information. That logic has a hard dependency
244 // on the presence of the FACS ACPI table. Since our ACPI tables are only
245 // installed after PCI enumeration completes, we must not trigger the S3 save
246 // earlier, hence we can't signal End-of-Dxe earlier.
248 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
250 if (QemuFwCfgS3Enabled ()) {
252 // Save the boot script too. Note that this will require us to emit the
253 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
259 // Prevent further changes to LockBoxes or SMRAM.
262 Status
= gBS
->InstallProtocolInterface (&Handle
,
263 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
265 ASSERT_EFI_ERROR (Status
);
267 PlatformInitializeConsole (gPlatformConsole
);
268 PcdSet16 (PcdPlatformBootTimeOut
, GetFrontPageTimeoutFromQemu ());
270 PlatformRegisterOptionsAndKeys ();
277 IN EFI_HANDLE RootBridgeHandle
,
285 // Make the PCI bus driver connect the root bridge, non-recursively. This
286 // will produce a number of child handles with PciIo on them.
288 Status
= gBS
->ConnectController (
289 RootBridgeHandle
, // ControllerHandle
290 NULL
, // DriverImageHandle
291 NULL
, // RemainingDevicePath -- produce all
300 PrepareLpcBridgeDevicePath (
301 IN EFI_HANDLE DeviceHandle
307 Add IsaKeyboard to ConIn,
308 add IsaSerial to ConOut, ConIn, ErrOut.
313 DeviceHandle - Handle of PCIIO protocol.
317 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
318 EFI_STATUS - No LPC bridge is added.
323 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
324 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
328 Status
= gBS
->HandleProtocol (
330 &gEfiDevicePathProtocolGuid
,
333 if (EFI_ERROR (Status
)) {
336 TempDevicePath
= DevicePath
;
341 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
343 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
348 DevicePath
= TempDevicePath
;
349 gPnp16550ComPortDeviceNode
.UID
= 0;
351 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
352 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
353 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
358 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
359 if (DevPathStr
!= NULL
) {
362 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
364 gPnp16550ComPortDeviceNode
.UID
+ 1,
367 FreePool(DevPathStr
);
370 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
371 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
372 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
377 DevicePath
= TempDevicePath
;
378 gPnp16550ComPortDeviceNode
.UID
= 1;
380 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
381 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
382 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
387 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
388 if (DevPathStr
!= NULL
) {
391 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
393 gPnp16550ComPortDeviceNode
.UID
+ 1,
396 FreePool(DevPathStr
);
399 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
400 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
401 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
408 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
409 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
414 EFI_HANDLE PciDeviceHandle
;
415 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
416 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
417 UINTN GopHandleCount
;
418 EFI_HANDLE
*GopHandleBuffer
;
420 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
421 return EFI_INVALID_PARAMETER
;
425 // Initialize the GopDevicePath to be PciDevicePath
427 *GopDevicePath
= PciDevicePath
;
428 TempPciDevicePath
= PciDevicePath
;
430 Status
= gBS
->LocateDevicePath (
431 &gEfiDevicePathProtocolGuid
,
435 if (EFI_ERROR (Status
)) {
440 // Try to connect this handle, so that GOP dirver could start on this
441 // device and create child handles with GraphicsOutput Protocol installed
442 // on them, then we get device paths of these child handles and select
443 // them as possible console device.
445 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
447 Status
= gBS
->LocateHandleBuffer (
449 &gEfiGraphicsOutputProtocolGuid
,
454 if (!EFI_ERROR (Status
)) {
456 // Add all the child handles as possible Console Device
458 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
459 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
460 if (EFI_ERROR (Status
)) {
466 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
469 // In current implementation, we only enable one of the child handles
470 // as console device, i.e. sotre one of the child handle's device
471 // path to variable "ConOut"
472 // In futhure, we could select all child handles to be console device
475 *GopDevicePath
= TempDevicePath
;
478 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
479 // Add the integrity GOP device path.
481 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
482 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
485 gBS
->FreePool (GopHandleBuffer
);
492 PreparePciVgaDevicePath (
493 IN EFI_HANDLE DeviceHandle
499 Add PCI VGA to ConOut.
504 DeviceHandle - Handle of PCIIO protocol.
508 EFI_SUCCESS - PCI VGA is added to ConOut.
509 EFI_STATUS - No PCI VGA device is added.
514 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
515 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
518 GopDevicePath
= NULL
;
519 Status
= gBS
->HandleProtocol (
521 &gEfiDevicePathProtocolGuid
,
524 if (EFI_ERROR (Status
)) {
528 GetGopDevicePath (DevicePath
, &GopDevicePath
);
529 DevicePath
= GopDevicePath
;
531 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
537 PreparePciSerialDevicePath (
538 IN EFI_HANDLE DeviceHandle
544 Add PCI Serial to ConOut, ConIn, ErrOut.
549 DeviceHandle - Handle of PCIIO protocol.
553 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
554 EFI_STATUS - No PCI Serial device is added.
559 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
562 Status
= gBS
->HandleProtocol (
564 &gEfiDevicePathProtocolGuid
,
567 if (EFI_ERROR (Status
)) {
571 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
572 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
574 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
575 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
576 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
582 VisitAllInstancesOfProtocol (
584 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
590 EFI_HANDLE
*HandleBuffer
;
595 // Start to check all the PciIo to find all possible device
599 Status
= gBS
->LocateHandleBuffer (
606 if (EFI_ERROR (Status
)) {
610 for (Index
= 0; Index
< HandleCount
; Index
++) {
611 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
612 if (EFI_ERROR (Status
)) {
616 Status
= (*CallBackFunction
) (
623 gBS
->FreePool (HandleBuffer
);
631 VisitingAPciInstance (
632 IN EFI_HANDLE Handle
,
638 EFI_PCI_IO_PROTOCOL
*PciIo
;
641 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
644 // Check for all PCI device
646 Status
= PciIo
->Pci
.Read (
650 sizeof (Pci
) / sizeof (UINT32
),
653 if (EFI_ERROR (Status
)) {
657 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
668 VisitAllPciInstances (
669 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
672 return VisitAllInstancesOfProtocol (
673 &gEfiPciIoProtocolGuid
,
674 VisitingAPciInstance
,
675 (VOID
*)(UINTN
) CallBackFunction
681 Do platform specific PCI Device check and add them to
682 ConOut, ConIn, ErrOut.
684 @param[in] Handle - Handle of PCI device instance
685 @param[in] PciIo - PCI IO protocol instance
686 @param[in] Pci - PCI Header register block
688 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
689 @retval EFI_STATUS - PCI Device check or Console variable update fail.
694 DetectAndPreparePlatformPciDevicePath (
695 IN EFI_HANDLE Handle
,
696 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
702 Status
= PciIo
->Attributes (
704 EfiPciIoAttributeOperationEnable
,
705 EFI_PCI_DEVICE_ENABLE
,
708 ASSERT_EFI_ERROR (Status
);
710 if (!mDetectVgaOnly
) {
712 // Here we decide whether it is LPC Bridge
714 if ((IS_PCI_LPC (Pci
)) ||
715 ((IS_PCI_ISA_PDECODE (Pci
)) &&
716 (Pci
->Hdr
.VendorId
== 0x8086) &&
717 (Pci
->Hdr
.DeviceId
== 0x7000)
721 // Add IsaKeyboard to ConIn,
722 // add IsaSerial to ConOut, ConIn, ErrOut
724 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
725 PrepareLpcBridgeDevicePath (Handle
);
729 // Here we decide which Serial device to enable in PCI bus
731 if (IS_PCI_16550SERIAL (Pci
)) {
733 // Add them to ConOut, ConIn, ErrOut.
735 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
736 PreparePciSerialDevicePath (Handle
);
742 // Here we decide which VGA device to enable in PCI bus
744 if (IS_PCI_VGA (Pci
)) {
746 // Add them to ConOut.
748 DEBUG ((EFI_D_INFO
, "Found PCI VGA device\n"));
749 PreparePciVgaDevicePath (Handle
);
758 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
760 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
762 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
763 @retval EFI_STATUS - PCI Device check or Console variable update fail.
767 DetectAndPreparePlatformPciDevicePaths (
768 BOOLEAN DetectVgaOnly
771 mDetectVgaOnly
= DetectVgaOnly
;
772 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
777 PlatformInitializeConsole (
778 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
784 Connect the predefined platform default console device. Always try to find
785 and enable the vga device if have.
789 PlatformConsole - Predfined platform default console device array.
793 EFI_DEVICE_PATH_PROTOCOL
*VarConout
;
794 EFI_DEVICE_PATH_PROTOCOL
*VarConin
;
797 // Connect RootBridge
799 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME
, (VOID
**) &VarConout
, NULL
);
800 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME
, (VOID
**) &VarConin
, NULL
);
802 if (VarConout
== NULL
|| VarConin
== NULL
) {
804 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
806 DetectAndPreparePlatformPciDevicePaths (FALSE
);
809 // Have chance to connect the platform default console,
810 // the platform default console is the minimue device group
811 // the platform should support
813 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
815 // Update the console variable with the connect type
817 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
818 EfiBootManagerUpdateConsoleVariable (ConIn
, PlatformConsole
[Index
].DevicePath
, NULL
);
820 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
821 EfiBootManagerUpdateConsoleVariable (ConOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
823 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
824 EfiBootManagerUpdateConsoleVariable (ErrOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
829 // Only detect VGA device and add them to ConOut
831 DetectAndPreparePlatformPciDevicePaths (TRUE
);
837 Configure PCI Interrupt Line register for applicable devices
838 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
840 @param[in] Handle - Handle of PCI device instance
841 @param[in] PciIo - PCI IO protocol instance
842 @param[in] PciHdr - PCI Header register block
844 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
850 IN EFI_HANDLE Handle
,
851 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
852 IN PCI_TYPE00
*PciHdr
855 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
856 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
861 UINT32 RootBusNumber
;
863 Status
= EFI_SUCCESS
;
865 if (PciHdr
->Device
.InterruptPin
!= 0) {
867 DevPathNode
= DevicePathFromHandle (Handle
);
868 ASSERT (DevPathNode
!= NULL
);
869 DevPath
= DevPathNode
;
872 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
873 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
874 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
875 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
879 // Compute index into PciHostIrqs[] table by walking
880 // the device path and adding up all device numbers
882 Status
= EFI_NOT_FOUND
;
884 Idx
= PciHdr
->Device
.InterruptPin
- 1;
885 while (!IsDevicePathEnd (DevPathNode
)) {
886 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
887 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
889 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
892 // Unlike SeaBIOS, which starts climbing from the leaf device
893 // up toward the root, we traverse the device path starting at
894 // the root moving toward the leaf node.
895 // The slot number of the top-level parent bridge is needed for
896 // Q35 cases with more than 24 slots on the root bus.
898 if (Status
!= EFI_SUCCESS
) {
899 Status
= EFI_SUCCESS
;
900 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
904 DevPathNode
= NextDevicePathNode (DevPathNode
);
906 if (EFI_ERROR (Status
)) {
909 if (RootBusNumber
== 0 && RootSlot
== 0) {
912 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
919 // Final PciHostIrqs[] index calculation depends on the platform
920 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
922 switch (mHostBridgeDevId
) {
923 case INTEL_82441_DEVICE_ID
:
926 case INTEL_Q35_MCH_DEVICE_ID
:
928 // SeaBIOS contains the following comment:
929 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
930 // with a different starting index - see q35-acpi-dsdt.dsl.
932 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
936 // in this case, subtract back out RootSlot from Idx
937 // (SeaBIOS never adds it to begin with, but that would make our
938 // device path traversal loop above too awkward)
944 ASSERT (FALSE
); // should never get here
946 Idx
%= ARRAY_SIZE (PciHostIrqs
);
947 IrqLine
= PciHostIrqs
[Idx
];
951 CHAR16
*DevPathString
;
952 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
953 UINTN Segment
, Bus
, Device
, Function
;
955 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
956 if (DevPathString
== NULL
) {
957 DevPathString
= Fallback
;
959 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
960 ASSERT_EFI_ERROR (Status
);
962 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
963 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
966 if (DevPathString
!= Fallback
) {
967 FreePool (DevPathString
);
973 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
975 Status
= PciIo
->Pci
.Write (
989 PciAcpiInitialization (
995 // Query Host Bridge DID to determine platform type
997 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
998 switch (mHostBridgeDevId
) {
999 case INTEL_82441_DEVICE_ID
:
1000 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1002 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1004 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1005 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1006 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1007 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1009 case INTEL_Q35_MCH_DEVICE_ID
:
1010 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1012 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1014 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1015 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1016 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1017 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1018 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1019 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1020 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1021 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1024 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1025 __FUNCTION__
, mHostBridgeDevId
));
1031 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1033 VisitAllPciInstances (SetPciIntLine
);
1036 // Set ACPI SCI_EN bit in PMCNTRL
1038 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1042 This function detects if OVMF is running on Xen.
1051 EFI_HOB_GUID_TYPE
*GuidHob
;
1052 STATIC INTN FoundHob
= -1;
1054 if (FoundHob
== 0) {
1056 } else if (FoundHob
== 1) {
1061 // See if a XenInfo HOB is available
1063 GuidHob
= GetFirstGuidHob (&gEfiXenInfoGuid
);
1064 if (GuidHob
== NULL
) {
1075 ConnectRecursivelyIfPciMassStorage (
1076 IN EFI_HANDLE Handle
,
1077 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1078 IN PCI_TYPE00
*PciHeader
1082 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1086 // Recognize PCI Mass Storage, and Xen PCI devices
1088 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1089 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1091 Status
= gBS
->HandleProtocol (
1093 &gEfiDevicePathProtocolGuid
,
1096 if (EFI_ERROR (Status
)) {
1101 // Print Device Path
1103 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1104 if (DevPathStr
!= NULL
) {
1107 "Found %s device: %s\n",
1108 IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ? L
"Mass Storage" : L
"Xen",
1111 FreePool(DevPathStr
);
1114 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1115 if (EFI_ERROR (Status
)) {
1126 This notification function is invoked when the
1127 EMU Variable FVB has been changed.
1129 @param Event The event that occured
1130 @param Context For EFI compatiblity. Not used.
1135 EmuVariablesUpdatedCallback (
1140 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1141 UpdateNvVarsOnFileSystem ();
1147 VisitingFileSystemInstance (
1148 IN EFI_HANDLE Handle
,
1154 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1156 if (ConnectedToFileSystem
) {
1157 return EFI_ALREADY_STARTED
;
1160 Status
= ConnectNvVarsToFileSystem (Handle
);
1161 if (EFI_ERROR (Status
)) {
1165 ConnectedToFileSystem
= TRUE
;
1167 EfiCreateProtocolNotifyEvent (
1168 &gEfiDevicePathProtocolGuid
,
1170 EmuVariablesUpdatedCallback
,
1172 &mEmuVariableEventReg
1174 PcdSet64 (PcdEmuVariableEvent
, (UINT64
)(UINTN
) mEmuVariableEvent
);
1181 PlatformBdsRestoreNvVarsFromHardDisk (
1184 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1185 VisitAllInstancesOfProtocol (
1186 &gEfiSimpleFileSystemProtocolGuid
,
1187 VisitingFileSystemInstance
,
1194 PlatformBdsConnectSequence (
1199 Routine Description:
1201 Connect with predeined platform connect sequence,
1202 the OEM/IBV can customize with their own connect sequence.
1216 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1221 // Here we can get the customized platform connect sequence
1222 // Notes: we can connect with new variable which record the
1223 // last time boots connect device path sequence
1225 while (gPlatformConnectSequence
[Index
] != NULL
) {
1227 // Build the platform boot option
1229 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1234 // Just use the simple policy to connect all devices
1236 DEBUG ((EFI_D_INFO
, "EfiBootManagerConnectAll\n"));
1237 EfiBootManagerConnectAll ();
1239 PciAcpiInitialization ();
1243 Save the S3 boot script.
1245 Note that DxeSmmReadyToLock must be signaled after this function returns;
1246 otherwise the script wouldn't be saved actually.
1255 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1256 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1258 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1259 (VOID
**) &BootScript
);
1260 ASSERT_EFI_ERROR (Status
);
1263 // Despite the opcode documentation in the PI spec, the protocol
1264 // implementation embeds a deep copy of the info in the boot script, rather
1265 // than storing just a pointer to runtime or NVS storage.
1267 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1268 (UINT32
) sizeof Info
,
1269 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1270 ASSERT_EFI_ERROR (Status
);
1276 PlatformBootManagerAfterConsole (
1281 Routine Description:
1283 The function will excute with as the platform policy, current policy
1284 is driven by boot mode. IBV/OEM can customize this code for their specific
1289 EFI_BOOT_MODE BootMode
;
1291 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1293 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1294 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1295 "from disk since flash variables appear to be supported.\n"));
1298 // Try to restore variables from the hard disk early so
1299 // they can be used for the other BDS connect operations.
1301 PlatformBdsRestoreNvVarsFromHardDisk ();
1305 // Get current Boot Mode
1307 BootMode
= GetBootModeHob ();
1308 DEBUG ((EFI_D_ERROR
, "Boot Mode:%x\n", BootMode
));
1311 // Go the different platform policy with different boot mode
1312 // Notes: this part code can be change with the table policy
1314 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1319 BootLogoEnableLogo (
1320 ImageFormatBmp
, // ImageFormat
1321 PcdGetPtr (PcdLogoFile
), // Logo
1322 EdkiiPlatformLogoDisplayAttributeCenter
, // Attribute
1328 // Perform some platform specific connect sequence
1330 PlatformBdsConnectSequence ();
1333 // Process QEMU's -kernel command line option
1335 TryRunningQemuKernel ();
1337 EfiBootManagerRefreshAllBootOption ();
1340 // Register UEFI Shell
1342 PlatformRegisterFvBootOption (
1343 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1346 SetBootOrderFromQemu ();
1350 This notification function is invoked when an instance of the
1351 EFI_DEVICE_PATH_PROTOCOL is produced.
1353 @param Event The event that occured
1354 @param Context For EFI compatiblity. Not used.
1367 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1368 ATAPI_DEVICE_PATH
*Atapi
;
1371 // Examine all new handles
1375 // Get the next handle
1377 BufferSize
= sizeof (Handle
);
1378 Status
= gBS
->LocateHandle (
1381 mEfiDevPathNotifyReg
,
1387 // If not found, we're done
1389 if (EFI_NOT_FOUND
== Status
) {
1393 if (EFI_ERROR (Status
)) {
1398 // Get the DevicePath protocol on that handle
1400 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevPathNode
);
1401 ASSERT_EFI_ERROR (Status
);
1403 while (!IsDevicePathEnd (DevPathNode
)) {
1405 // Find the handler to dump this device path node
1408 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1409 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1411 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1417 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1424 // Next device path node
1426 DevPathNode
= NextDevicePathNode (DevPathNode
);
1435 InstallDevicePathCallback (
1439 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1440 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1441 &gEfiDevicePathProtocolGuid
,
1445 &mEfiDevPathNotifyReg
1450 This function is called each second during the boot manager waits the timeout.
1452 @param TimeoutRemain The remaining timeout.
1456 PlatformBootManagerWaitCallback (
1457 UINT16 TimeoutRemain
1460 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1461 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1464 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1466 Black
.Raw
= 0x00000000;
1467 White
.Raw
= 0x00FFFFFF;
1469 BootLogoUpdateProgress (
1472 L
"Start boot option",
1474 (Timeout
- TimeoutRemain
) * 100 / Timeout
,