2 Platform BDS customizations.
4 Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
5 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "BdsPlatform.h"
11 #include <Guid/RootBridgesConnectedEventGroup.h>
12 #include <Protocol/FirmwareVolume2.h>
13 #include <Library/PlatformBmPrintScLib.h>
14 #include <Library/Tcg2PhysicalPresenceLib.h>
16 #include <Protocol/BlockIo.h>
22 VOID
*mEfiDevPathNotifyReg
;
23 EFI_EVENT mEfiDevPathEvent
;
24 VOID
*mEmuVariableEventReg
;
25 EFI_EVENT mEmuVariableEvent
;
26 UINT16 mHostBridgeDevId
;
29 // Table of host IRQs matching PCI IRQs A-D
30 // (for configuring PCI Interrupt Line register)
32 CONST UINT8 PciHostIrqs
[] = {
33 0x0a, 0x0a, 0x0b, 0x0b
42 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
49 @param[in] Handle - Handle of PCI device instance
50 @param[in] PciIo - PCI IO protocol instance
51 @param[in] Pci - PCI Header register block
55 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
57 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
62 // Function prototypes
66 VisitAllInstancesOfProtocol (
68 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
73 VisitAllPciInstancesOfProtocol (
74 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
78 InstallDevicePathCallback (
83 PlatformRegisterFvBootOption (
91 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
92 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
93 UINTN BootOptionCount
;
94 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
95 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
96 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
98 Status
= gBS
->HandleProtocol (
100 &gEfiLoadedImageProtocolGuid
,
101 (VOID
**)&LoadedImage
103 ASSERT_EFI_ERROR (Status
);
105 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
106 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
107 ASSERT (DevicePath
!= NULL
);
108 DevicePath
= AppendDevicePathNode (
110 (EFI_DEVICE_PATH_PROTOCOL
*)&FileNode
112 ASSERT (DevicePath
!= NULL
);
114 Status
= EfiBootManagerInitializeLoadOption (
116 LoadOptionNumberUnassigned
,
124 ASSERT_EFI_ERROR (Status
);
125 FreePool (DevicePath
);
127 BootOptions
= EfiBootManagerGetLoadOptions (
132 OptionIndex
= EfiBootManagerFindLoadOption (
138 if (OptionIndex
== -1) {
139 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
140 ASSERT_EFI_ERROR (Status
);
143 EfiBootManagerFreeLoadOption (&NewOption
);
144 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
148 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
149 whose device paths do not resolve exactly to an FvFile in the system.
151 This removes any boot options that point to binaries built into the firmware
152 and have become stale due to any of the following:
153 - DXEFV's base address or size changed (historical),
154 - DXEFV's FvNameGuid changed,
155 - the FILE_GUID of the pointed-to binary changed,
156 - the referenced binary is no longer built into the firmware.
158 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
159 avoids exact duplicates.
162 RemoveStaleFvFileOptions (
166 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
167 UINTN BootOptionCount
;
170 BootOptions
= EfiBootManagerGetLoadOptions (
175 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
176 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
181 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
182 // then keep the boot option.
184 Node1
= BootOptions
[Index
].FilePath
;
185 if (!((DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
) &&
186 (DevicePathSubType (Node1
) == HW_MEMMAP_DP
)) &&
187 !((DevicePathType (Node1
) == MEDIA_DEVICE_PATH
) &&
188 (DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)))
194 // If the second device path node is not FvFile(...), then keep the boot
197 Node2
= NextDevicePathNode (Node1
);
198 if ((DevicePathType (Node2
) != MEDIA_DEVICE_PATH
) ||
199 (DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
))
205 // Locate the Firmware Volume2 protocol instance that is denoted by the
206 // boot option. If this lookup fails (i.e., the boot option references a
207 // firmware volume that doesn't exist), then we'll proceed to delete the
211 Status
= gBS
->LocateDevicePath (
212 &gEfiFirmwareVolume2ProtocolGuid
,
217 if (!EFI_ERROR (Status
)) {
219 // The firmware volume was found; now let's see if it contains the FvFile
220 // identified by GUID.
222 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
223 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
225 EFI_FV_FILETYPE FoundType
;
226 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
227 UINT32 AuthenticationStatus
;
229 Status
= gBS
->HandleProtocol (
231 &gEfiFirmwareVolume2ProtocolGuid
,
234 ASSERT_EFI_ERROR (Status
);
236 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
238 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
241 Status
= FvProtocol
->ReadFile (
243 &FvFileNode
->FvFileName
, // NameGuid
248 &AuthenticationStatus
250 if (!EFI_ERROR (Status
)) {
252 // The FvFile was found. Keep the boot option.
259 // Delete the boot option.
261 Status
= EfiBootManagerDeleteLoadOptionVariable (
262 BootOptions
[Index
].OptionNumber
,
266 CHAR16
*DevicePathString
;
268 DevicePathString
= ConvertDevicePathToText (
269 BootOptions
[Index
].FilePath
,
274 EFI_ERROR (Status
) ? DEBUG_WARN
: DEBUG_VERBOSE
,
275 "%a: removing stale Boot#%04x %s: %r\n",
277 (UINT32
)BootOptions
[Index
].OptionNumber
,
278 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
281 if (DevicePathString
!= NULL
) {
282 FreePool (DevicePathString
);
288 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
292 PlatformRegisterOptionsAndKeys (
300 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
303 // Register ENTER as CONTINUE key
305 Enter
.ScanCode
= SCAN_NULL
;
306 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
307 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
308 ASSERT_EFI_ERROR (Status
);
311 // Map F2 to Boot Manager Menu
313 F2
.ScanCode
= SCAN_F2
;
314 F2
.UnicodeChar
= CHAR_NULL
;
315 Esc
.ScanCode
= SCAN_ESC
;
316 Esc
.UnicodeChar
= CHAR_NULL
;
317 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
318 ASSERT_EFI_ERROR (Status
);
319 Status
= EfiBootManagerAddKeyOptionVariable (
321 (UINT16
)BootOption
.OptionNumber
,
326 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
327 Status
= EfiBootManagerAddKeyOptionVariable (
329 (UINT16
)BootOption
.OptionNumber
,
334 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
340 IN EFI_HANDLE RootBridgeHandle
,
348 ConnectVirtioPciRng (
349 IN EFI_HANDLE Handle
,
361 // BDS Platform Functions
365 Do the platform init, can be customized by OEM/IBV
367 Possible things that can be done in PlatformBootManagerBeforeConsole:
369 > Update console variable: 1. include hot-plug devices;
370 > 2. Clear ConIn and add SOL for AMT
371 > Register new Driver#### or Boot####
372 > Register new Key####: e.g.: F12
373 > Signal ReadyToLock event
374 > Authentication action: 1. connect Auth devices;
375 > 2. Identify auto logon user.
379 PlatformBootManagerBeforeConsole (
386 DEBUG ((DEBUG_INFO
, "PlatformBootManagerBeforeConsole\n"));
387 InstallDevicePathCallback ();
389 VisitAllInstancesOfProtocol (
390 &gEfiPciRootBridgeIoProtocolGuid
,
396 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
398 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
401 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
402 // the preparation of S3 system information. That logic has a hard dependency
403 // on the presence of the FACS ACPI table. Since our ACPI tables are only
404 // installed after PCI enumeration completes, we must not trigger the S3 save
405 // earlier, hence we can't signal End-of-Dxe earlier.
407 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
409 // We need to connect all trusted consoles for TCG PP. Here we treat all
410 // consoles in OVMF to be trusted consoles.
411 PlatformInitializeConsole (gPlatformConsole
);
414 // Process TPM PPI request
416 Tcg2PhysicalPresenceLibProcessRequest (NULL
);
419 // Prevent further changes to LockBoxes or SMRAM.
420 // Any TPM 2 Physical Presence Interface opcode must be handled before.
423 Status
= gBS
->InstallProtocolInterface (
425 &gEfiDxeSmmReadyToLockProtocolGuid
,
426 EFI_NATIVE_INTERFACE
,
429 ASSERT_EFI_ERROR (Status
);
432 // Dispatch deferred images after EndOfDxe event and ReadyToLock
435 EfiBootManagerDispatchDeferredImages ();
438 // GPU passthrough only allows Console enablement after ROM image load
440 PlatformInitializeConsole (gPlatformConsole
);
442 PlatformRegisterOptionsAndKeys ();
445 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
446 // instances on Virtio PCI RNG devices.
448 VisitAllInstancesOfProtocol (
449 &gEfiPciIoProtocolGuid
,
458 IN EFI_HANDLE RootBridgeHandle
,
466 // Make the PCI bus driver connect the root bridge, non-recursively. This
467 // will produce a number of child handles with PciIo on them.
469 Status
= gBS
->ConnectController (
470 RootBridgeHandle
, // ControllerHandle
471 NULL
, // DriverImageHandle
472 NULL
, // RemainingDevicePath -- produce all
482 ConnectVirtioPciRng (
483 IN EFI_HANDLE Handle
,
488 EFI_PCI_IO_PROTOCOL
*PciIo
;
499 // Read and check VendorId.
501 Status
= PciIo
->Pci
.Read (
504 PCI_VENDOR_ID_OFFSET
,
508 if (EFI_ERROR (Status
)) {
512 if (VendorId
!= VIRTIO_VENDOR_ID
) {
517 // Read DeviceId and RevisionId.
519 Status
= PciIo
->Pci
.Read (
522 PCI_DEVICE_ID_OFFSET
,
526 if (EFI_ERROR (Status
)) {
530 Status
= PciIo
->Pci
.Read (
533 PCI_REVISION_ID_OFFSET
,
537 if (EFI_ERROR (Status
)) {
542 // From DeviceId and RevisionId, determine whether the device is a
543 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
544 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
545 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
546 // only be sanity-checked, and SubsystemId will decide.
548 if ((DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
) &&
549 (RevisionId
>= 0x01))
552 } else if ((DeviceId
>= 0x1000) && (DeviceId
<= 0x103F) && (RevisionId
== 0x00)) {
559 // Read and check SubsystemId as dictated by Virtio10.
561 Status
= PciIo
->Pci
.Read (
564 PCI_SUBSYSTEM_ID_OFFSET
,
568 if (EFI_ERROR (Status
)) {
572 if ((Virtio10
&& (SubsystemId
>= 0x40)) ||
573 (!Virtio10
&& (SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)))
575 Status
= gBS
->ConnectController (
576 Handle
, // ControllerHandle
577 NULL
, // DriverImageHandle -- connect all drivers
578 NULL
, // RemainingDevicePath -- produce all child handles
579 FALSE
// Recursive -- don't follow child handles
581 if (EFI_ERROR (Status
)) {
589 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
594 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
596 @param[in] DeviceHandle Handle of the LPC Bridge device.
598 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
599 ConOut, ConIn, and ErrOut.
601 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
605 PrepareLpcBridgeDevicePath (
606 IN EFI_HANDLE DeviceHandle
610 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
611 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
615 Status
= gBS
->HandleProtocol (
617 &gEfiDevicePathProtocolGuid
,
620 if (EFI_ERROR (Status
)) {
624 TempDevicePath
= DevicePath
;
629 DevicePath
= AppendDevicePathNode (
631 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
634 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
639 DevicePath
= TempDevicePath
;
640 gPnp16550ComPortDeviceNode
.UID
= 0;
642 DevicePath
= AppendDevicePathNode (
644 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
646 DevicePath
= AppendDevicePathNode (
648 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
650 DevicePath
= AppendDevicePathNode (
652 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
658 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
659 if (DevPathStr
!= NULL
) {
662 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
664 gPnp16550ComPortDeviceNode
.UID
+ 1,
667 FreePool (DevPathStr
);
670 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
671 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
672 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
674 // Don't register COM2 which can be used for DBG instead so keep it clean
681 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
682 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
687 EFI_HANDLE PciDeviceHandle
;
688 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
689 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
690 UINTN GopHandleCount
;
691 EFI_HANDLE
*GopHandleBuffer
;
693 if ((PciDevicePath
== NULL
) || (GopDevicePath
== NULL
)) {
694 return EFI_INVALID_PARAMETER
;
698 // Initialize the GopDevicePath to be PciDevicePath
700 *GopDevicePath
= PciDevicePath
;
701 TempPciDevicePath
= PciDevicePath
;
703 Status
= gBS
->LocateDevicePath (
704 &gEfiDevicePathProtocolGuid
,
708 if (EFI_ERROR (Status
)) {
713 // Try to connect this handle, so that GOP driver could start on this
714 // device and create child handles with GraphicsOutput Protocol installed
715 // on them, then we get device paths of these child handles and select
716 // them as possible console device.
718 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
720 Status
= gBS
->LocateHandleBuffer (
722 &gEfiGraphicsOutputProtocolGuid
,
727 if (!EFI_ERROR (Status
)) {
729 // Add all the child handles as possible Console Device
731 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
732 Status
= gBS
->HandleProtocol (
733 GopHandleBuffer
[Index
],
734 &gEfiDevicePathProtocolGuid
,
735 (VOID
*)&TempDevicePath
737 if (EFI_ERROR (Status
)) {
744 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
748 // In current implementation, we only enable one of the child handles
749 // as console device, i.e. sotre one of the child handle's device
750 // path to variable "ConOut"
751 // In future, we could select all child handles to be console device
754 *GopDevicePath
= TempDevicePath
;
757 // Delete the PCI device's path that added by
758 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
760 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
761 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
765 gBS
->FreePool (GopHandleBuffer
);
772 Add PCI display to ConOut.
774 @param[in] DeviceHandle Handle of the PCI display device.
776 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
778 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
782 PreparePciDisplayDevicePath (
783 IN EFI_HANDLE DeviceHandle
787 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
788 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
791 GopDevicePath
= NULL
;
792 Status
= gBS
->HandleProtocol (
794 &gEfiDevicePathProtocolGuid
,
797 if (EFI_ERROR (Status
)) {
801 GetGopDevicePath (DevicePath
, &GopDevicePath
);
802 DevicePath
= GopDevicePath
;
804 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
810 Add PCI Serial to ConOut, ConIn, ErrOut.
812 @param[in] DeviceHandle Handle of the PCI serial device.
814 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
817 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
821 PreparePciSerialDevicePath (
822 IN EFI_HANDLE DeviceHandle
826 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
829 Status
= gBS
->HandleProtocol (
831 &gEfiDevicePathProtocolGuid
,
834 if (EFI_ERROR (Status
)) {
838 DevicePath
= AppendDevicePathNode (
840 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
842 DevicePath
= AppendDevicePathNode (
844 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
847 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
848 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
849 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
855 VisitAllInstancesOfProtocol (
857 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
863 EFI_HANDLE
*HandleBuffer
;
868 // Start to check all the PciIo to find all possible device
872 Status
= gBS
->LocateHandleBuffer (
879 if (EFI_ERROR (Status
)) {
883 for (Index
= 0; Index
< HandleCount
; Index
++) {
884 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
885 if (EFI_ERROR (Status
)) {
889 Status
= (*CallBackFunction
)(
896 gBS
->FreePool (HandleBuffer
);
903 VisitingAPciInstance (
904 IN EFI_HANDLE Handle
,
910 EFI_PCI_IO_PROTOCOL
*PciIo
;
913 PciIo
= (EFI_PCI_IO_PROTOCOL
*)Instance
;
916 // Check for all PCI device
918 Status
= PciIo
->Pci
.Read (
922 sizeof (Pci
) / sizeof (UINT32
),
925 if (EFI_ERROR (Status
)) {
929 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
)Context
)(
937 VisitAllPciInstances (
938 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
941 return VisitAllInstancesOfProtocol (
942 &gEfiPciIoProtocolGuid
,
943 VisitingAPciInstance
,
944 (VOID
*)(UINTN
)CallBackFunction
949 Do platform specific PCI Device check and add them to
950 ConOut, ConIn, ErrOut.
952 @param[in] Handle - Handle of PCI device instance
953 @param[in] PciIo - PCI IO protocol instance
954 @param[in] Pci - PCI Header register block
956 @retval EFI_SUCCESS - PCI Device check and Console variable update
958 @retval EFI_STATUS - PCI Device check or Console variable update fail.
963 DetectAndPreparePlatformPciDevicePath (
964 IN EFI_HANDLE Handle
,
965 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
971 Status
= PciIo
->Attributes (
973 EfiPciIoAttributeOperationEnable
,
974 EFI_PCI_DEVICE_ENABLE
,
977 ASSERT_EFI_ERROR (Status
);
980 // Here we decide whether it is LPC Bridge
982 if ((IS_PCI_LPC (Pci
)) ||
983 ((IS_PCI_ISA_PDECODE (Pci
)) &&
984 (Pci
->Hdr
.VendorId
== 0x8086) &&
985 (Pci
->Hdr
.DeviceId
== 0x7000)
990 // Add IsaKeyboard to ConIn,
991 // add IsaSerial to ConOut, ConIn, ErrOut
993 DEBUG ((DEBUG_INFO
, "Found LPC Bridge device\n"));
994 PrepareLpcBridgeDevicePath (Handle
);
999 // Here we decide which Serial device to enable in PCI bus
1001 if (IS_PCI_16550SERIAL (Pci
)) {
1003 // Add them to ConOut, ConIn, ErrOut.
1005 DEBUG ((DEBUG_INFO
, "Found PCI 16550 SERIAL device\n"));
1006 PreparePciSerialDevicePath (Handle
);
1011 // Here we decide which display device to enable in PCI bus
1013 if (IS_PCI_DISPLAY (Pci
)) {
1015 // Add them to ConOut.
1017 DEBUG ((DEBUG_INFO
, "Found PCI display device\n"));
1018 PreparePciDisplayDevicePath (Handle
);
1026 Connect the predefined platform default console device.
1028 Always try to find and enable PCI display devices.
1030 @param[in] PlatformConsole Predefined platform default console device array.
1033 PlatformInitializeConsole (
1034 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
1040 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1043 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
1046 // Have chance to connect the platform default console,
1047 // the platform default console is the minimum device group
1048 // the platform should support
1050 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1052 // Update the console variable with the connect type
1054 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1055 EfiBootManagerUpdateConsoleVariable (
1057 PlatformConsole
[Index
].DevicePath
,
1062 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1063 EfiBootManagerUpdateConsoleVariable (
1065 PlatformConsole
[Index
].DevicePath
,
1070 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1071 EfiBootManagerUpdateConsoleVariable (
1073 PlatformConsole
[Index
].DevicePath
,
1081 Configure PCI Interrupt Line register for applicable devices
1082 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1084 @param[in] Handle - Handle of PCI device instance
1085 @param[in] PciIo - PCI IO protocol instance
1086 @param[in] PciHdr - PCI Header register block
1088 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1094 IN EFI_HANDLE Handle
,
1095 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1096 IN PCI_TYPE00
*PciHdr
1099 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1100 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1105 UINT32 RootBusNumber
;
1107 Status
= EFI_SUCCESS
;
1109 if (PciHdr
->Device
.InterruptPin
!= 0) {
1110 DevPathNode
= DevicePathFromHandle (Handle
);
1111 ASSERT (DevPathNode
!= NULL
);
1112 DevPath
= DevPathNode
;
1115 if ((DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
) &&
1116 (DevicePathSubType (DevPathNode
) == ACPI_DP
) &&
1117 (((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID (0x0A03)))
1119 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1123 // Compute index into PciHostIrqs[] table by walking
1124 // the device path and adding up all device numbers
1126 Status
= EFI_NOT_FOUND
;
1128 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1129 while (!IsDevicePathEnd (DevPathNode
)) {
1130 if ((DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
) &&
1131 (DevicePathSubType (DevPathNode
) == HW_PCI_DP
))
1133 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1136 // Unlike SeaBIOS, which starts climbing from the leaf device
1137 // up toward the root, we traverse the device path starting at
1138 // the root moving toward the leaf node.
1139 // The slot number of the top-level parent bridge is needed for
1140 // Q35 cases with more than 24 slots on the root bus.
1142 if (Status
!= EFI_SUCCESS
) {
1143 Status
= EFI_SUCCESS
;
1144 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1148 DevPathNode
= NextDevicePathNode (DevPathNode
);
1151 if (EFI_ERROR (Status
)) {
1155 if ((RootBusNumber
== 0) && (RootSlot
== 0)) {
1158 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1165 // Final PciHostIrqs[] index calculation depends on the platform
1166 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1168 switch (mHostBridgeDevId
) {
1169 case 0x7432: // BHYVE (AMD hostbridge)
1170 case 0x1275: // BHYVE (Intel hostbridge)
1171 case INTEL_82441_DEVICE_ID
:
1174 case INTEL_Q35_MCH_DEVICE_ID
:
1176 // SeaBIOS contains the following comment:
1177 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1178 // with a different starting index - see q35-acpi-dsdt.dsl.
1180 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1182 if (RootSlot
> 24) {
1184 // in this case, subtract back out RootSlot from Idx
1185 // (SeaBIOS never adds it to begin with, but that would make our
1186 // device path traversal loop above too awkward)
1193 ASSERT (FALSE
); // should never get here
1196 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1197 IrqLine
= PciHostIrqs
[Idx
];
1199 DEBUG_CODE_BEGIN ();
1201 CHAR16
*DevPathString
;
1202 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1203 UINTN Segment
, Bus
, Device
, Function
;
1205 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1206 if (DevPathString
== NULL
) {
1207 DevPathString
= Fallback
;
1210 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1211 ASSERT_EFI_ERROR (Status
);
1215 "%a: [%02x:%02x.%x] %s -> 0x%02x\n",
1224 if (DevPathString
!= Fallback
) {
1225 FreePool (DevPathString
);
1231 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1233 Status
= PciIo
->Pci
.Write (
1236 PCI_INT_LINE_OFFSET
,
1246 PciAcpiInitialization (
1252 // Query Host Bridge DID to determine platform type
1254 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1255 switch (mHostBridgeDevId
) {
1256 case 0x7432: // BHYVE (AMD hostbridge)
1257 case 0x1275: // BHYVE (Intel hostbridge)
1258 case INTEL_82441_DEVICE_ID
:
1259 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1261 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1263 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1264 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1265 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1266 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1268 case INTEL_Q35_MCH_DEVICE_ID
:
1269 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1271 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1273 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1274 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1275 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1276 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1277 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1278 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1279 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1280 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1285 "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1294 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1296 VisitAllPciInstances (SetPciIntLine
);
1299 // Set ACPI SCI_EN bit in PMCNTRL
1301 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1306 ConnectRecursivelyIfPciMassStorage (
1307 IN EFI_HANDLE Handle
,
1308 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1309 IN PCI_TYPE00
*PciHeader
1313 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1317 // Recognize PCI Mass Storage, and Xen PCI devices
1319 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
)) {
1321 Status
= gBS
->HandleProtocol (
1323 &gEfiDevicePathProtocolGuid
,
1326 if (EFI_ERROR (Status
)) {
1331 // Print Device Path
1333 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1334 if (DevPathStr
!= NULL
) {
1337 "Found %s device: %s\n",
1338 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1344 FreePool (DevPathStr
);
1347 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1348 if (EFI_ERROR (Status
)) {
1357 This notification function is invoked when the
1358 EMU Variable FVB has been changed.
1360 @param Event The event that occurred
1361 @param Context For EFI compatibility. Not used.
1366 EmuVariablesUpdatedCallback (
1371 DEBUG ((DEBUG_INFO
, "EmuVariablesUpdatedCallback\n"));
1372 UpdateNvVarsOnFileSystem ();
1377 VisitingFileSystemInstance (
1378 IN EFI_HANDLE Handle
,
1384 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1385 RETURN_STATUS PcdStatus
;
1387 if (ConnectedToFileSystem
) {
1388 return EFI_ALREADY_STARTED
;
1391 Status
= ConnectNvVarsToFileSystem (Handle
);
1392 if (EFI_ERROR (Status
)) {
1396 ConnectedToFileSystem
= TRUE
;
1398 EfiCreateProtocolNotifyEvent (
1399 &gEfiDevicePathProtocolGuid
,
1401 EmuVariablesUpdatedCallback
,
1403 &mEmuVariableEventReg
1405 PcdStatus
= PcdSet64S (
1406 PcdEmuVariableEvent
,
1407 (UINT64
)(UINTN
)mEmuVariableEvent
1409 ASSERT_RETURN_ERROR (PcdStatus
);
1415 PlatformBdsRestoreNvVarsFromHardDisk (
1418 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1419 VisitAllInstancesOfProtocol (
1420 &gEfiSimpleFileSystemProtocolGuid
,
1421 VisitingFileSystemInstance
,
1427 Connect with predefined platform connect sequence.
1429 The OEM/IBV can customize with their own connect sequence.
1432 PlatformBdsConnectSequence (
1438 DEBUG ((DEBUG_INFO
, "PlatformBdsConnectSequence\n"));
1443 // Here we can get the customized platform connect sequence
1444 // Notes: we can connect with new variable which record the
1445 // last time boots connect device path sequence
1447 while (gPlatformConnectSequence
[Index
] != NULL
) {
1449 // Build the platform boot option
1451 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1456 // Just use the simple policy to connect all devices
1458 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1459 EfiBootManagerConnectAll ();
1463 Save the S3 boot script.
1465 Note that DxeSmmReadyToLock must be signaled after this function returns;
1466 otherwise the script wouldn't be saved actually.
1468 #if defined (__GNUC__)
1469 __attribute__ ((unused
))
1478 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1479 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1481 Status
= gBS
->LocateProtocol (
1482 &gEfiS3SaveStateProtocolGuid
,
1484 (VOID
**)&BootScript
1486 ASSERT_EFI_ERROR (Status
);
1489 // Despite the opcode documentation in the PI spec, the protocol
1490 // implementation embeds a deep copy of the info in the boot script, rather
1491 // than storing just a pointer to runtime or NVS storage.
1493 Status
= BootScript
->Write (
1495 EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1496 (UINT32
)sizeof Info
,
1497 (EFI_PHYSICAL_ADDRESS
)(UINTN
)&Info
1499 ASSERT_EFI_ERROR (Status
);
1503 Do the platform specific action after the console is ready
1505 Possible things that can be done in PlatformBootManagerAfterConsole:
1507 > Console post action:
1508 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1509 > Signal console ready platform customized event
1510 > Run diagnostics like memory testing
1511 > Connect certain devices
1512 > Dispatch aditional option roms
1513 > Special boot: e.g.: USB boot, enter UI
1517 PlatformBootManagerAfterConsole (
1521 EFI_BOOT_MODE BootMode
;
1523 DEBUG ((DEBUG_INFO
, "PlatformBootManagerAfterConsole\n"));
1525 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1528 "PlatformBdsPolicyBehavior: not restoring NvVars "
1529 "from disk since flash variables appear to be supported.\n"
1533 // Try to restore variables from the hard disk early so
1534 // they can be used for the other BDS connect operations.
1537 /* XXX Calling this causes Keyboard to be removed from ConIn which
1538 results in unresponsive guest boot loaders in the GUI. Restore it
1539 when we figure out what is needed to get NvVars storage done
1542 /*PlatformBdsRestoreNvVarsFromHardDisk ();*/
1546 // Get current Boot Mode
1548 BootMode
= GetBootModeHob ();
1549 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1552 // Go the different platform policy with different boot mode
1553 // Notes: this part code can be change with the table policy
1555 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1560 BootLogoEnableLogo ();
1563 // Set PCI Interrupt Line registers and ACPI SCI_EN
1565 PciAcpiInitialization ();
1568 // Perform some platform specific connect sequence
1570 PlatformBdsConnectSequence ();
1572 EfiBootManagerRefreshAllBootOption ();
1575 // Register UEFI Shell
1577 PlatformRegisterFvBootOption (
1578 &gUefiShellFileGuid
,
1579 L
"EFI Internal Shell",
1583 RemoveStaleFvFileOptions ();
1585 PlatformBmPrintScRegisterHandler ();
1589 This notification function is invoked when an instance of the
1590 EFI_DEVICE_PATH_PROTOCOL is produced.
1592 @param Event The event that occurred
1593 @param Context For EFI compatibility. Not used.
1606 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1607 ATAPI_DEVICE_PATH
*Atapi
;
1610 // Examine all new handles
1614 // Get the next handle
1616 BufferSize
= sizeof (Handle
);
1617 Status
= gBS
->LocateHandle (
1620 mEfiDevPathNotifyReg
,
1626 // If not found, we're done
1628 if (EFI_NOT_FOUND
== Status
) {
1632 if (EFI_ERROR (Status
)) {
1637 // Get the DevicePath protocol on that handle
1639 Status
= gBS
->HandleProtocol (
1641 &gEfiDevicePathProtocolGuid
,
1642 (VOID
**)&DevPathNode
1644 ASSERT_EFI_ERROR (Status
);
1646 while (!IsDevicePathEnd (DevPathNode
)) {
1648 // Find the handler to dump this device path node
1651 (DevicePathType (DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1652 (DevicePathSubType (DevPathNode
) == MSG_ATAPI_DP
)
1655 Atapi
= (ATAPI_DEVICE_PATH
*)DevPathNode
;
1661 (Atapi
->PrimarySecondary
== 1) ? 0x42 : 0x40
1668 // Next device path node
1670 DevPathNode
= NextDevicePathNode (DevPathNode
);
1678 InstallDevicePathCallback (
1682 DEBUG ((DEBUG_INFO
, "Registered NotifyDevPath Event\n"));
1683 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1684 &gEfiDevicePathProtocolGuid
,
1688 &mEfiDevPathNotifyReg
1693 This function is called each second during the boot manager waits the
1696 @param TimeoutRemain The remaining timeout.
1700 PlatformBootManagerWaitCallback (
1701 UINT16 TimeoutRemain
1704 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1705 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1708 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1710 Black
.Raw
= 0x00000000;
1711 White
.Raw
= 0x00FFFFFF;
1713 BootLogoUpdateProgress (
1716 L
"Start boot option",
1718 (Timeout
- TimeoutRemain
) * 100 / Timeout
,
1724 The function is called when no boot option could be launched,
1725 including platform recovery options and options pointing to applications
1726 built into firmware volumes.
1728 If this function returns, BDS attempts to enter an infinite loop.
1732 PlatformBootManagerUnableToBoot (
1738 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu
;
1742 // BootManagerMenu doesn't contain the correct information when return status
1743 // is EFI_NOT_FOUND.
1745 Status
= EfiBootManagerGetBootManagerMenu (&BootManagerMenu
);
1746 if (EFI_ERROR (Status
)) {
1751 // Normally BdsDxe does not print anything to the system console, but this is
1752 // a last resort -- the end-user will likely not see any DEBUG messages
1753 // logged in this situation.
1755 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1756 // here to see if it makes sense to request and wait for a keypress.
1758 if (gST
->ConIn
!= NULL
) {
1760 "%a: No bootable option or device was found.\n"
1761 "%a: Press any key to enter the Boot Manager Menu.\n",
1765 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &Index
);
1766 ASSERT_EFI_ERROR (Status
);
1767 ASSERT (Index
== 0);
1770 // Drain any queued keys.
1772 while (!EFI_ERROR (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
))) {
1774 // just throw away Key
1780 EfiBootManagerBoot (&BootManagerMenu
);