2 Platform BDS customizations.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "BdsPlatform.h"
10 #include <Guid/XenInfo.h>
11 #include <Guid/RootBridgesConnectedEventGroup.h>
12 #include <Protocol/FirmwareVolume2.h>
13 #include <Library/PlatformBmPrintScLib.h>
14 #include <Library/Tcg2PhysicalPresenceLib.h>
21 VOID
*mEfiDevPathNotifyReg
;
22 EFI_EVENT mEfiDevPathEvent
;
23 VOID
*mEmuVariableEventReg
;
24 EFI_EVENT mEmuVariableEvent
;
25 UINT16 mHostBridgeDevId
;
28 // Table of host IRQs matching PCI IRQs A-D
29 // (for configuring PCI Interrupt Line register)
31 CONST UINT8 PciHostIrqs
[] = {
32 0x0a, 0x0a, 0x0b, 0x0b
41 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
48 @param[in] Handle - Handle of PCI device instance
49 @param[in] PciIo - PCI IO protocol instance
50 @param[in] Pci - PCI Header register block
54 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
56 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 (
128 &BootOptionCount
, LoadOptionTypeBoot
131 OptionIndex
= EfiBootManagerFindLoadOption (
132 &NewOption
, BootOptions
, BootOptionCount
135 if (OptionIndex
== -1) {
136 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
137 ASSERT_EFI_ERROR (Status
);
139 EfiBootManagerFreeLoadOption (&NewOption
);
140 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
144 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
145 whose device paths do not resolve exactly to an FvFile in the system.
147 This removes any boot options that point to binaries built into the firmware
148 and have become stale due to any of the following:
149 - DXEFV's base address or size changed (historical),
150 - DXEFV's FvNameGuid changed,
151 - the FILE_GUID of the pointed-to binary changed,
152 - the referenced binary is no longer built into the firmware.
154 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
155 avoids exact duplicates.
158 RemoveStaleFvFileOptions (
162 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
163 UINTN BootOptionCount
;
166 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
,
169 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
170 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
175 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
176 // then keep the boot option.
178 Node1
= BootOptions
[Index
].FilePath
;
179 if (!(DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
&&
180 DevicePathSubType (Node1
) == HW_MEMMAP_DP
) &&
181 !(DevicePathType (Node1
) == MEDIA_DEVICE_PATH
&&
182 DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)) {
187 // If the second device path node is not FvFile(...), then keep the boot
190 Node2
= NextDevicePathNode (Node1
);
191 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
192 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
197 // Locate the Firmware Volume2 protocol instance that is denoted by the
198 // boot option. If this lookup fails (i.e., the boot option references a
199 // firmware volume that doesn't exist), then we'll proceed to delete the
203 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
,
204 &SearchNode
, &FvHandle
);
206 if (!EFI_ERROR (Status
)) {
208 // The firmware volume was found; now let's see if it contains the FvFile
209 // identified by GUID.
211 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
212 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
214 EFI_FV_FILETYPE FoundType
;
215 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
216 UINT32 AuthenticationStatus
;
218 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
,
219 (VOID
**)&FvProtocol
);
220 ASSERT_EFI_ERROR (Status
);
222 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
224 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
227 Status
= FvProtocol
->ReadFile (
229 &FvFileNode
->FvFileName
, // NameGuid
234 &AuthenticationStatus
236 if (!EFI_ERROR (Status
)) {
238 // The FvFile was found. Keep the boot option.
245 // Delete the boot option.
247 Status
= EfiBootManagerDeleteLoadOptionVariable (
248 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
250 CHAR16
*DevicePathString
;
252 DevicePathString
= ConvertDevicePathToText(BootOptions
[Index
].FilePath
,
255 EFI_ERROR (Status
) ? EFI_D_WARN
: EFI_D_VERBOSE
,
256 "%a: removing stale Boot#%04x %s: %r\n",
258 (UINT32
)BootOptions
[Index
].OptionNumber
,
259 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
262 if (DevicePathString
!= NULL
) {
263 FreePool (DevicePathString
);
268 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
272 PlatformRegisterOptionsAndKeys (
280 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
283 // Register ENTER as CONTINUE key
285 Enter
.ScanCode
= SCAN_NULL
;
286 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
287 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
288 ASSERT_EFI_ERROR (Status
);
291 // Map F2 to Boot Manager Menu
293 F2
.ScanCode
= SCAN_F2
;
294 F2
.UnicodeChar
= CHAR_NULL
;
295 Esc
.ScanCode
= SCAN_ESC
;
296 Esc
.UnicodeChar
= CHAR_NULL
;
297 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
298 ASSERT_EFI_ERROR (Status
);
299 Status
= EfiBootManagerAddKeyOptionVariable (
300 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
302 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
303 Status
= EfiBootManagerAddKeyOptionVariable (
304 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
306 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
312 IN EFI_HANDLE RootBridgeHandle
,
320 ConnectVirtioPciRng (
321 IN EFI_HANDLE Handle
,
333 // BDS Platform Functions
336 Do the platform init, can be customized by OEM/IBV
338 Possible things that can be done in PlatformBootManagerBeforeConsole:
340 > Update console variable: 1. include hot-plug devices;
341 > 2. Clear ConIn and add SOL for AMT
342 > Register new Driver#### or Boot####
343 > Register new Key####: e.g.: F12
344 > Signal ReadyToLock event
345 > Authentication action: 1. connect Auth devices;
346 > 2. Identify auto logon user.
350 PlatformBootManagerBeforeConsole (
356 RETURN_STATUS PcdStatus
;
358 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
359 InstallDevicePathCallback ();
361 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
362 ConnectRootBridge
, NULL
);
365 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
367 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
370 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
371 // the preparation of S3 system information. That logic has a hard dependency
372 // on the presence of the FACS ACPI table. Since our ACPI tables are only
373 // installed after PCI enumeration completes, we must not trigger the S3 save
374 // earlier, hence we can't signal End-of-Dxe earlier.
376 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
378 if (QemuFwCfgS3Enabled ()) {
380 // Save the boot script too. Note that this will require us to emit the
381 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
387 // Prevent further changes to LockBoxes or SMRAM.
390 Status
= gBS
->InstallProtocolInterface (&Handle
,
391 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
393 ASSERT_EFI_ERROR (Status
);
396 // Dispatch deferred images after EndOfDxe event and ReadyToLock
399 EfiBootManagerDispatchDeferredImages ();
401 PlatformInitializeConsole (gPlatformConsole
);
402 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
,
403 GetFrontPageTimeoutFromQemu ());
404 ASSERT_RETURN_ERROR (PcdStatus
);
406 PlatformRegisterOptionsAndKeys ();
409 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
410 // instances on Virtio PCI RNG devices.
412 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
420 IN EFI_HANDLE RootBridgeHandle
,
428 // Make the PCI bus driver connect the root bridge, non-recursively. This
429 // will produce a number of child handles with PciIo on them.
431 Status
= gBS
->ConnectController (
432 RootBridgeHandle
, // ControllerHandle
433 NULL
, // DriverImageHandle
434 NULL
, // RemainingDevicePath -- produce all
445 ConnectVirtioPciRng (
446 IN EFI_HANDLE Handle
,
451 EFI_PCI_IO_PROTOCOL
*PciIo
;
462 // Read and check VendorId.
464 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
466 if (EFI_ERROR (Status
)) {
469 if (VendorId
!= VIRTIO_VENDOR_ID
) {
474 // Read DeviceId and RevisionId.
476 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
478 if (EFI_ERROR (Status
)) {
481 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
483 if (EFI_ERROR (Status
)) {
488 // From DeviceId and RevisionId, determine whether the device is a
489 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
490 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
491 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
492 // only be sanity-checked, and SubsystemId will decide.
494 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
495 RevisionId
>= 0x01) {
497 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
504 // Read and check SubsystemId as dictated by Virtio10.
506 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
507 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
508 if (EFI_ERROR (Status
)) {
511 if ((Virtio10
&& SubsystemId
>= 0x40) ||
512 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
513 Status
= gBS
->ConnectController (
514 Handle
, // ControllerHandle
515 NULL
, // DriverImageHandle -- connect all drivers
516 NULL
, // RemainingDevicePath -- produce all child handles
517 FALSE
// Recursive -- don't follow child handles
519 if (EFI_ERROR (Status
)) {
526 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
532 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
534 @param[in] DeviceHandle Handle of the LPC Bridge device.
536 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
537 ConOut, ConIn, and ErrOut.
539 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
543 PrepareLpcBridgeDevicePath (
544 IN EFI_HANDLE DeviceHandle
548 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
549 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
553 Status
= gBS
->HandleProtocol (
555 &gEfiDevicePathProtocolGuid
,
558 if (EFI_ERROR (Status
)) {
561 TempDevicePath
= DevicePath
;
566 DevicePath
= AppendDevicePathNode (DevicePath
,
567 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
569 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
574 DevicePath
= TempDevicePath
;
575 gPnp16550ComPortDeviceNode
.UID
= 0;
577 DevicePath
= AppendDevicePathNode (DevicePath
,
578 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
579 DevicePath
= AppendDevicePathNode (DevicePath
,
580 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
581 DevicePath
= AppendDevicePathNode (DevicePath
,
582 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
587 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
588 if (DevPathStr
!= NULL
) {
591 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
593 gPnp16550ComPortDeviceNode
.UID
+ 1,
596 FreePool(DevPathStr
);
599 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
600 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
601 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
606 DevicePath
= TempDevicePath
;
607 gPnp16550ComPortDeviceNode
.UID
= 1;
609 DevicePath
= AppendDevicePathNode (DevicePath
,
610 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
611 DevicePath
= AppendDevicePathNode (DevicePath
,
612 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
613 DevicePath
= AppendDevicePathNode (DevicePath
,
614 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
619 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
620 if (DevPathStr
!= NULL
) {
623 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
625 gPnp16550ComPortDeviceNode
.UID
+ 1,
628 FreePool(DevPathStr
);
631 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
632 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
633 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
640 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
641 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
646 EFI_HANDLE PciDeviceHandle
;
647 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
648 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
649 UINTN GopHandleCount
;
650 EFI_HANDLE
*GopHandleBuffer
;
652 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
653 return EFI_INVALID_PARAMETER
;
657 // Initialize the GopDevicePath to be PciDevicePath
659 *GopDevicePath
= PciDevicePath
;
660 TempPciDevicePath
= PciDevicePath
;
662 Status
= gBS
->LocateDevicePath (
663 &gEfiDevicePathProtocolGuid
,
667 if (EFI_ERROR (Status
)) {
672 // Try to connect this handle, so that GOP driver could start on this
673 // device and create child handles with GraphicsOutput Protocol installed
674 // on them, then we get device paths of these child handles and select
675 // them as possible console device.
677 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
679 Status
= gBS
->LocateHandleBuffer (
681 &gEfiGraphicsOutputProtocolGuid
,
686 if (!EFI_ERROR (Status
)) {
688 // Add all the child handles as possible Console Device
690 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
691 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
692 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
693 if (EFI_ERROR (Status
)) {
699 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
702 // In current implementation, we only enable one of the child handles
703 // as console device, i.e. sotre one of the child handle's device
704 // path to variable "ConOut"
705 // In future, we could select all child handles to be console device
708 *GopDevicePath
= TempDevicePath
;
711 // Delete the PCI device's path that added by
712 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
714 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
715 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
718 gBS
->FreePool (GopHandleBuffer
);
725 Add PCI display to ConOut.
727 @param[in] DeviceHandle Handle of the PCI display device.
729 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
731 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
735 PreparePciDisplayDevicePath (
736 IN EFI_HANDLE DeviceHandle
740 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
741 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
744 GopDevicePath
= NULL
;
745 Status
= gBS
->HandleProtocol (
747 &gEfiDevicePathProtocolGuid
,
750 if (EFI_ERROR (Status
)) {
754 GetGopDevicePath (DevicePath
, &GopDevicePath
);
755 DevicePath
= GopDevicePath
;
757 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
763 Add PCI Serial to ConOut, ConIn, ErrOut.
765 @param[in] DeviceHandle Handle of the PCI serial device.
767 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
770 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
774 PreparePciSerialDevicePath (
775 IN EFI_HANDLE DeviceHandle
779 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
782 Status
= gBS
->HandleProtocol (
784 &gEfiDevicePathProtocolGuid
,
787 if (EFI_ERROR (Status
)) {
791 DevicePath
= AppendDevicePathNode (DevicePath
,
792 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
793 DevicePath
= AppendDevicePathNode (DevicePath
,
794 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
796 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
797 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
798 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
804 VisitAllInstancesOfProtocol (
806 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
812 EFI_HANDLE
*HandleBuffer
;
817 // Start to check all the PciIo to find all possible device
821 Status
= gBS
->LocateHandleBuffer (
828 if (EFI_ERROR (Status
)) {
832 for (Index
= 0; Index
< HandleCount
; Index
++) {
833 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
834 if (EFI_ERROR (Status
)) {
838 Status
= (*CallBackFunction
) (
845 gBS
->FreePool (HandleBuffer
);
853 VisitingAPciInstance (
854 IN EFI_HANDLE Handle
,
860 EFI_PCI_IO_PROTOCOL
*PciIo
;
863 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
866 // Check for all PCI device
868 Status
= PciIo
->Pci
.Read (
872 sizeof (Pci
) / sizeof (UINT32
),
875 if (EFI_ERROR (Status
)) {
879 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
890 VisitAllPciInstances (
891 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
894 return VisitAllInstancesOfProtocol (
895 &gEfiPciIoProtocolGuid
,
896 VisitingAPciInstance
,
897 (VOID
*)(UINTN
) CallBackFunction
903 Do platform specific PCI Device check and add them to
904 ConOut, ConIn, ErrOut.
906 @param[in] Handle - Handle of PCI device instance
907 @param[in] PciIo - PCI IO protocol instance
908 @param[in] Pci - PCI Header register block
910 @retval EFI_SUCCESS - PCI Device check and Console variable update
912 @retval EFI_STATUS - PCI Device check or Console variable update fail.
917 DetectAndPreparePlatformPciDevicePath (
918 IN EFI_HANDLE Handle
,
919 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
925 Status
= PciIo
->Attributes (
927 EfiPciIoAttributeOperationEnable
,
928 EFI_PCI_DEVICE_ENABLE
,
931 ASSERT_EFI_ERROR (Status
);
934 // Here we decide whether it is LPC Bridge
936 if ((IS_PCI_LPC (Pci
)) ||
937 ((IS_PCI_ISA_PDECODE (Pci
)) &&
938 (Pci
->Hdr
.VendorId
== 0x8086) &&
939 (Pci
->Hdr
.DeviceId
== 0x7000)
943 // Add IsaKeyboard to ConIn,
944 // add IsaSerial to ConOut, ConIn, ErrOut
946 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
947 PrepareLpcBridgeDevicePath (Handle
);
951 // Here we decide which Serial device to enable in PCI bus
953 if (IS_PCI_16550SERIAL (Pci
)) {
955 // Add them to ConOut, ConIn, ErrOut.
957 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
958 PreparePciSerialDevicePath (Handle
);
963 // Here we decide which display device to enable in PCI bus
965 if (IS_PCI_DISPLAY (Pci
)) {
967 // Add them to ConOut.
969 DEBUG ((EFI_D_INFO
, "Found PCI display device\n"));
970 PreparePciDisplayDevicePath (Handle
);
979 Connect the predefined platform default console device.
981 Always try to find and enable PCI display devices.
983 @param[in] PlatformConsole Predefined platform default console device array.
986 PlatformInitializeConsole (
987 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
993 // Do platform specific PCI Device check and add them to ConOut, ConIn,
996 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
999 // Have chance to connect the platform default console,
1000 // the platform default console is the minimum device group
1001 // the platform should support
1003 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1005 // Update the console variable with the connect type
1007 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1008 EfiBootManagerUpdateConsoleVariable (ConIn
,
1009 PlatformConsole
[Index
].DevicePath
, NULL
);
1011 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1012 EfiBootManagerUpdateConsoleVariable (ConOut
,
1013 PlatformConsole
[Index
].DevicePath
, NULL
);
1015 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1016 EfiBootManagerUpdateConsoleVariable (ErrOut
,
1017 PlatformConsole
[Index
].DevicePath
, NULL
);
1024 Configure PCI Interrupt Line register for applicable devices
1025 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1027 @param[in] Handle - Handle of PCI device instance
1028 @param[in] PciIo - PCI IO protocol instance
1029 @param[in] PciHdr - PCI Header register block
1031 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1037 IN EFI_HANDLE Handle
,
1038 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1039 IN PCI_TYPE00
*PciHdr
1042 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1043 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1048 UINT32 RootBusNumber
;
1050 Status
= EFI_SUCCESS
;
1052 if (PciHdr
->Device
.InterruptPin
!= 0) {
1054 DevPathNode
= DevicePathFromHandle (Handle
);
1055 ASSERT (DevPathNode
!= NULL
);
1056 DevPath
= DevPathNode
;
1059 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1060 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1061 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1062 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1066 // Compute index into PciHostIrqs[] table by walking
1067 // the device path and adding up all device numbers
1069 Status
= EFI_NOT_FOUND
;
1071 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1072 while (!IsDevicePathEnd (DevPathNode
)) {
1073 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1074 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1076 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1079 // Unlike SeaBIOS, which starts climbing from the leaf device
1080 // up toward the root, we traverse the device path starting at
1081 // the root moving toward the leaf node.
1082 // The slot number of the top-level parent bridge is needed for
1083 // Q35 cases with more than 24 slots on the root bus.
1085 if (Status
!= EFI_SUCCESS
) {
1086 Status
= EFI_SUCCESS
;
1087 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1091 DevPathNode
= NextDevicePathNode (DevPathNode
);
1093 if (EFI_ERROR (Status
)) {
1096 if (RootBusNumber
== 0 && RootSlot
== 0) {
1099 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1106 // Final PciHostIrqs[] index calculation depends on the platform
1107 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1109 switch (mHostBridgeDevId
) {
1110 case INTEL_82441_DEVICE_ID
:
1113 case INTEL_Q35_MCH_DEVICE_ID
:
1115 // SeaBIOS contains the following comment:
1116 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1117 // with a different starting index - see q35-acpi-dsdt.dsl.
1119 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1121 if (RootSlot
> 24) {
1123 // in this case, subtract back out RootSlot from Idx
1124 // (SeaBIOS never adds it to begin with, but that would make our
1125 // device path traversal loop above too awkward)
1131 ASSERT (FALSE
); // should never get here
1133 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1134 IrqLine
= PciHostIrqs
[Idx
];
1136 DEBUG_CODE_BEGIN ();
1138 CHAR16
*DevPathString
;
1139 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1140 UINTN Segment
, Bus
, Device
, Function
;
1142 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1143 if (DevPathString
== NULL
) {
1144 DevPathString
= Fallback
;
1146 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1147 ASSERT_EFI_ERROR (Status
);
1149 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1150 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1153 if (DevPathString
!= Fallback
) {
1154 FreePool (DevPathString
);
1160 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1162 Status
= PciIo
->Pci
.Write (
1165 PCI_INT_LINE_OFFSET
,
1176 PciAcpiInitialization (
1182 // Query Host Bridge DID to determine platform type
1184 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1185 switch (mHostBridgeDevId
) {
1186 case INTEL_82441_DEVICE_ID
:
1187 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1189 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1191 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1192 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1193 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1194 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1196 case INTEL_Q35_MCH_DEVICE_ID
:
1197 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1199 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1201 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1202 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1203 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1204 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1205 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1206 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1207 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1208 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1211 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1212 __FUNCTION__
, mHostBridgeDevId
));
1218 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1220 VisitAllPciInstances (SetPciIntLine
);
1223 // Set ACPI SCI_EN bit in PMCNTRL
1225 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1229 This function detects if OVMF is running on Xen.
1238 EFI_HOB_GUID_TYPE
*GuidHob
;
1239 STATIC INTN FoundHob
= -1;
1241 if (FoundHob
== 0) {
1243 } else if (FoundHob
== 1) {
1248 // See if a XenInfo HOB is available
1250 GuidHob
= GetFirstGuidHob (&gEfiXenInfoGuid
);
1251 if (GuidHob
== NULL
) {
1262 ConnectRecursivelyIfPciMassStorage (
1263 IN EFI_HANDLE Handle
,
1264 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1265 IN PCI_TYPE00
*PciHeader
1269 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1273 // Recognize PCI Mass Storage, and Xen PCI devices
1275 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1276 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1278 Status
= gBS
->HandleProtocol (
1280 &gEfiDevicePathProtocolGuid
,
1283 if (EFI_ERROR (Status
)) {
1288 // Print Device Path
1290 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1291 if (DevPathStr
!= NULL
) {
1294 "Found %s device: %s\n",
1295 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1301 FreePool(DevPathStr
);
1304 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1305 if (EFI_ERROR (Status
)) {
1316 This notification function is invoked when the
1317 EMU Variable FVB has been changed.
1319 @param Event The event that occurred
1320 @param Context For EFI compatibility. Not used.
1325 EmuVariablesUpdatedCallback (
1330 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1331 UpdateNvVarsOnFileSystem ();
1337 VisitingFileSystemInstance (
1338 IN EFI_HANDLE Handle
,
1344 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1345 RETURN_STATUS PcdStatus
;
1347 if (ConnectedToFileSystem
) {
1348 return EFI_ALREADY_STARTED
;
1351 Status
= ConnectNvVarsToFileSystem (Handle
);
1352 if (EFI_ERROR (Status
)) {
1356 ConnectedToFileSystem
= TRUE
;
1358 EfiCreateProtocolNotifyEvent (
1359 &gEfiDevicePathProtocolGuid
,
1361 EmuVariablesUpdatedCallback
,
1363 &mEmuVariableEventReg
1365 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1366 (UINT64
)(UINTN
) mEmuVariableEvent
);
1367 ASSERT_RETURN_ERROR (PcdStatus
);
1374 PlatformBdsRestoreNvVarsFromHardDisk (
1377 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1378 VisitAllInstancesOfProtocol (
1379 &gEfiSimpleFileSystemProtocolGuid
,
1380 VisitingFileSystemInstance
,
1387 Connect with predefined platform connect sequence.
1389 The OEM/IBV can customize with their own connect sequence.
1392 PlatformBdsConnectSequence (
1397 RETURN_STATUS Status
;
1399 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1404 // Here we can get the customized platform connect sequence
1405 // Notes: we can connect with new variable which record the
1406 // last time boots connect device path sequence
1408 while (gPlatformConnectSequence
[Index
] != NULL
) {
1410 // Build the platform boot option
1412 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1416 Status
= ConnectDevicesFromQemu ();
1417 if (RETURN_ERROR (Status
)) {
1419 // Just use the simple policy to connect all devices
1421 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1422 EfiBootManagerConnectAll ();
1427 Save the S3 boot script.
1429 Note that DxeSmmReadyToLock must be signaled after this function returns;
1430 otherwise the script wouldn't be saved actually.
1439 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1440 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1442 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1443 (VOID
**) &BootScript
);
1444 ASSERT_EFI_ERROR (Status
);
1447 // Despite the opcode documentation in the PI spec, the protocol
1448 // implementation embeds a deep copy of the info in the boot script, rather
1449 // than storing just a pointer to runtime or NVS storage.
1451 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1452 (UINT32
) sizeof Info
,
1453 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1454 ASSERT_EFI_ERROR (Status
);
1459 Do the platform specific action after the console is ready
1461 Possible things that can be done in PlatformBootManagerAfterConsole:
1463 > Console post action:
1464 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1465 > Signal console ready platform customized event
1466 > Run diagnostics like memory testing
1467 > Connect certain devices
1468 > Dispatch aditional option roms
1469 > Special boot: e.g.: USB boot, enter UI
1473 PlatformBootManagerAfterConsole (
1477 EFI_BOOT_MODE BootMode
;
1479 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1481 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1482 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1483 "from disk since flash variables appear to be supported.\n"));
1486 // Try to restore variables from the hard disk early so
1487 // they can be used for the other BDS connect operations.
1489 PlatformBdsRestoreNvVarsFromHardDisk ();
1493 // Get current Boot Mode
1495 BootMode
= GetBootModeHob ();
1496 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1499 // Go the different platform policy with different boot mode
1500 // Notes: this part code can be change with the table policy
1502 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1507 BootLogoEnableLogo ();
1510 // Set PCI Interrupt Line registers and ACPI SCI_EN
1512 PciAcpiInitialization ();
1515 // Process TPM PPI request
1517 Tcg2PhysicalPresenceLibProcessRequest (NULL
);
1520 // Process QEMU's -kernel command line option
1522 TryRunningQemuKernel ();
1525 // Perform some platform specific connect sequence
1527 PlatformBdsConnectSequence ();
1529 EfiBootManagerRefreshAllBootOption ();
1532 // Register UEFI Shell
1534 PlatformRegisterFvBootOption (
1535 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1538 RemoveStaleFvFileOptions ();
1539 SetBootOrderFromQemu ();
1541 PlatformBmPrintScRegisterHandler ();
1545 This notification function is invoked when an instance of the
1546 EFI_DEVICE_PATH_PROTOCOL is produced.
1548 @param Event The event that occurred
1549 @param Context For EFI compatibility. Not used.
1562 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1563 ATAPI_DEVICE_PATH
*Atapi
;
1566 // Examine all new handles
1570 // Get the next handle
1572 BufferSize
= sizeof (Handle
);
1573 Status
= gBS
->LocateHandle (
1576 mEfiDevPathNotifyReg
,
1582 // If not found, we're done
1584 if (EFI_NOT_FOUND
== Status
) {
1588 if (EFI_ERROR (Status
)) {
1593 // Get the DevicePath protocol on that handle
1595 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1596 (VOID
**)&DevPathNode
);
1597 ASSERT_EFI_ERROR (Status
);
1599 while (!IsDevicePathEnd (DevPathNode
)) {
1601 // Find the handler to dump this device path node
1604 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1605 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1607 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1613 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1620 // Next device path node
1622 DevPathNode
= NextDevicePathNode (DevPathNode
);
1631 InstallDevicePathCallback (
1635 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1636 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1637 &gEfiDevicePathProtocolGuid
,
1641 &mEfiDevPathNotifyReg
1646 This function is called each second during the boot manager waits the
1649 @param TimeoutRemain The remaining timeout.
1653 PlatformBootManagerWaitCallback (
1654 UINT16 TimeoutRemain
1657 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1658 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1661 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1663 Black
.Raw
= 0x00000000;
1664 White
.Raw
= 0x00FFFFFF;
1666 BootLogoUpdateProgress (
1669 L
"Start boot option",
1671 (Timeout
- TimeoutRemain
) * 100 / Timeout
,
1677 The function is called when no boot option could be launched,
1678 including platform recovery options and options pointing to applications
1679 built into firmware volumes.
1681 If this function returns, BDS attempts to enter an infinite loop.
1685 PlatformBootManagerUnableToBoot (
1691 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu
;
1695 // BootManagerMenu doesn't contain the correct information when return status
1696 // is EFI_NOT_FOUND.
1698 Status
= EfiBootManagerGetBootManagerMenu (&BootManagerMenu
);
1699 if (EFI_ERROR (Status
)) {
1703 // Normally BdsDxe does not print anything to the system console, but this is
1704 // a last resort -- the end-user will likely not see any DEBUG messages
1705 // logged in this situation.
1707 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1708 // here to see if it makes sense to request and wait for a keypress.
1710 if (gST
->ConIn
!= NULL
) {
1712 "%a: No bootable option or device was found.\n"
1713 "%a: Press any key to enter the Boot Manager Menu.\n",
1717 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &Index
);
1718 ASSERT_EFI_ERROR (Status
);
1719 ASSERT (Index
== 0);
1722 // Drain any queued keys.
1724 while (!EFI_ERROR (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
))) {
1726 // just throw away Key
1732 EfiBootManagerBoot (&BootManagerMenu
);