2 Platform BDS customizations.
4 Copyright (c) 2004 - 2014, 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 <Library/QemuBootOrderLib.h>
23 VOID
*mEfiDevPathNotifyReg
;
24 EFI_EVENT mEfiDevPathEvent
;
25 VOID
*mEmuVariableEventReg
;
26 EFI_EVENT mEmuVariableEvent
;
27 BOOLEAN mDetectVgaOnly
;
28 UINT16 mHostBridgeDevId
;
31 // Table of host IRQs matching PCI IRQs A-D
32 // (for configuring PCI Interrupt Line register)
34 CONST UINT8 PciHostIrqs
[] = {
35 0x0a, 0x0a, 0x0b, 0x0b
41 #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
49 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
56 @param[in] Handle - Handle of PCI device instance
57 @param[in] PciIo - PCI IO protocol instance
58 @param[in] Pci - PCI Header register block
62 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
64 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
70 // Function prototypes
74 VisitAllInstancesOfProtocol (
76 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
81 VisitAllPciInstancesOfProtocol (
82 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
86 InstallDevicePathCallback (
91 // BDS Platform Functions
102 Platform Bds init. Incude the platform firmware vendor, revision
113 DEBUG ((EFI_D_INFO
, "PlatformBdsInit\n"));
114 InstallDevicePathCallback ();
121 IN EFI_HANDLE RootBridgeHandle
,
129 // Make the PCI bus driver connect the root bridge, non-recursively. This
130 // will produce a number of child handles with PciIo on them.
132 Status
= gBS
->ConnectController (
133 RootBridgeHandle
, // ControllerHandle
134 NULL
, // DriverImageHandle
135 NULL
, // RemainingDevicePath -- produce all
144 PrepareLpcBridgeDevicePath (
145 IN EFI_HANDLE DeviceHandle
151 Add IsaKeyboard to ConIn,
152 add IsaSerial to ConOut, ConIn, ErrOut.
157 DeviceHandle - Handle of PCIIO protocol.
161 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
162 EFI_STATUS - No LPC bridge is added.
167 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
168 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
172 Status
= gBS
->HandleProtocol (
174 &gEfiDevicePathProtocolGuid
,
177 if (EFI_ERROR (Status
)) {
180 TempDevicePath
= DevicePath
;
185 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
187 BdsLibUpdateConsoleVariable (VarConsoleInp
, DevicePath
, NULL
);
192 DevicePath
= TempDevicePath
;
193 gPnp16550ComPortDeviceNode
.UID
= 0;
195 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
196 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
197 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
202 DevPathStr
= DevicePathToStr(DevicePath
);
203 if (DevPathStr
!= NULL
) {
206 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
208 gPnp16550ComPortDeviceNode
.UID
+ 1,
211 FreePool(DevPathStr
);
214 BdsLibUpdateConsoleVariable (VarConsoleOut
, DevicePath
, NULL
);
215 BdsLibUpdateConsoleVariable (VarConsoleInp
, DevicePath
, NULL
);
216 BdsLibUpdateConsoleVariable (VarErrorOut
, DevicePath
, NULL
);
221 DevicePath
= TempDevicePath
;
222 gPnp16550ComPortDeviceNode
.UID
= 1;
224 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
225 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
226 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
231 DevPathStr
= DevicePathToStr(DevicePath
);
232 if (DevPathStr
!= NULL
) {
235 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
237 gPnp16550ComPortDeviceNode
.UID
+ 1,
240 FreePool(DevPathStr
);
243 BdsLibUpdateConsoleVariable (VarConsoleOut
, DevicePath
, NULL
);
244 BdsLibUpdateConsoleVariable (VarConsoleInp
, DevicePath
, NULL
);
245 BdsLibUpdateConsoleVariable (VarErrorOut
, DevicePath
, NULL
);
252 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
253 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
258 EFI_HANDLE PciDeviceHandle
;
259 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
260 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
261 UINTN GopHandleCount
;
262 EFI_HANDLE
*GopHandleBuffer
;
264 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
265 return EFI_INVALID_PARAMETER
;
269 // Initialize the GopDevicePath to be PciDevicePath
271 *GopDevicePath
= PciDevicePath
;
272 TempPciDevicePath
= PciDevicePath
;
274 Status
= gBS
->LocateDevicePath (
275 &gEfiDevicePathProtocolGuid
,
279 if (EFI_ERROR (Status
)) {
284 // Try to connect this handle, so that GOP dirver could start on this
285 // device and create child handles with GraphicsOutput Protocol installed
286 // on them, then we get device paths of these child handles and select
287 // them as possible console device.
289 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
291 Status
= gBS
->LocateHandleBuffer (
293 &gEfiGraphicsOutputProtocolGuid
,
298 if (!EFI_ERROR (Status
)) {
300 // Add all the child handles as possible Console Device
302 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
303 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
304 if (EFI_ERROR (Status
)) {
310 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
313 // In current implementation, we only enable one of the child handles
314 // as console device, i.e. sotre one of the child handle's device
315 // path to variable "ConOut"
316 // In futhure, we could select all child handles to be console device
319 *GopDevicePath
= TempDevicePath
;
322 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
323 // Add the integrity GOP device path.
325 BdsLibUpdateConsoleVariable (VarConsoleOutDev
, NULL
, PciDevicePath
);
326 BdsLibUpdateConsoleVariable (VarConsoleOutDev
, TempDevicePath
, NULL
);
329 gBS
->FreePool (GopHandleBuffer
);
336 PreparePciVgaDevicePath (
337 IN EFI_HANDLE DeviceHandle
343 Add PCI VGA to ConOut.
348 DeviceHandle - Handle of PCIIO protocol.
352 EFI_SUCCESS - PCI VGA is added to ConOut.
353 EFI_STATUS - No PCI VGA device is added.
358 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
359 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
362 GopDevicePath
= NULL
;
363 Status
= gBS
->HandleProtocol (
365 &gEfiDevicePathProtocolGuid
,
368 if (EFI_ERROR (Status
)) {
372 GetGopDevicePath (DevicePath
, &GopDevicePath
);
373 DevicePath
= GopDevicePath
;
375 BdsLibUpdateConsoleVariable (VarConsoleOut
, DevicePath
, NULL
);
381 PreparePciSerialDevicePath (
382 IN EFI_HANDLE DeviceHandle
388 Add PCI Serial to ConOut, ConIn, ErrOut.
393 DeviceHandle - Handle of PCIIO protocol.
397 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
398 EFI_STATUS - No PCI Serial device is added.
403 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
406 Status
= gBS
->HandleProtocol (
408 &gEfiDevicePathProtocolGuid
,
411 if (EFI_ERROR (Status
)) {
415 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
416 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
418 BdsLibUpdateConsoleVariable (VarConsoleOut
, DevicePath
, NULL
);
419 BdsLibUpdateConsoleVariable (VarConsoleInp
, DevicePath
, NULL
);
420 BdsLibUpdateConsoleVariable (VarErrorOut
, DevicePath
, NULL
);
426 VisitAllInstancesOfProtocol (
428 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
434 EFI_HANDLE
*HandleBuffer
;
439 // Start to check all the PciIo to find all possible device
443 Status
= gBS
->LocateHandleBuffer (
450 if (EFI_ERROR (Status
)) {
454 for (Index
= 0; Index
< HandleCount
; Index
++) {
455 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
456 if (EFI_ERROR (Status
)) {
460 Status
= (*CallBackFunction
) (
467 gBS
->FreePool (HandleBuffer
);
475 VisitingAPciInstance (
476 IN EFI_HANDLE Handle
,
482 EFI_PCI_IO_PROTOCOL
*PciIo
;
485 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
488 // Check for all PCI device
490 Status
= PciIo
->Pci
.Read (
494 sizeof (Pci
) / sizeof (UINT32
),
497 if (EFI_ERROR (Status
)) {
501 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
512 VisitAllPciInstances (
513 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
516 return VisitAllInstancesOfProtocol (
517 &gEfiPciIoProtocolGuid
,
518 VisitingAPciInstance
,
519 (VOID
*)(UINTN
) CallBackFunction
525 Do platform specific PCI Device check and add them to
526 ConOut, ConIn, ErrOut.
528 @param[in] Handle - Handle of PCI device instance
529 @param[in] PciIo - PCI IO protocol instance
530 @param[in] Pci - PCI Header register block
532 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
533 @retval EFI_STATUS - PCI Device check or Console variable update fail.
538 DetectAndPreparePlatformPciDevicePath (
539 IN EFI_HANDLE Handle
,
540 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
546 Status
= PciIo
->Attributes (
548 EfiPciIoAttributeOperationEnable
,
549 EFI_PCI_DEVICE_ENABLE
,
552 ASSERT_EFI_ERROR (Status
);
554 if (!mDetectVgaOnly
) {
556 // Here we decide whether it is LPC Bridge
558 if ((IS_PCI_LPC (Pci
)) ||
559 ((IS_PCI_ISA_PDECODE (Pci
)) &&
560 (Pci
->Hdr
.VendorId
== 0x8086) &&
561 (Pci
->Hdr
.DeviceId
== 0x7000)
565 // Add IsaKeyboard to ConIn,
566 // add IsaSerial to ConOut, ConIn, ErrOut
568 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
569 PrepareLpcBridgeDevicePath (Handle
);
573 // Here we decide which Serial device to enable in PCI bus
575 if (IS_PCI_16550SERIAL (Pci
)) {
577 // Add them to ConOut, ConIn, ErrOut.
579 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
580 PreparePciSerialDevicePath (Handle
);
586 // Here we decide which VGA device to enable in PCI bus
588 if (IS_PCI_VGA (Pci
)) {
590 // Add them to ConOut.
592 DEBUG ((EFI_D_INFO
, "Found PCI VGA device\n"));
593 PreparePciVgaDevicePath (Handle
);
602 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
604 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
606 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
607 @retval EFI_STATUS - PCI Device check or Console variable update fail.
611 DetectAndPreparePlatformPciDevicePaths (
612 BOOLEAN DetectVgaOnly
615 mDetectVgaOnly
= DetectVgaOnly
;
616 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
621 PlatformBdsConnectConsole (
622 IN BDS_CONSOLE_CONNECT_ENTRY
*PlatformConsole
628 Connect the predefined platform default console device. Always try to find
629 and enable the vga device if have.
633 PlatformConsole - Predfined platform default console device array.
637 EFI_SUCCESS - Success connect at least one ConIn and ConOut
638 device, there must have one ConOut device is
641 EFI_STATUS - Return the status of
642 BdsLibConnectAllDefaultConsoles ()
648 EFI_DEVICE_PATH_PROTOCOL
*VarConout
;
649 EFI_DEVICE_PATH_PROTOCOL
*VarConin
;
650 UINTN DevicePathSize
;
653 // Connect RootBridge
655 VarConout
= BdsLibGetVariableAndSize (
657 &gEfiGlobalVariableGuid
,
660 VarConin
= BdsLibGetVariableAndSize (
662 &gEfiGlobalVariableGuid
,
666 if (VarConout
== NULL
|| VarConin
== NULL
) {
668 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
670 DetectAndPreparePlatformPciDevicePaths (FALSE
);
673 // Have chance to connect the platform default console,
674 // the platform default console is the minimue device group
675 // the platform should support
677 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
679 // Update the console variable with the connect type
681 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
682 BdsLibUpdateConsoleVariable (VarConsoleInp
, PlatformConsole
[Index
].DevicePath
, NULL
);
684 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
685 BdsLibUpdateConsoleVariable (VarConsoleOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
687 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
688 BdsLibUpdateConsoleVariable (VarErrorOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
693 // Only detect VGA device and add them to ConOut
695 DetectAndPreparePlatformPciDevicePaths (TRUE
);
699 // Connect the all the default console with current cosole variable
701 Status
= BdsLibConnectAllDefaultConsoles ();
702 if (EFI_ERROR (Status
)) {
711 Configure PCI Interrupt Line register for applicable devices
712 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
714 @param[in] Handle - Handle of PCI device instance
715 @param[in] PciIo - PCI IO protocol instance
716 @param[in] PciHdr - PCI Header register block
718 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
724 IN EFI_HANDLE Handle
,
725 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
726 IN PCI_TYPE00
*PciHdr
729 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
730 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
735 UINT32 RootBusNumber
;
737 Status
= EFI_SUCCESS
;
739 if (PciHdr
->Device
.InterruptPin
!= 0) {
741 DevPathNode
= DevicePathFromHandle (Handle
);
742 ASSERT (DevPathNode
!= NULL
);
743 DevPath
= DevPathNode
;
746 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
747 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
748 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
749 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
753 // Compute index into PciHostIrqs[] table by walking
754 // the device path and adding up all device numbers
756 Status
= EFI_NOT_FOUND
;
758 Idx
= PciHdr
->Device
.InterruptPin
- 1;
759 while (!IsDevicePathEnd (DevPathNode
)) {
760 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
761 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
763 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
766 // Unlike SeaBIOS, which starts climbing from the leaf device
767 // up toward the root, we traverse the device path starting at
768 // the root moving toward the leaf node.
769 // The slot number of the top-level parent bridge is needed for
770 // Q35 cases with more than 24 slots on the root bus.
772 if (Status
!= EFI_SUCCESS
) {
773 Status
= EFI_SUCCESS
;
774 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
778 DevPathNode
= NextDevicePathNode (DevPathNode
);
780 if (EFI_ERROR (Status
)) {
783 if (RootBusNumber
== 0 && RootSlot
== 0) {
786 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
793 // Final PciHostIrqs[] index calculation depends on the platform
794 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
796 switch (mHostBridgeDevId
) {
797 case INTEL_82441_DEVICE_ID
:
800 case INTEL_Q35_MCH_DEVICE_ID
:
802 // SeaBIOS contains the following comment:
803 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
804 // with a different starting index - see q35-acpi-dsdt.dsl.
806 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
810 // in this case, subtract back out RootSlot from Idx
811 // (SeaBIOS never adds it to begin with, but that would make our
812 // device path traversal loop above too awkward)
818 ASSERT (FALSE
); // should never get here
820 Idx
%= ARRAY_SIZE (PciHostIrqs
);
821 IrqLine
= PciHostIrqs
[Idx
];
825 CHAR16
*DevPathString
;
826 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
827 UINTN Segment
, Bus
, Device
, Function
;
829 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
830 if (DevPathString
== NULL
) {
831 DevPathString
= Fallback
;
833 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
834 ASSERT_EFI_ERROR (Status
);
836 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
837 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
840 if (DevPathString
!= Fallback
) {
841 FreePool (DevPathString
);
847 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
849 Status
= PciIo
->Pci
.Write (
863 PciAcpiInitialization (
869 // Query Host Bridge DID to determine platform type
871 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
872 switch (mHostBridgeDevId
) {
873 case INTEL_82441_DEVICE_ID
:
874 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
876 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
878 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
879 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
880 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
881 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
883 case INTEL_Q35_MCH_DEVICE_ID
:
884 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
886 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
888 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
889 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
890 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
891 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
892 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
893 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
894 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
895 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
898 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
899 __FUNCTION__
, mHostBridgeDevId
));
905 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
907 VisitAllPciInstances (SetPciIntLine
);
910 // Set ACPI SCI_EN bit in PMCNTRL
912 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
918 ConnectRecursivelyIfPciMassStorage (
919 IN EFI_HANDLE Handle
,
920 IN EFI_PCI_IO_PROTOCOL
*Instance
,
921 IN PCI_TYPE00
*PciHeader
925 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
928 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
)) {
930 Status
= gBS
->HandleProtocol (
932 &gEfiDevicePathProtocolGuid
,
935 if (EFI_ERROR (Status
)) {
942 DevPathStr
= DevicePathToStr (DevicePath
);
943 if (DevPathStr
!= NULL
) {
946 "Found Mass Storage device: %s\n",
949 FreePool(DevPathStr
);
952 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
953 if (EFI_ERROR (Status
)) {
964 This notification function is invoked when the
965 EMU Variable FVB has been changed.
967 @param Event The event that occured
968 @param Context For EFI compatiblity. Not used.
973 EmuVariablesUpdatedCallback (
978 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
979 UpdateNvVarsOnFileSystem ();
985 VisitingFileSystemInstance (
986 IN EFI_HANDLE Handle
,
992 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
994 if (ConnectedToFileSystem
) {
995 return EFI_ALREADY_STARTED
;
998 Status
= ConnectNvVarsToFileSystem (Handle
);
999 if (EFI_ERROR (Status
)) {
1003 ConnectedToFileSystem
= TRUE
;
1005 EfiCreateProtocolNotifyEvent (
1006 &gEfiDevicePathProtocolGuid
,
1008 EmuVariablesUpdatedCallback
,
1010 &mEmuVariableEventReg
1012 PcdSet64 (PcdEmuVariableEvent
, (UINT64
)(UINTN
) mEmuVariableEvent
);
1019 PlatformBdsRestoreNvVarsFromHardDisk (
1022 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1023 VisitAllInstancesOfProtocol (
1024 &gEfiSimpleFileSystemProtocolGuid
,
1025 VisitingFileSystemInstance
,
1033 PlatformBdsConnectSequence (
1038 Routine Description:
1040 Connect with predeined platform connect sequence,
1041 the OEM/IBV can customize with their own connect sequence.
1055 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1060 // Here we can get the customized platform connect sequence
1061 // Notes: we can connect with new variable which record the
1062 // last time boots connect device path sequence
1064 while (gPlatformConnectSequence
[Index
] != NULL
) {
1066 // Build the platform boot option
1068 BdsLibConnectDevicePath (gPlatformConnectSequence
[Index
]);
1073 // Just use the simple policy to connect all devices
1075 BdsLibConnectAll ();
1077 PciAcpiInitialization ();
1080 // Clear the logo after all devices are connected.
1082 gST
->ConOut
->ClearScreen (gST
->ConOut
);
1086 PlatformBdsGetDriverOption (
1087 IN OUT LIST_ENTRY
*BdsDriverLists
1091 Routine Description:
1093 Load the predefined driver option, OEM/IBV can customize this
1094 to load their own drivers
1098 BdsDriverLists - The header of the driver option link list.
1106 DEBUG ((EFI_D_INFO
, "PlatformBdsGetDriverOption\n"));
1111 PlatformBdsDiagnostics (
1112 IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel
,
1113 IN BOOLEAN QuietBoot
,
1114 IN BASEM_MEMORY_TEST BaseMemoryTest
1118 Routine Description:
1120 Perform the platform diagnostic, such like test memory. OEM/IBV also
1121 can customize this fuction to support specific platform diagnostic.
1125 MemoryTestLevel - The memory test intensive level
1127 QuietBoot - Indicate if need to enable the quiet boot
1129 BaseMemoryTest - A pointer to BaseMemoryTest()
1139 DEBUG ((EFI_D_INFO
, "PlatformBdsDiagnostics\n"));
1142 // Here we can decide if we need to show
1143 // the diagnostics screen
1144 // Notes: this quiet boot code should be remove
1145 // from the graphic lib
1148 EnableQuietBoot (PcdGetPtr(PcdLogoFile
));
1150 // Perform system diagnostic
1152 Status
= BaseMemoryTest (MemoryTestLevel
);
1153 if (EFI_ERROR (Status
)) {
1154 DisableQuietBoot ();
1160 // Perform system diagnostic
1162 Status
= BaseMemoryTest (MemoryTestLevel
);
1167 Empty callback function executed when the EndOfDxe event group is signaled.
1169 We only need this function because we'd like to signal EndOfDxe, and for that
1170 we need to create an event, with a callback function.
1172 @param[in] Event Event whose notification function is being invoked.
1173 @param[in] Context The pointer to the notification function's context, which
1174 is implementation-dependent.
1188 Save the S3 boot script.
1190 Note that we trigger DxeSmmReadyToLock here -- otherwise the script wouldn't
1191 be saved actually. Triggering this protocol installation event in turn locks
1192 down SMM, so no further changes to LockBoxes or SMRAM are possible
1202 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
);
1221 Status
= gBS
->InstallProtocolInterface (&Handle
,
1222 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
1224 ASSERT_EFI_ERROR (Status
);
1230 PlatformBdsPolicyBehavior (
1231 IN OUT LIST_ENTRY
*DriverOptionList
,
1232 IN OUT LIST_ENTRY
*BootOptionList
,
1233 IN PROCESS_CAPSULES ProcessCapsules
,
1234 IN BASEM_MEMORY_TEST BaseMemoryTest
1238 Routine Description:
1240 The function will excute with as the platform policy, current policy
1241 is driven by boot mode. IBV/OEM can customize this code for their specific
1246 DriverOptionList - The header of the driver option link list
1248 BootOptionList - The header of the boot option link list
1250 ProcessCapsules - A pointer to ProcessCapsules()
1252 BaseMemoryTest - A pointer to BaseMemoryTest()
1261 EFI_BOOT_MODE BootMode
;
1262 EFI_EVENT EndOfDxeEvent
;
1264 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior\n"));
1266 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
1267 ConnectRootBridge
, NULL
);
1270 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
1271 // the preparation of S3 system information. That logic has a hard dependency
1272 // on the presence of the FACS ACPI table. Since our ACPI tables are only
1273 // installed after PCI enumeration completes, we must not trigger the S3 save
1274 // earlier, hence we can't signal End-of-Dxe earlier.
1276 Status
= gBS
->CreateEventEx (EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, OnEndOfDxe
,
1277 NULL
/* NotifyContext */, &gEfiEndOfDxeEventGroupGuid
,
1279 if (!EFI_ERROR (Status
)) {
1280 gBS
->SignalEvent (EndOfDxeEvent
);
1281 gBS
->CloseEvent (EndOfDxeEvent
);
1284 if (QemuFwCfgS3Enabled ()) {
1286 // Save the boot script too. Note that this requires/includes emitting the
1287 // DxeSmmReadyToLock event, which in turn locks down SMM.
1289 SaveS3BootScript ();
1292 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1293 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1294 "from disk since flash variables appear to be supported.\n"));
1297 // Try to restore variables from the hard disk early so
1298 // they can be used for the other BDS connect operations.
1300 PlatformBdsRestoreNvVarsFromHardDisk ();
1304 // Load the driver option as the driver option list
1306 PlatformBdsGetDriverOption (DriverOptionList
);
1309 // Get current Boot Mode
1311 Status
= BdsLibGetBootMode (&BootMode
);
1312 DEBUG ((EFI_D_ERROR
, "Boot Mode:%x\n", BootMode
));
1315 // Go the different platform policy with different boot mode
1316 // Notes: this part code can be change with the table policy
1318 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1320 // Connect platform console
1322 Status
= PlatformBdsConnectConsole (gPlatformConsole
);
1323 if (EFI_ERROR (Status
)) {
1325 // Here OEM/IBV can customize with defined action
1327 PlatformBdsNoConsoleAction ();
1331 // Memory test and Logo show
1333 PlatformBdsDiagnostics (IGNORE
, TRUE
, BaseMemoryTest
);
1336 // Perform some platform specific connect sequence
1338 PlatformBdsConnectSequence ();
1341 // Process QEMU's -kernel command line option
1343 TryRunningQemuKernel ();
1345 DEBUG ((EFI_D_INFO
, "BdsLibConnectAll\n"));
1346 BdsLibConnectAll ();
1347 BdsLibEnumerateAllBootOption (BootOptionList
);
1349 SetBootOrderFromQemu (BootOptionList
);
1351 // The BootOrder variable may have changed, reload the in-memory list with
1354 BdsLibBuildOptionFromVar (BootOptionList
, L
"BootOrder");
1356 PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE
);
1361 PlatformBdsBootSuccess (
1362 IN BDS_COMMON_OPTION
*Option
1366 Routine Description:
1368 Hook point after a boot attempt succeeds. We don't expect a boot option to
1369 return, so the EFI 1.0 specification defines that you will default to an
1370 interactive mode and stop processing the BootOrder list in this case. This
1371 is alos a platform implementation and can be customized by IBV/OEM.
1375 Option - Pointer to Boot Option that succeeded to boot.
1385 DEBUG ((EFI_D_INFO
, "PlatformBdsBootSuccess\n"));
1387 // If Boot returned with EFI_SUCCESS and there is not in the boot device
1388 // select loop then we need to pop up a UI and wait for user input.
1390 TmpStr
= Option
->StatusString
;
1391 if (TmpStr
!= NULL
) {
1392 BdsLibOutputStrings (gST
->ConOut
, TmpStr
, Option
->Description
, L
"\n\r", NULL
);
1399 PlatformBdsBootFail (
1400 IN BDS_COMMON_OPTION
*Option
,
1401 IN EFI_STATUS Status
,
1402 IN CHAR16
*ExitData
,
1403 IN UINTN ExitDataSize
1407 Routine Description:
1409 Hook point after a boot attempt fails.
1413 Option - Pointer to Boot Option that failed to boot.
1415 Status - Status returned from failed boot.
1417 ExitData - Exit data returned from failed boot.
1419 ExitDataSize - Exit data size returned from failed boot.
1429 DEBUG ((EFI_D_INFO
, "PlatformBdsBootFail\n"));
1432 // If Boot returned with failed status then we need to pop up a UI and wait
1435 TmpStr
= Option
->StatusString
;
1436 if (TmpStr
!= NULL
) {
1437 BdsLibOutputStrings (gST
->ConOut
, TmpStr
, Option
->Description
, L
"\n\r", NULL
);
1443 PlatformBdsNoConsoleAction (
1448 Routine Description:
1450 This function is remained for IBV/OEM to do some platform action,
1451 if there no console device can be connected.
1459 EFI_SUCCESS - Direct return success now.
1463 DEBUG ((EFI_D_INFO
, "PlatformBdsNoConsoleAction\n"));
1469 PlatformBdsLockNonUpdatableFlash (
1473 DEBUG ((EFI_D_INFO
, "PlatformBdsLockNonUpdatableFlash\n"));
1479 This notification function is invoked when an instance of the
1480 EFI_DEVICE_PATH_PROTOCOL is produced.
1482 @param Event The event that occured
1483 @param Context For EFI compatiblity. Not used.
1496 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1497 ATAPI_DEVICE_PATH
*Atapi
;
1500 // Examine all new handles
1504 // Get the next handle
1506 BufferSize
= sizeof (Handle
);
1507 Status
= gBS
->LocateHandle (
1510 mEfiDevPathNotifyReg
,
1516 // If not found, we're done
1518 if (EFI_NOT_FOUND
== Status
) {
1522 if (EFI_ERROR (Status
)) {
1527 // Get the DevicePath protocol on that handle
1529 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevPathNode
);
1530 ASSERT_EFI_ERROR (Status
);
1532 while (!IsDevicePathEnd (DevPathNode
)) {
1534 // Find the handler to dump this device path node
1537 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1538 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1540 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1546 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1553 // Next device path node
1555 DevPathNode
= NextDevicePathNode (DevPathNode
);
1564 InstallDevicePathCallback (
1568 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1569 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1570 &gEfiDevicePathProtocolGuid
,
1574 &mEfiDevPathNotifyReg
1579 Lock the ConsoleIn device in system table. All key
1580 presses will be ignored until the Password is typed in. The only way to
1581 disable the password is to type it in to a ConIn device.
1583 @param Password Password used to lock ConIn device.
1585 @retval EFI_SUCCESS lock the Console In Spliter virtual handle successfully.
1586 @retval EFI_UNSUPPORTED Password not found
1595 return EFI_UNSUPPORTED
;