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/RootBridgesConnectedEventGroup.h>
17 #include <Library/QemuBootOrderLib.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 (
94 IN EFI_HANDLE RootBridgeHandle
,
106 // BDS Platform Functions
110 PlatformBootManagerBeforeConsole (
117 Platform Bds init. Incude the platform firmware vendor, revision
131 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
132 InstallDevicePathCallback ();
134 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
135 ConnectRootBridge
, NULL
);
138 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
140 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
143 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
144 // the preparation of S3 system information. That logic has a hard dependency
145 // on the presence of the FACS ACPI table. Since our ACPI tables are only
146 // installed after PCI enumeration completes, we must not trigger the S3 save
147 // earlier, hence we can't signal End-of-Dxe earlier.
149 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
151 if (QemuFwCfgS3Enabled ()) {
153 // Save the boot script too. Note that this will require us to emit the
154 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
160 // Prevent further changes to LockBoxes or SMRAM.
163 Status
= gBS
->InstallProtocolInterface (&Handle
,
164 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
166 ASSERT_EFI_ERROR (Status
);
168 PlatformInitializeConsole (gPlatformConsole
);
175 IN EFI_HANDLE RootBridgeHandle
,
183 // Make the PCI bus driver connect the root bridge, non-recursively. This
184 // will produce a number of child handles with PciIo on them.
186 Status
= gBS
->ConnectController (
187 RootBridgeHandle
, // ControllerHandle
188 NULL
, // DriverImageHandle
189 NULL
, // RemainingDevicePath -- produce all
198 PrepareLpcBridgeDevicePath (
199 IN EFI_HANDLE DeviceHandle
205 Add IsaKeyboard to ConIn,
206 add IsaSerial to ConOut, ConIn, ErrOut.
211 DeviceHandle - Handle of PCIIO protocol.
215 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
216 EFI_STATUS - No LPC bridge is added.
221 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
222 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
226 Status
= gBS
->HandleProtocol (
228 &gEfiDevicePathProtocolGuid
,
231 if (EFI_ERROR (Status
)) {
234 TempDevicePath
= DevicePath
;
239 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
241 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
246 DevicePath
= TempDevicePath
;
247 gPnp16550ComPortDeviceNode
.UID
= 0;
249 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
250 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
251 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
256 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
257 if (DevPathStr
!= NULL
) {
260 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
262 gPnp16550ComPortDeviceNode
.UID
+ 1,
265 FreePool(DevPathStr
);
268 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
269 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
270 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
275 DevicePath
= TempDevicePath
;
276 gPnp16550ComPortDeviceNode
.UID
= 1;
278 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
279 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
280 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
285 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
286 if (DevPathStr
!= NULL
) {
289 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
291 gPnp16550ComPortDeviceNode
.UID
+ 1,
294 FreePool(DevPathStr
);
297 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
298 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
299 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
306 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
307 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
312 EFI_HANDLE PciDeviceHandle
;
313 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
314 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
315 UINTN GopHandleCount
;
316 EFI_HANDLE
*GopHandleBuffer
;
318 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
319 return EFI_INVALID_PARAMETER
;
323 // Initialize the GopDevicePath to be PciDevicePath
325 *GopDevicePath
= PciDevicePath
;
326 TempPciDevicePath
= PciDevicePath
;
328 Status
= gBS
->LocateDevicePath (
329 &gEfiDevicePathProtocolGuid
,
333 if (EFI_ERROR (Status
)) {
338 // Try to connect this handle, so that GOP dirver could start on this
339 // device and create child handles with GraphicsOutput Protocol installed
340 // on them, then we get device paths of these child handles and select
341 // them as possible console device.
343 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
345 Status
= gBS
->LocateHandleBuffer (
347 &gEfiGraphicsOutputProtocolGuid
,
352 if (!EFI_ERROR (Status
)) {
354 // Add all the child handles as possible Console Device
356 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
357 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
358 if (EFI_ERROR (Status
)) {
364 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
367 // In current implementation, we only enable one of the child handles
368 // as console device, i.e. sotre one of the child handle's device
369 // path to variable "ConOut"
370 // In futhure, we could select all child handles to be console device
373 *GopDevicePath
= TempDevicePath
;
376 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
377 // Add the integrity GOP device path.
379 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
380 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
383 gBS
->FreePool (GopHandleBuffer
);
390 PreparePciVgaDevicePath (
391 IN EFI_HANDLE DeviceHandle
397 Add PCI VGA to ConOut.
402 DeviceHandle - Handle of PCIIO protocol.
406 EFI_SUCCESS - PCI VGA is added to ConOut.
407 EFI_STATUS - No PCI VGA device is added.
412 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
413 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
416 GopDevicePath
= NULL
;
417 Status
= gBS
->HandleProtocol (
419 &gEfiDevicePathProtocolGuid
,
422 if (EFI_ERROR (Status
)) {
426 GetGopDevicePath (DevicePath
, &GopDevicePath
);
427 DevicePath
= GopDevicePath
;
429 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
435 PreparePciSerialDevicePath (
436 IN EFI_HANDLE DeviceHandle
442 Add PCI Serial to ConOut, ConIn, ErrOut.
447 DeviceHandle - Handle of PCIIO protocol.
451 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
452 EFI_STATUS - No PCI Serial device is added.
457 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
460 Status
= gBS
->HandleProtocol (
462 &gEfiDevicePathProtocolGuid
,
465 if (EFI_ERROR (Status
)) {
469 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
470 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
472 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
473 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
474 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
480 VisitAllInstancesOfProtocol (
482 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
488 EFI_HANDLE
*HandleBuffer
;
493 // Start to check all the PciIo to find all possible device
497 Status
= gBS
->LocateHandleBuffer (
504 if (EFI_ERROR (Status
)) {
508 for (Index
= 0; Index
< HandleCount
; Index
++) {
509 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
510 if (EFI_ERROR (Status
)) {
514 Status
= (*CallBackFunction
) (
521 gBS
->FreePool (HandleBuffer
);
529 VisitingAPciInstance (
530 IN EFI_HANDLE Handle
,
536 EFI_PCI_IO_PROTOCOL
*PciIo
;
539 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
542 // Check for all PCI device
544 Status
= PciIo
->Pci
.Read (
548 sizeof (Pci
) / sizeof (UINT32
),
551 if (EFI_ERROR (Status
)) {
555 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
566 VisitAllPciInstances (
567 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
570 return VisitAllInstancesOfProtocol (
571 &gEfiPciIoProtocolGuid
,
572 VisitingAPciInstance
,
573 (VOID
*)(UINTN
) CallBackFunction
579 Do platform specific PCI Device check and add them to
580 ConOut, ConIn, ErrOut.
582 @param[in] Handle - Handle of PCI device instance
583 @param[in] PciIo - PCI IO protocol instance
584 @param[in] Pci - PCI Header register block
586 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
587 @retval EFI_STATUS - PCI Device check or Console variable update fail.
592 DetectAndPreparePlatformPciDevicePath (
593 IN EFI_HANDLE Handle
,
594 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
600 Status
= PciIo
->Attributes (
602 EfiPciIoAttributeOperationEnable
,
603 EFI_PCI_DEVICE_ENABLE
,
606 ASSERT_EFI_ERROR (Status
);
608 if (!mDetectVgaOnly
) {
610 // Here we decide whether it is LPC Bridge
612 if ((IS_PCI_LPC (Pci
)) ||
613 ((IS_PCI_ISA_PDECODE (Pci
)) &&
614 (Pci
->Hdr
.VendorId
== 0x8086) &&
615 (Pci
->Hdr
.DeviceId
== 0x7000)
619 // Add IsaKeyboard to ConIn,
620 // add IsaSerial to ConOut, ConIn, ErrOut
622 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
623 PrepareLpcBridgeDevicePath (Handle
);
627 // Here we decide which Serial device to enable in PCI bus
629 if (IS_PCI_16550SERIAL (Pci
)) {
631 // Add them to ConOut, ConIn, ErrOut.
633 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
634 PreparePciSerialDevicePath (Handle
);
640 // Here we decide which VGA device to enable in PCI bus
642 if (IS_PCI_VGA (Pci
)) {
644 // Add them to ConOut.
646 DEBUG ((EFI_D_INFO
, "Found PCI VGA device\n"));
647 PreparePciVgaDevicePath (Handle
);
656 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
658 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
660 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
661 @retval EFI_STATUS - PCI Device check or Console variable update fail.
665 DetectAndPreparePlatformPciDevicePaths (
666 BOOLEAN DetectVgaOnly
669 mDetectVgaOnly
= DetectVgaOnly
;
670 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
675 PlatformInitializeConsole (
676 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
682 Connect the predefined platform default console device. Always try to find
683 and enable the vga device if have.
687 PlatformConsole - Predfined platform default console device array.
691 EFI_DEVICE_PATH_PROTOCOL
*VarConout
;
692 EFI_DEVICE_PATH_PROTOCOL
*VarConin
;
695 // Connect RootBridge
697 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME
, (VOID
**) &VarConout
, NULL
);
698 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME
, (VOID
**) &VarConin
, NULL
);
700 if (VarConout
== NULL
|| VarConin
== NULL
) {
702 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
704 DetectAndPreparePlatformPciDevicePaths (FALSE
);
707 // Have chance to connect the platform default console,
708 // the platform default console is the minimue device group
709 // the platform should support
711 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
713 // Update the console variable with the connect type
715 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
716 EfiBootManagerUpdateConsoleVariable (ConIn
, PlatformConsole
[Index
].DevicePath
, NULL
);
718 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
719 EfiBootManagerUpdateConsoleVariable (ConOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
721 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
722 EfiBootManagerUpdateConsoleVariable (ErrOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
727 // Only detect VGA device and add them to ConOut
729 DetectAndPreparePlatformPciDevicePaths (TRUE
);
735 Configure PCI Interrupt Line register for applicable devices
736 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
738 @param[in] Handle - Handle of PCI device instance
739 @param[in] PciIo - PCI IO protocol instance
740 @param[in] PciHdr - PCI Header register block
742 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
748 IN EFI_HANDLE Handle
,
749 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
750 IN PCI_TYPE00
*PciHdr
753 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
754 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
759 UINT32 RootBusNumber
;
761 Status
= EFI_SUCCESS
;
763 if (PciHdr
->Device
.InterruptPin
!= 0) {
765 DevPathNode
= DevicePathFromHandle (Handle
);
766 ASSERT (DevPathNode
!= NULL
);
767 DevPath
= DevPathNode
;
770 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
771 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
772 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
773 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
777 // Compute index into PciHostIrqs[] table by walking
778 // the device path and adding up all device numbers
780 Status
= EFI_NOT_FOUND
;
782 Idx
= PciHdr
->Device
.InterruptPin
- 1;
783 while (!IsDevicePathEnd (DevPathNode
)) {
784 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
785 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
787 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
790 // Unlike SeaBIOS, which starts climbing from the leaf device
791 // up toward the root, we traverse the device path starting at
792 // the root moving toward the leaf node.
793 // The slot number of the top-level parent bridge is needed for
794 // Q35 cases with more than 24 slots on the root bus.
796 if (Status
!= EFI_SUCCESS
) {
797 Status
= EFI_SUCCESS
;
798 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
802 DevPathNode
= NextDevicePathNode (DevPathNode
);
804 if (EFI_ERROR (Status
)) {
807 if (RootBusNumber
== 0 && RootSlot
== 0) {
810 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
817 // Final PciHostIrqs[] index calculation depends on the platform
818 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
820 switch (mHostBridgeDevId
) {
821 case INTEL_82441_DEVICE_ID
:
824 case INTEL_Q35_MCH_DEVICE_ID
:
826 // SeaBIOS contains the following comment:
827 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
828 // with a different starting index - see q35-acpi-dsdt.dsl.
830 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
834 // in this case, subtract back out RootSlot from Idx
835 // (SeaBIOS never adds it to begin with, but that would make our
836 // device path traversal loop above too awkward)
842 ASSERT (FALSE
); // should never get here
844 Idx
%= ARRAY_SIZE (PciHostIrqs
);
845 IrqLine
= PciHostIrqs
[Idx
];
849 CHAR16
*DevPathString
;
850 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
851 UINTN Segment
, Bus
, Device
, Function
;
853 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
854 if (DevPathString
== NULL
) {
855 DevPathString
= Fallback
;
857 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
858 ASSERT_EFI_ERROR (Status
);
860 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
861 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
864 if (DevPathString
!= Fallback
) {
865 FreePool (DevPathString
);
871 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
873 Status
= PciIo
->Pci
.Write (
887 PciAcpiInitialization (
893 // Query Host Bridge DID to determine platform type
895 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
896 switch (mHostBridgeDevId
) {
897 case INTEL_82441_DEVICE_ID
:
898 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
900 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
902 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
903 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
904 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
905 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
907 case INTEL_Q35_MCH_DEVICE_ID
:
908 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
910 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
912 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
913 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
914 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
915 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
916 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
917 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
918 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
919 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
922 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
923 __FUNCTION__
, mHostBridgeDevId
));
929 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
931 VisitAllPciInstances (SetPciIntLine
);
934 // Set ACPI SCI_EN bit in PMCNTRL
936 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
942 ConnectRecursivelyIfPciMassStorage (
943 IN EFI_HANDLE Handle
,
944 IN EFI_PCI_IO_PROTOCOL
*Instance
,
945 IN PCI_TYPE00
*PciHeader
949 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
952 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
)) {
954 Status
= gBS
->HandleProtocol (
956 &gEfiDevicePathProtocolGuid
,
959 if (EFI_ERROR (Status
)) {
966 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
967 if (DevPathStr
!= NULL
) {
970 "Found Mass Storage device: %s\n",
973 FreePool(DevPathStr
);
976 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
977 if (EFI_ERROR (Status
)) {
988 This notification function is invoked when the
989 EMU Variable FVB has been changed.
991 @param Event The event that occured
992 @param Context For EFI compatiblity. Not used.
997 EmuVariablesUpdatedCallback (
1002 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1003 UpdateNvVarsOnFileSystem ();
1009 VisitingFileSystemInstance (
1010 IN EFI_HANDLE Handle
,
1016 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1018 if (ConnectedToFileSystem
) {
1019 return EFI_ALREADY_STARTED
;
1022 Status
= ConnectNvVarsToFileSystem (Handle
);
1023 if (EFI_ERROR (Status
)) {
1027 ConnectedToFileSystem
= TRUE
;
1029 EfiCreateProtocolNotifyEvent (
1030 &gEfiDevicePathProtocolGuid
,
1032 EmuVariablesUpdatedCallback
,
1034 &mEmuVariableEventReg
1036 PcdSet64 (PcdEmuVariableEvent
, (UINT64
)(UINTN
) mEmuVariableEvent
);
1043 PlatformBdsRestoreNvVarsFromHardDisk (
1046 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1047 VisitAllInstancesOfProtocol (
1048 &gEfiSimpleFileSystemProtocolGuid
,
1049 VisitingFileSystemInstance
,
1057 PlatformBdsConnectSequence (
1062 Routine Description:
1064 Connect with predeined platform connect sequence,
1065 the OEM/IBV can customize with their own connect sequence.
1079 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1084 // Here we can get the customized platform connect sequence
1085 // Notes: we can connect with new variable which record the
1086 // last time boots connect device path sequence
1088 while (gPlatformConnectSequence
[Index
] != NULL
) {
1090 // Build the platform boot option
1092 BdsLibConnectDevicePath (gPlatformConnectSequence
[Index
]);
1097 // Just use the simple policy to connect all devices
1099 BdsLibConnectAll ();
1101 PciAcpiInitialization ();
1104 // Clear the logo after all devices are connected.
1106 gST
->ConOut
->ClearScreen (gST
->ConOut
);
1110 PlatformBdsGetDriverOption (
1111 IN OUT LIST_ENTRY
*BdsDriverLists
1115 Routine Description:
1117 Load the predefined driver option, OEM/IBV can customize this
1118 to load their own drivers
1122 BdsDriverLists - The header of the driver option link list.
1130 DEBUG ((EFI_D_INFO
, "PlatformBdsGetDriverOption\n"));
1135 PlatformBdsDiagnostics (
1136 IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel
,
1137 IN BOOLEAN QuietBoot
,
1138 IN BASEM_MEMORY_TEST BaseMemoryTest
1142 Routine Description:
1144 Perform the platform diagnostic, such like test memory. OEM/IBV also
1145 can customize this fuction to support specific platform diagnostic.
1149 MemoryTestLevel - The memory test intensive level
1151 QuietBoot - Indicate if need to enable the quiet boot
1153 BaseMemoryTest - A pointer to BaseMemoryTest()
1163 DEBUG ((EFI_D_INFO
, "PlatformBdsDiagnostics\n"));
1166 // Here we can decide if we need to show
1167 // the diagnostics screen
1168 // Notes: this quiet boot code should be remove
1169 // from the graphic lib
1172 EnableQuietBoot (PcdGetPtr(PcdLogoFile
));
1174 // Perform system diagnostic
1176 Status
= BaseMemoryTest (MemoryTestLevel
);
1177 if (EFI_ERROR (Status
)) {
1178 DisableQuietBoot ();
1184 // Perform system diagnostic
1186 Status
= BaseMemoryTest (MemoryTestLevel
);
1191 Save the S3 boot script.
1193 Note that DxeSmmReadyToLock must be signaled after this function returns;
1194 otherwise the script wouldn't be saved actually.
1203 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1204 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1206 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1207 (VOID
**) &BootScript
);
1208 ASSERT_EFI_ERROR (Status
);
1211 // Despite the opcode documentation in the PI spec, the protocol
1212 // implementation embeds a deep copy of the info in the boot script, rather
1213 // than storing just a pointer to runtime or NVS storage.
1215 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1216 (UINT32
) sizeof Info
,
1217 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1218 ASSERT_EFI_ERROR (Status
);
1224 PlatformBootManagerAfterConsole (
1229 Routine Description:
1231 The function will excute with as the platform policy, current policy
1232 is driven by boot mode. IBV/OEM can customize this code for their specific
1238 EFI_BOOT_MODE BootMode
;
1240 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1242 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1243 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1244 "from disk since flash variables appear to be supported.\n"));
1247 // Try to restore variables from the hard disk early so
1248 // they can be used for the other BDS connect operations.
1250 PlatformBdsRestoreNvVarsFromHardDisk ();
1254 // Load the driver option as the driver option list
1256 PlatformBdsGetDriverOption (DriverOptionList
);
1259 // Get current Boot Mode
1261 Status
= BdsLibGetBootMode (&BootMode
);
1262 DEBUG ((EFI_D_ERROR
, "Boot Mode:%x\n", BootMode
));
1265 // Go the different platform policy with different boot mode
1266 // Notes: this part code can be change with the table policy
1268 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1271 // Memory test and Logo show
1273 PlatformBdsDiagnostics (IGNORE
, TRUE
, BaseMemoryTest
);
1276 // Perform some platform specific connect sequence
1278 PlatformBdsConnectSequence ();
1281 // Process QEMU's -kernel command line option
1283 TryRunningQemuKernel ();
1285 DEBUG ((EFI_D_INFO
, "BdsLibConnectAll\n"));
1286 BdsLibConnectAll ();
1287 BdsLibEnumerateAllBootOption (BootOptionList
);
1289 SetBootOrderFromQemu (BootOptionList
);
1291 // The BootOrder variable may have changed, reload the in-memory list with
1294 BdsLibBuildOptionFromVar (BootOptionList
, L
"BootOrder");
1296 PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE
);
1301 PlatformBdsBootSuccess (
1302 IN BDS_COMMON_OPTION
*Option
1306 Routine Description:
1308 Hook point after a boot attempt succeeds. We don't expect a boot option to
1309 return, so the EFI 1.0 specification defines that you will default to an
1310 interactive mode and stop processing the BootOrder list in this case. This
1311 is alos a platform implementation and can be customized by IBV/OEM.
1315 Option - Pointer to Boot Option that succeeded to boot.
1325 DEBUG ((EFI_D_INFO
, "PlatformBdsBootSuccess\n"));
1327 // If Boot returned with EFI_SUCCESS and there is not in the boot device
1328 // select loop then we need to pop up a UI and wait for user input.
1330 TmpStr
= Option
->StatusString
;
1331 if (TmpStr
!= NULL
) {
1332 BdsLibOutputStrings (gST
->ConOut
, TmpStr
, Option
->Description
, L
"\n\r", NULL
);
1339 PlatformBdsBootFail (
1340 IN BDS_COMMON_OPTION
*Option
,
1341 IN EFI_STATUS Status
,
1342 IN CHAR16
*ExitData
,
1343 IN UINTN ExitDataSize
1347 Routine Description:
1349 Hook point after a boot attempt fails.
1353 Option - Pointer to Boot Option that failed to boot.
1355 Status - Status returned from failed boot.
1357 ExitData - Exit data returned from failed boot.
1359 ExitDataSize - Exit data size returned from failed boot.
1369 DEBUG ((EFI_D_INFO
, "PlatformBdsBootFail\n"));
1372 // If Boot returned with failed status then we need to pop up a UI and wait
1375 TmpStr
= Option
->StatusString
;
1376 if (TmpStr
!= NULL
) {
1377 BdsLibOutputStrings (gST
->ConOut
, TmpStr
, Option
->Description
, L
"\n\r", NULL
);
1384 PlatformBdsLockNonUpdatableFlash (
1388 DEBUG ((EFI_D_INFO
, "PlatformBdsLockNonUpdatableFlash\n"));
1394 This notification function is invoked when an instance of the
1395 EFI_DEVICE_PATH_PROTOCOL is produced.
1397 @param Event The event that occured
1398 @param Context For EFI compatiblity. Not used.
1411 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1412 ATAPI_DEVICE_PATH
*Atapi
;
1415 // Examine all new handles
1419 // Get the next handle
1421 BufferSize
= sizeof (Handle
);
1422 Status
= gBS
->LocateHandle (
1425 mEfiDevPathNotifyReg
,
1431 // If not found, we're done
1433 if (EFI_NOT_FOUND
== Status
) {
1437 if (EFI_ERROR (Status
)) {
1442 // Get the DevicePath protocol on that handle
1444 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevPathNode
);
1445 ASSERT_EFI_ERROR (Status
);
1447 while (!IsDevicePathEnd (DevPathNode
)) {
1449 // Find the handler to dump this device path node
1452 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1453 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1455 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1461 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1468 // Next device path node
1470 DevPathNode
= NextDevicePathNode (DevPathNode
);
1479 InstallDevicePathCallback (
1483 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1484 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1485 &gEfiDevicePathProtocolGuid
,
1489 &mEfiDevPathNotifyReg
1494 This function is called each second during the boot manager waits the timeout.
1496 @param TimeoutRemain The remaining timeout.
1500 PlatformBootManagerWaitCallback (
1501 UINT16 TimeoutRemain