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 ();
437 PlatformRegisterOptionsAndKeys ();
440 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
441 // instances on Virtio PCI RNG devices.
443 VisitAllInstancesOfProtocol (
444 &gEfiPciIoProtocolGuid
,
453 IN EFI_HANDLE RootBridgeHandle
,
461 // Make the PCI bus driver connect the root bridge, non-recursively. This
462 // will produce a number of child handles with PciIo on them.
464 Status
= gBS
->ConnectController (
465 RootBridgeHandle
, // ControllerHandle
466 NULL
, // DriverImageHandle
467 NULL
, // RemainingDevicePath -- produce all
477 ConnectVirtioPciRng (
478 IN EFI_HANDLE Handle
,
483 EFI_PCI_IO_PROTOCOL
*PciIo
;
494 // Read and check VendorId.
496 Status
= PciIo
->Pci
.Read (
499 PCI_VENDOR_ID_OFFSET
,
503 if (EFI_ERROR (Status
)) {
507 if (VendorId
!= VIRTIO_VENDOR_ID
) {
512 // Read DeviceId and RevisionId.
514 Status
= PciIo
->Pci
.Read (
517 PCI_DEVICE_ID_OFFSET
,
521 if (EFI_ERROR (Status
)) {
525 Status
= PciIo
->Pci
.Read (
528 PCI_REVISION_ID_OFFSET
,
532 if (EFI_ERROR (Status
)) {
537 // From DeviceId and RevisionId, determine whether the device is a
538 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
539 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
540 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
541 // only be sanity-checked, and SubsystemId will decide.
543 if ((DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
) &&
544 (RevisionId
>= 0x01))
547 } else if ((DeviceId
>= 0x1000) && (DeviceId
<= 0x103F) && (RevisionId
== 0x00)) {
554 // Read and check SubsystemId as dictated by Virtio10.
556 Status
= PciIo
->Pci
.Read (
559 PCI_SUBSYSTEM_ID_OFFSET
,
563 if (EFI_ERROR (Status
)) {
567 if ((Virtio10
&& (SubsystemId
>= 0x40)) ||
568 (!Virtio10
&& (SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)))
570 Status
= gBS
->ConnectController (
571 Handle
, // ControllerHandle
572 NULL
, // DriverImageHandle -- connect all drivers
573 NULL
, // RemainingDevicePath -- produce all child handles
574 FALSE
// Recursive -- don't follow child handles
576 if (EFI_ERROR (Status
)) {
584 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
589 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
591 @param[in] DeviceHandle Handle of the LPC Bridge device.
593 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
594 ConOut, ConIn, and ErrOut.
596 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
600 PrepareLpcBridgeDevicePath (
601 IN EFI_HANDLE DeviceHandle
605 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
606 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
610 Status
= gBS
->HandleProtocol (
612 &gEfiDevicePathProtocolGuid
,
615 if (EFI_ERROR (Status
)) {
619 TempDevicePath
= DevicePath
;
624 DevicePath
= AppendDevicePathNode (
626 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
629 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
634 DevicePath
= TempDevicePath
;
635 gPnp16550ComPortDeviceNode
.UID
= 0;
637 DevicePath
= AppendDevicePathNode (
639 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
641 DevicePath
= AppendDevicePathNode (
643 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
645 DevicePath
= AppendDevicePathNode (
647 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
653 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
654 if (DevPathStr
!= NULL
) {
657 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
659 gPnp16550ComPortDeviceNode
.UID
+ 1,
662 FreePool (DevPathStr
);
665 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
666 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
667 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
669 // Don't register COM2 which can be used for DBG instead so keep it clean
676 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
677 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
682 EFI_HANDLE PciDeviceHandle
;
683 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
684 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
685 UINTN GopHandleCount
;
686 EFI_HANDLE
*GopHandleBuffer
;
688 if ((PciDevicePath
== NULL
) || (GopDevicePath
== NULL
)) {
689 return EFI_INVALID_PARAMETER
;
693 // Initialize the GopDevicePath to be PciDevicePath
695 *GopDevicePath
= PciDevicePath
;
696 TempPciDevicePath
= PciDevicePath
;
698 Status
= gBS
->LocateDevicePath (
699 &gEfiDevicePathProtocolGuid
,
703 if (EFI_ERROR (Status
)) {
708 // Try to connect this handle, so that GOP driver could start on this
709 // device and create child handles with GraphicsOutput Protocol installed
710 // on them, then we get device paths of these child handles and select
711 // them as possible console device.
713 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
715 Status
= gBS
->LocateHandleBuffer (
717 &gEfiGraphicsOutputProtocolGuid
,
722 if (!EFI_ERROR (Status
)) {
724 // Add all the child handles as possible Console Device
726 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
727 Status
= gBS
->HandleProtocol (
728 GopHandleBuffer
[Index
],
729 &gEfiDevicePathProtocolGuid
,
730 (VOID
*)&TempDevicePath
732 if (EFI_ERROR (Status
)) {
739 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
743 // In current implementation, we only enable one of the child handles
744 // as console device, i.e. sotre one of the child handle's device
745 // path to variable "ConOut"
746 // In future, we could select all child handles to be console device
749 *GopDevicePath
= TempDevicePath
;
752 // Delete the PCI device's path that added by
753 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
755 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
756 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
760 gBS
->FreePool (GopHandleBuffer
);
767 Add PCI display to ConOut.
769 @param[in] DeviceHandle Handle of the PCI display device.
771 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
773 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
777 PreparePciDisplayDevicePath (
778 IN EFI_HANDLE DeviceHandle
782 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
783 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
786 GopDevicePath
= NULL
;
787 Status
= gBS
->HandleProtocol (
789 &gEfiDevicePathProtocolGuid
,
792 if (EFI_ERROR (Status
)) {
796 GetGopDevicePath (DevicePath
, &GopDevicePath
);
797 DevicePath
= GopDevicePath
;
799 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
805 Add PCI Serial to ConOut, ConIn, ErrOut.
807 @param[in] DeviceHandle Handle of the PCI serial device.
809 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
812 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
816 PreparePciSerialDevicePath (
817 IN EFI_HANDLE DeviceHandle
821 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
824 Status
= gBS
->HandleProtocol (
826 &gEfiDevicePathProtocolGuid
,
829 if (EFI_ERROR (Status
)) {
833 DevicePath
= AppendDevicePathNode (
835 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
837 DevicePath
= AppendDevicePathNode (
839 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
842 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
843 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
844 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
850 VisitAllInstancesOfProtocol (
852 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
858 EFI_HANDLE
*HandleBuffer
;
863 // Start to check all the PciIo to find all possible device
867 Status
= gBS
->LocateHandleBuffer (
874 if (EFI_ERROR (Status
)) {
878 for (Index
= 0; Index
< HandleCount
; Index
++) {
879 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
880 if (EFI_ERROR (Status
)) {
884 Status
= (*CallBackFunction
)(
891 gBS
->FreePool (HandleBuffer
);
898 VisitingAPciInstance (
899 IN EFI_HANDLE Handle
,
905 EFI_PCI_IO_PROTOCOL
*PciIo
;
908 PciIo
= (EFI_PCI_IO_PROTOCOL
*)Instance
;
911 // Check for all PCI device
913 Status
= PciIo
->Pci
.Read (
917 sizeof (Pci
) / sizeof (UINT32
),
920 if (EFI_ERROR (Status
)) {
924 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
)Context
)(
932 VisitAllPciInstances (
933 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
936 return VisitAllInstancesOfProtocol (
937 &gEfiPciIoProtocolGuid
,
938 VisitingAPciInstance
,
939 (VOID
*)(UINTN
)CallBackFunction
944 Do platform specific PCI Device check and add them to
945 ConOut, ConIn, ErrOut.
947 @param[in] Handle - Handle of PCI device instance
948 @param[in] PciIo - PCI IO protocol instance
949 @param[in] Pci - PCI Header register block
951 @retval EFI_SUCCESS - PCI Device check and Console variable update
953 @retval EFI_STATUS - PCI Device check or Console variable update fail.
958 DetectAndPreparePlatformPciDevicePath (
959 IN EFI_HANDLE Handle
,
960 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
966 Status
= PciIo
->Attributes (
968 EfiPciIoAttributeOperationEnable
,
969 EFI_PCI_DEVICE_ENABLE
,
972 ASSERT_EFI_ERROR (Status
);
975 // Here we decide whether it is LPC Bridge
977 if ((IS_PCI_LPC (Pci
)) ||
978 ((IS_PCI_ISA_PDECODE (Pci
)) &&
979 (Pci
->Hdr
.VendorId
== 0x8086) &&
980 (Pci
->Hdr
.DeviceId
== 0x7000)
985 // Add IsaKeyboard to ConIn,
986 // add IsaSerial to ConOut, ConIn, ErrOut
988 DEBUG ((DEBUG_INFO
, "Found LPC Bridge device\n"));
989 PrepareLpcBridgeDevicePath (Handle
);
994 // Here we decide which Serial device to enable in PCI bus
996 if (IS_PCI_16550SERIAL (Pci
)) {
998 // Add them to ConOut, ConIn, ErrOut.
1000 DEBUG ((DEBUG_INFO
, "Found PCI 16550 SERIAL device\n"));
1001 PreparePciSerialDevicePath (Handle
);
1006 // Here we decide which display device to enable in PCI bus
1008 if (IS_PCI_DISPLAY (Pci
)) {
1010 // Add them to ConOut.
1012 DEBUG ((DEBUG_INFO
, "Found PCI display device\n"));
1013 PreparePciDisplayDevicePath (Handle
);
1021 Connect the predefined platform default console device.
1023 Always try to find and enable PCI display devices.
1025 @param[in] PlatformConsole Predefined platform default console device array.
1028 PlatformInitializeConsole (
1029 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
1035 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1038 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
1041 // Have chance to connect the platform default console,
1042 // the platform default console is the minimum device group
1043 // the platform should support
1045 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1047 // Update the console variable with the connect type
1049 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1050 EfiBootManagerUpdateConsoleVariable (
1052 PlatformConsole
[Index
].DevicePath
,
1057 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1058 EfiBootManagerUpdateConsoleVariable (
1060 PlatformConsole
[Index
].DevicePath
,
1065 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1066 EfiBootManagerUpdateConsoleVariable (
1068 PlatformConsole
[Index
].DevicePath
,
1076 Configure PCI Interrupt Line register for applicable devices
1077 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1079 @param[in] Handle - Handle of PCI device instance
1080 @param[in] PciIo - PCI IO protocol instance
1081 @param[in] PciHdr - PCI Header register block
1083 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1089 IN EFI_HANDLE Handle
,
1090 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1091 IN PCI_TYPE00
*PciHdr
1094 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1095 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1100 UINT32 RootBusNumber
;
1102 Status
= EFI_SUCCESS
;
1104 if (PciHdr
->Device
.InterruptPin
!= 0) {
1105 DevPathNode
= DevicePathFromHandle (Handle
);
1106 ASSERT (DevPathNode
!= NULL
);
1107 DevPath
= DevPathNode
;
1110 if ((DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
) &&
1111 (DevicePathSubType (DevPathNode
) == ACPI_DP
) &&
1112 (((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID (0x0A03)))
1114 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1118 // Compute index into PciHostIrqs[] table by walking
1119 // the device path and adding up all device numbers
1121 Status
= EFI_NOT_FOUND
;
1123 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1124 while (!IsDevicePathEnd (DevPathNode
)) {
1125 if ((DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
) &&
1126 (DevicePathSubType (DevPathNode
) == HW_PCI_DP
))
1128 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1131 // Unlike SeaBIOS, which starts climbing from the leaf device
1132 // up toward the root, we traverse the device path starting at
1133 // the root moving toward the leaf node.
1134 // The slot number of the top-level parent bridge is needed for
1135 // Q35 cases with more than 24 slots on the root bus.
1137 if (Status
!= EFI_SUCCESS
) {
1138 Status
= EFI_SUCCESS
;
1139 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1143 DevPathNode
= NextDevicePathNode (DevPathNode
);
1146 if (EFI_ERROR (Status
)) {
1150 if ((RootBusNumber
== 0) && (RootSlot
== 0)) {
1153 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1160 // Final PciHostIrqs[] index calculation depends on the platform
1161 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1163 switch (mHostBridgeDevId
) {
1164 case 0x7432: // BHYVE (AMD hostbridge)
1165 case 0x1275: // BHYVE (Intel hostbridge)
1166 case INTEL_82441_DEVICE_ID
:
1169 case INTEL_Q35_MCH_DEVICE_ID
:
1171 // SeaBIOS contains the following comment:
1172 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1173 // with a different starting index - see q35-acpi-dsdt.dsl.
1175 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1177 if (RootSlot
> 24) {
1179 // in this case, subtract back out RootSlot from Idx
1180 // (SeaBIOS never adds it to begin with, but that would make our
1181 // device path traversal loop above too awkward)
1188 ASSERT (FALSE
); // should never get here
1191 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1192 IrqLine
= PciHostIrqs
[Idx
];
1194 DEBUG_CODE_BEGIN ();
1196 CHAR16
*DevPathString
;
1197 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1198 UINTN Segment
, Bus
, Device
, Function
;
1200 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1201 if (DevPathString
== NULL
) {
1202 DevPathString
= Fallback
;
1205 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1206 ASSERT_EFI_ERROR (Status
);
1210 "%a: [%02x:%02x.%x] %s -> 0x%02x\n",
1219 if (DevPathString
!= Fallback
) {
1220 FreePool (DevPathString
);
1226 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1228 Status
= PciIo
->Pci
.Write (
1231 PCI_INT_LINE_OFFSET
,
1241 PciAcpiInitialization (
1247 // Query Host Bridge DID to determine platform type
1249 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1250 switch (mHostBridgeDevId
) {
1251 case 0x7432: // BHYVE (AMD hostbridge)
1252 case 0x1275: // BHYVE (Intel hostbridge)
1253 case INTEL_82441_DEVICE_ID
:
1254 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1256 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1258 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1259 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1260 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1261 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1263 case INTEL_Q35_MCH_DEVICE_ID
:
1264 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1266 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1268 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1269 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1270 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1271 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1272 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1273 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1274 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1275 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1280 "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1289 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1291 VisitAllPciInstances (SetPciIntLine
);
1294 // Set ACPI SCI_EN bit in PMCNTRL
1296 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1301 ConnectRecursivelyIfPciMassStorage (
1302 IN EFI_HANDLE Handle
,
1303 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1304 IN PCI_TYPE00
*PciHeader
1308 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1312 // Recognize PCI Mass Storage, and Xen PCI devices
1314 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
)) {
1316 Status
= gBS
->HandleProtocol (
1318 &gEfiDevicePathProtocolGuid
,
1321 if (EFI_ERROR (Status
)) {
1326 // Print Device Path
1328 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1329 if (DevPathStr
!= NULL
) {
1332 "Found %s device: %s\n",
1333 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1339 FreePool (DevPathStr
);
1342 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1343 if (EFI_ERROR (Status
)) {
1352 This notification function is invoked when the
1353 EMU Variable FVB has been changed.
1355 @param Event The event that occurred
1356 @param Context For EFI compatibility. Not used.
1361 EmuVariablesUpdatedCallback (
1366 DEBUG ((DEBUG_INFO
, "EmuVariablesUpdatedCallback\n"));
1367 UpdateNvVarsOnFileSystem ();
1372 VisitingFileSystemInstance (
1373 IN EFI_HANDLE Handle
,
1379 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1380 RETURN_STATUS PcdStatus
;
1382 if (ConnectedToFileSystem
) {
1383 return EFI_ALREADY_STARTED
;
1386 Status
= ConnectNvVarsToFileSystem (Handle
);
1387 if (EFI_ERROR (Status
)) {
1391 ConnectedToFileSystem
= TRUE
;
1393 EfiCreateProtocolNotifyEvent (
1394 &gEfiDevicePathProtocolGuid
,
1396 EmuVariablesUpdatedCallback
,
1398 &mEmuVariableEventReg
1400 PcdStatus
= PcdSet64S (
1401 PcdEmuVariableEvent
,
1402 (UINT64
)(UINTN
)mEmuVariableEvent
1404 ASSERT_RETURN_ERROR (PcdStatus
);
1410 PlatformBdsRestoreNvVarsFromHardDisk (
1413 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1414 VisitAllInstancesOfProtocol (
1415 &gEfiSimpleFileSystemProtocolGuid
,
1416 VisitingFileSystemInstance
,
1422 Connect with predefined platform connect sequence.
1424 The OEM/IBV can customize with their own connect sequence.
1427 PlatformBdsConnectSequence (
1433 DEBUG ((DEBUG_INFO
, "PlatformBdsConnectSequence\n"));
1438 // Here we can get the customized platform connect sequence
1439 // Notes: we can connect with new variable which record the
1440 // last time boots connect device path sequence
1442 while (gPlatformConnectSequence
[Index
] != NULL
) {
1444 // Build the platform boot option
1446 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1451 // Just use the simple policy to connect all devices
1453 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1454 EfiBootManagerConnectAll ();
1458 Save the S3 boot script.
1460 Note that DxeSmmReadyToLock must be signaled after this function returns;
1461 otherwise the script wouldn't be saved actually.
1463 #if defined (__GNUC__)
1464 __attribute__ ((unused
))
1473 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1474 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1476 Status
= gBS
->LocateProtocol (
1477 &gEfiS3SaveStateProtocolGuid
,
1479 (VOID
**)&BootScript
1481 ASSERT_EFI_ERROR (Status
);
1484 // Despite the opcode documentation in the PI spec, the protocol
1485 // implementation embeds a deep copy of the info in the boot script, rather
1486 // than storing just a pointer to runtime or NVS storage.
1488 Status
= BootScript
->Write (
1490 EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1491 (UINT32
)sizeof Info
,
1492 (EFI_PHYSICAL_ADDRESS
)(UINTN
)&Info
1494 ASSERT_EFI_ERROR (Status
);
1498 Do the platform specific action after the console is ready
1500 Possible things that can be done in PlatformBootManagerAfterConsole:
1502 > Console post action:
1503 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1504 > Signal console ready platform customized event
1505 > Run diagnostics like memory testing
1506 > Connect certain devices
1507 > Dispatch aditional option roms
1508 > Special boot: e.g.: USB boot, enter UI
1512 PlatformBootManagerAfterConsole (
1516 EFI_BOOT_MODE BootMode
;
1518 DEBUG ((DEBUG_INFO
, "PlatformBootManagerAfterConsole\n"));
1520 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1523 "PlatformBdsPolicyBehavior: not restoring NvVars "
1524 "from disk since flash variables appear to be supported.\n"
1528 // Try to restore variables from the hard disk early so
1529 // they can be used for the other BDS connect operations.
1532 /* XXX Calling this causes Keyboard to be removed from ConIn which
1533 results in unresponsive guest boot loaders in the GUI. Restore it
1534 when we figure out what is needed to get NvVars storage done
1537 /*PlatformBdsRestoreNvVarsFromHardDisk ();*/
1541 // Get current Boot Mode
1543 BootMode
= GetBootModeHob ();
1544 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1547 // Go the different platform policy with different boot mode
1548 // Notes: this part code can be change with the table policy
1550 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1555 BootLogoEnableLogo ();
1558 // Set PCI Interrupt Line registers and ACPI SCI_EN
1560 PciAcpiInitialization ();
1563 // Perform some platform specific connect sequence
1565 PlatformBdsConnectSequence ();
1567 EfiBootManagerRefreshAllBootOption ();
1570 // Register UEFI Shell
1572 PlatformRegisterFvBootOption (
1573 &gUefiShellFileGuid
,
1574 L
"EFI Internal Shell",
1578 RemoveStaleFvFileOptions ();
1580 PlatformBmPrintScRegisterHandler ();
1584 This notification function is invoked when an instance of the
1585 EFI_DEVICE_PATH_PROTOCOL is produced.
1587 @param Event The event that occurred
1588 @param Context For EFI compatibility. Not used.
1601 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1602 ATAPI_DEVICE_PATH
*Atapi
;
1605 // Examine all new handles
1609 // Get the next handle
1611 BufferSize
= sizeof (Handle
);
1612 Status
= gBS
->LocateHandle (
1615 mEfiDevPathNotifyReg
,
1621 // If not found, we're done
1623 if (EFI_NOT_FOUND
== Status
) {
1627 if (EFI_ERROR (Status
)) {
1632 // Get the DevicePath protocol on that handle
1634 Status
= gBS
->HandleProtocol (
1636 &gEfiDevicePathProtocolGuid
,
1637 (VOID
**)&DevPathNode
1639 ASSERT_EFI_ERROR (Status
);
1641 while (!IsDevicePathEnd (DevPathNode
)) {
1643 // Find the handler to dump this device path node
1646 (DevicePathType (DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1647 (DevicePathSubType (DevPathNode
) == MSG_ATAPI_DP
)
1650 Atapi
= (ATAPI_DEVICE_PATH
*)DevPathNode
;
1656 (Atapi
->PrimarySecondary
== 1) ? 0x42 : 0x40
1663 // Next device path node
1665 DevPathNode
= NextDevicePathNode (DevPathNode
);
1673 InstallDevicePathCallback (
1677 DEBUG ((DEBUG_INFO
, "Registered NotifyDevPath Event\n"));
1678 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1679 &gEfiDevicePathProtocolGuid
,
1683 &mEfiDevPathNotifyReg
1688 This function is called each second during the boot manager waits the
1691 @param TimeoutRemain The remaining timeout.
1695 PlatformBootManagerWaitCallback (
1696 UINT16 TimeoutRemain
1699 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1700 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1703 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1705 Black
.Raw
= 0x00000000;
1706 White
.Raw
= 0x00FFFFFF;
1708 BootLogoUpdateProgress (
1711 L
"Start boot option",
1713 (Timeout
- TimeoutRemain
) * 100 / Timeout
,
1719 The function is called when no boot option could be launched,
1720 including platform recovery options and options pointing to applications
1721 built into firmware volumes.
1723 If this function returns, BDS attempts to enter an infinite loop.
1727 PlatformBootManagerUnableToBoot (
1733 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu
;
1737 // BootManagerMenu doesn't contain the correct information when return status
1738 // is EFI_NOT_FOUND.
1740 Status
= EfiBootManagerGetBootManagerMenu (&BootManagerMenu
);
1741 if (EFI_ERROR (Status
)) {
1746 // Normally BdsDxe does not print anything to the system console, but this is
1747 // a last resort -- the end-user will likely not see any DEBUG messages
1748 // logged in this situation.
1750 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1751 // here to see if it makes sense to request and wait for a keypress.
1753 if (gST
->ConIn
!= NULL
) {
1755 "%a: No bootable option or device was found.\n"
1756 "%a: Press any key to enter the Boot Manager Menu.\n",
1760 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &Index
);
1761 ASSERT_EFI_ERROR (Status
);
1762 ASSERT (Index
== 0);
1765 // Drain any queued keys.
1767 while (!EFI_ERROR (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
))) {
1769 // just throw away Key
1775 EfiBootManagerBoot (&BootManagerMenu
);