2 Platform BDS customizations.
4 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "BdsPlatform.h"
10 #include <Guid/RootBridgesConnectedEventGroup.h>
11 #include <Protocol/FirmwareVolume2.h>
12 #include <Library/PlatformBmPrintScLib.h>
13 #include <Library/Tcg2PhysicalPresenceLib.h>
14 #include <Library/XenPlatformLib.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
[] = {
44 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
51 @param[in] Handle - Handle of PCI device instance
52 @param[in] PciIo - PCI IO protocol instance
53 @param[in] Pci - PCI Header register block
57 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
59 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
65 // Function prototypes
69 VisitAllInstancesOfProtocol (
71 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
76 VisitAllPciInstancesOfProtocol (
77 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
81 InstallDevicePathCallback (
86 PlatformRegisterFvBootOption (
94 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
95 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
96 UINTN BootOptionCount
;
97 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
98 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
99 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
101 Status
= gBS
->HandleProtocol (
103 &gEfiLoadedImageProtocolGuid
,
104 (VOID
**) &LoadedImage
106 ASSERT_EFI_ERROR (Status
);
108 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
109 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
110 ASSERT (DevicePath
!= NULL
);
111 DevicePath
= AppendDevicePathNode (
113 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
115 ASSERT (DevicePath
!= NULL
);
117 Status
= EfiBootManagerInitializeLoadOption (
119 LoadOptionNumberUnassigned
,
127 ASSERT_EFI_ERROR (Status
);
128 FreePool (DevicePath
);
130 BootOptions
= EfiBootManagerGetLoadOptions (
131 &BootOptionCount
, LoadOptionTypeBoot
134 OptionIndex
= EfiBootManagerFindLoadOption (
135 &NewOption
, BootOptions
, BootOptionCount
138 if (OptionIndex
== -1) {
139 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
140 ASSERT_EFI_ERROR (Status
);
142 EfiBootManagerFreeLoadOption (&NewOption
);
143 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
147 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
148 whose device paths do not resolve exactly to an FvFile in the system.
150 This removes any boot options that point to binaries built into the firmware
151 and have become stale due to any of the following:
152 - DXEFV's base address or size changed (historical),
153 - DXEFV's FvNameGuid changed,
154 - the FILE_GUID of the pointed-to binary changed,
155 - the referenced binary is no longer built into the firmware.
157 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
158 avoids exact duplicates.
161 RemoveStaleFvFileOptions (
165 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
166 UINTN BootOptionCount
;
169 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
,
172 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
173 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
178 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
179 // then keep the boot option.
181 Node1
= BootOptions
[Index
].FilePath
;
182 if (!(DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
&&
183 DevicePathSubType (Node1
) == HW_MEMMAP_DP
) &&
184 !(DevicePathType (Node1
) == MEDIA_DEVICE_PATH
&&
185 DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)) {
190 // If the second device path node is not FvFile(...), then keep the boot
193 Node2
= NextDevicePathNode (Node1
);
194 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
195 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
200 // Locate the Firmware Volume2 protocol instance that is denoted by the
201 // boot option. If this lookup fails (i.e., the boot option references a
202 // firmware volume that doesn't exist), then we'll proceed to delete the
206 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
,
207 &SearchNode
, &FvHandle
);
209 if (!EFI_ERROR (Status
)) {
211 // The firmware volume was found; now let's see if it contains the FvFile
212 // identified by GUID.
214 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
215 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
217 EFI_FV_FILETYPE FoundType
;
218 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
219 UINT32 AuthenticationStatus
;
221 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
,
222 (VOID
**)&FvProtocol
);
223 ASSERT_EFI_ERROR (Status
);
225 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
227 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
230 Status
= FvProtocol
->ReadFile (
232 &FvFileNode
->FvFileName
, // NameGuid
237 &AuthenticationStatus
239 if (!EFI_ERROR (Status
)) {
241 // The FvFile was found. Keep the boot option.
248 // Delete the boot option.
250 Status
= EfiBootManagerDeleteLoadOptionVariable (
251 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
253 CHAR16
*DevicePathString
;
255 DevicePathString
= ConvertDevicePathToText(BootOptions
[Index
].FilePath
,
258 EFI_ERROR (Status
) ? DEBUG_WARN
: DEBUG_VERBOSE
,
259 "%a: removing stale Boot#%04x %s: %r\n",
261 (UINT32
)BootOptions
[Index
].OptionNumber
,
262 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
265 if (DevicePathString
!= NULL
) {
266 FreePool (DevicePathString
);
271 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
275 PlatformRegisterOptionsAndKeys (
283 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
286 // Register ENTER as CONTINUE key
288 Enter
.ScanCode
= SCAN_NULL
;
289 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
290 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
291 ASSERT_EFI_ERROR (Status
);
294 // Map F2 to Boot Manager Menu
296 F2
.ScanCode
= SCAN_F2
;
297 F2
.UnicodeChar
= CHAR_NULL
;
298 Esc
.ScanCode
= SCAN_ESC
;
299 Esc
.UnicodeChar
= CHAR_NULL
;
300 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
301 ASSERT_EFI_ERROR (Status
);
302 Status
= EfiBootManagerAddKeyOptionVariable (
303 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
305 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
306 Status
= EfiBootManagerAddKeyOptionVariable (
307 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
309 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
315 IN EFI_HANDLE RootBridgeHandle
,
323 ConnectVirtioPciRng (
324 IN EFI_HANDLE Handle
,
336 // BDS Platform Functions
339 Do the platform init, can be customized by OEM/IBV
341 Possible things that can be done in PlatformBootManagerBeforeConsole:
343 > Update console variable: 1. include hot-plug devices;
344 > 2. Clear ConIn and add SOL for AMT
345 > Register new Driver#### or Boot####
346 > Register new Key####: e.g.: F12
347 > Signal ReadyToLock event
348 > Authentication action: 1. connect Auth devices;
349 > 2. Identify auto logon user.
353 PlatformBootManagerBeforeConsole (
359 UINT16 FrontPageTimeout
;
360 RETURN_STATUS PcdStatus
;
362 DEBUG ((DEBUG_INFO
, "PlatformBootManagerBeforeConsole\n"));
363 InstallDevicePathCallback ();
365 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
366 ConnectRootBridge
, NULL
);
369 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
371 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
374 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
375 // the preparation of S3 system information. That logic has a hard dependency
376 // on the presence of the FACS ACPI table. Since our ACPI tables are only
377 // installed after PCI enumeration completes, we must not trigger the S3 save
378 // earlier, hence we can't signal End-of-Dxe earlier.
380 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
382 if (PcdGetBool (PcdAcpiS3Enable
)) {
384 // Save the boot script too. Note that this will require us to emit the
385 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
390 // We need to connect all trusted consoles for TCG PP. Here we treat all
391 // consoles in OVMF to be trusted consoles.
392 PlatformInitializeConsole (
393 XenDetected() ? gXenPlatformConsole
: gPlatformConsole
);
396 // Process TPM PPI request; this may require keyboard input
398 Tcg2PhysicalPresenceLibProcessRequest (NULL
);
401 // Prevent further changes to LockBoxes or SMRAM.
402 // Any TPM 2 Physical Presence Interface opcode must be handled before.
405 Status
= gBS
->InstallProtocolInterface (&Handle
,
406 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
408 ASSERT_EFI_ERROR (Status
);
411 // Dispatch deferred images after EndOfDxe event and ReadyToLock
414 EfiBootManagerDispatchDeferredImages ();
416 FrontPageTimeout
= GetFrontPageTimeoutFromQemu ();
417 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
, FrontPageTimeout
);
418 ASSERT_RETURN_ERROR (PcdStatus
);
420 // Reflect the PCD in the standard Timeout variable.
422 Status
= gRT
->SetVariable (
423 EFI_TIME_OUT_VARIABLE_NAME
,
424 &gEfiGlobalVariableGuid
,
425 (EFI_VARIABLE_NON_VOLATILE
|
426 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
427 EFI_VARIABLE_RUNTIME_ACCESS
),
428 sizeof FrontPageTimeout
,
432 EFI_ERROR (Status
) ? DEBUG_ERROR
: DEBUG_VERBOSE
,
433 "%a: SetVariable(%s, %u): %r\n",
435 EFI_TIME_OUT_VARIABLE_NAME
,
440 PlatformRegisterOptionsAndKeys ();
443 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
444 // instances on Virtio PCI RNG devices.
446 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
454 IN EFI_HANDLE RootBridgeHandle
,
462 // Make the PCI bus driver connect the root bridge, non-recursively. This
463 // will produce a number of child handles with PciIo on them.
465 Status
= gBS
->ConnectController (
466 RootBridgeHandle
, // ControllerHandle
467 NULL
, // DriverImageHandle
468 NULL
, // RemainingDevicePath -- produce all
479 ConnectVirtioPciRng (
480 IN EFI_HANDLE Handle
,
485 EFI_PCI_IO_PROTOCOL
*PciIo
;
496 // Read and check VendorId.
498 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
500 if (EFI_ERROR (Status
)) {
503 if (VendorId
!= VIRTIO_VENDOR_ID
) {
508 // Read DeviceId and RevisionId.
510 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
512 if (EFI_ERROR (Status
)) {
515 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
517 if (EFI_ERROR (Status
)) {
522 // From DeviceId and RevisionId, determine whether the device is a
523 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
524 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
525 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
526 // only be sanity-checked, and SubsystemId will decide.
528 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
529 RevisionId
>= 0x01) {
531 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
538 // Read and check SubsystemId as dictated by Virtio10.
540 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
541 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
542 if (EFI_ERROR (Status
)) {
545 if ((Virtio10
&& SubsystemId
>= 0x40) ||
546 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
547 Status
= gBS
->ConnectController (
548 Handle
, // ControllerHandle
549 NULL
, // DriverImageHandle -- connect all drivers
550 NULL
, // RemainingDevicePath -- produce all child handles
551 FALSE
// Recursive -- don't follow child handles
553 if (EFI_ERROR (Status
)) {
560 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
566 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
568 @param[in] DeviceHandle Handle of the LPC Bridge device.
570 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
571 ConOut, ConIn, and ErrOut.
573 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
577 PrepareLpcBridgeDevicePath (
578 IN EFI_HANDLE DeviceHandle
582 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
583 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
587 Status
= gBS
->HandleProtocol (
589 &gEfiDevicePathProtocolGuid
,
592 if (EFI_ERROR (Status
)) {
595 TempDevicePath
= DevicePath
;
600 DevicePath
= AppendDevicePathNode (DevicePath
,
601 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
603 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
608 DevicePath
= TempDevicePath
;
609 gPnp16550ComPortDeviceNode
.UID
= 0;
611 DevicePath
= AppendDevicePathNode (DevicePath
,
612 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
613 DevicePath
= AppendDevicePathNode (DevicePath
,
614 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
615 DevicePath
= AppendDevicePathNode (DevicePath
,
616 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
621 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
622 if (DevPathStr
!= NULL
) {
625 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
627 gPnp16550ComPortDeviceNode
.UID
+ 1,
630 FreePool(DevPathStr
);
633 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
634 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
635 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
640 DevicePath
= TempDevicePath
;
641 gPnp16550ComPortDeviceNode
.UID
= 1;
643 DevicePath
= AppendDevicePathNode (DevicePath
,
644 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
645 DevicePath
= AppendDevicePathNode (DevicePath
,
646 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
647 DevicePath
= AppendDevicePathNode (DevicePath
,
648 (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
);
674 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
675 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
680 EFI_HANDLE PciDeviceHandle
;
681 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
682 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
683 UINTN GopHandleCount
;
684 EFI_HANDLE
*GopHandleBuffer
;
686 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
687 return EFI_INVALID_PARAMETER
;
691 // Initialize the GopDevicePath to be PciDevicePath
693 *GopDevicePath
= PciDevicePath
;
694 TempPciDevicePath
= PciDevicePath
;
696 Status
= gBS
->LocateDevicePath (
697 &gEfiDevicePathProtocolGuid
,
701 if (EFI_ERROR (Status
)) {
706 // Try to connect this handle, so that GOP driver could start on this
707 // device and create child handles with GraphicsOutput Protocol installed
708 // on them, then we get device paths of these child handles and select
709 // them as possible console device.
711 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
713 Status
= gBS
->LocateHandleBuffer (
715 &gEfiGraphicsOutputProtocolGuid
,
720 if (!EFI_ERROR (Status
)) {
722 // Add all the child handles as possible Console Device
724 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
725 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
726 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
727 if (EFI_ERROR (Status
)) {
733 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
736 // In current implementation, we only enable one of the child handles
737 // as console device, i.e. sotre one of the child handle's device
738 // path to variable "ConOut"
739 // In future, we could select all child handles to be console device
742 *GopDevicePath
= TempDevicePath
;
745 // Delete the PCI device's path that added by
746 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
748 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
749 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
752 gBS
->FreePool (GopHandleBuffer
);
759 Add PCI display to ConOut.
761 @param[in] DeviceHandle Handle of the PCI display device.
763 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
765 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
769 PreparePciDisplayDevicePath (
770 IN EFI_HANDLE DeviceHandle
774 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
775 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
778 GopDevicePath
= NULL
;
779 Status
= gBS
->HandleProtocol (
781 &gEfiDevicePathProtocolGuid
,
784 if (EFI_ERROR (Status
)) {
788 GetGopDevicePath (DevicePath
, &GopDevicePath
);
789 DevicePath
= GopDevicePath
;
791 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
797 Add PCI Serial to ConOut, ConIn, ErrOut.
799 @param[in] DeviceHandle Handle of the PCI serial device.
801 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
804 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
808 PreparePciSerialDevicePath (
809 IN EFI_HANDLE DeviceHandle
813 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
816 Status
= gBS
->HandleProtocol (
818 &gEfiDevicePathProtocolGuid
,
821 if (EFI_ERROR (Status
)) {
825 DevicePath
= AppendDevicePathNode (DevicePath
,
826 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
827 DevicePath
= AppendDevicePathNode (DevicePath
,
828 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
830 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
831 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
832 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
838 VisitAllInstancesOfProtocol (
840 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
846 EFI_HANDLE
*HandleBuffer
;
851 // Start to check all the PciIo to find all possible device
855 Status
= gBS
->LocateHandleBuffer (
862 if (EFI_ERROR (Status
)) {
866 for (Index
= 0; Index
< HandleCount
; Index
++) {
867 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
868 if (EFI_ERROR (Status
)) {
872 Status
= (*CallBackFunction
) (
879 gBS
->FreePool (HandleBuffer
);
887 VisitingAPciInstance (
888 IN EFI_HANDLE Handle
,
894 EFI_PCI_IO_PROTOCOL
*PciIo
;
897 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
900 // Check for all PCI device
902 Status
= PciIo
->Pci
.Read (
906 sizeof (Pci
) / sizeof (UINT32
),
909 if (EFI_ERROR (Status
)) {
913 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
924 VisitAllPciInstances (
925 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
928 return VisitAllInstancesOfProtocol (
929 &gEfiPciIoProtocolGuid
,
930 VisitingAPciInstance
,
931 (VOID
*)(UINTN
) CallBackFunction
937 Do platform specific PCI Device check and add them to
938 ConOut, ConIn, ErrOut.
940 @param[in] Handle - Handle of PCI device instance
941 @param[in] PciIo - PCI IO protocol instance
942 @param[in] Pci - PCI Header register block
944 @retval EFI_SUCCESS - PCI Device check and Console variable update
946 @retval EFI_STATUS - PCI Device check or Console variable update fail.
951 DetectAndPreparePlatformPciDevicePath (
952 IN EFI_HANDLE Handle
,
953 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
959 Status
= PciIo
->Attributes (
961 EfiPciIoAttributeOperationEnable
,
962 EFI_PCI_DEVICE_ENABLE
,
965 ASSERT_EFI_ERROR (Status
);
968 // Here we decide whether it is LPC Bridge
970 if ((IS_PCI_LPC (Pci
)) ||
971 ((IS_PCI_ISA_PDECODE (Pci
)) &&
972 (Pci
->Hdr
.VendorId
== 0x8086) &&
973 (Pci
->Hdr
.DeviceId
== 0x7000)
977 // Add IsaKeyboard to ConIn,
978 // add IsaSerial to ConOut, ConIn, ErrOut
980 DEBUG ((DEBUG_INFO
, "Found LPC Bridge device\n"));
981 PrepareLpcBridgeDevicePath (Handle
);
985 // Here we decide which Serial device to enable in PCI bus
987 if (IS_PCI_16550SERIAL (Pci
)) {
989 // Add them to ConOut, ConIn, ErrOut.
991 DEBUG ((DEBUG_INFO
, "Found PCI 16550 SERIAL device\n"));
992 PreparePciSerialDevicePath (Handle
);
997 // Here we decide which display device to enable in PCI bus
999 if (IS_PCI_DISPLAY (Pci
)) {
1001 // Add them to ConOut.
1003 DEBUG ((DEBUG_INFO
, "Found PCI display device\n"));
1004 PreparePciDisplayDevicePath (Handle
);
1013 Connect the predefined platform default console device.
1015 Always try to find and enable PCI display devices.
1017 @param[in] PlatformConsole Predefined platform default console device array.
1020 PlatformInitializeConsole (
1021 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
1027 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1030 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
1033 // Have chance to connect the platform default console,
1034 // the platform default console is the minimum device group
1035 // the platform should support
1037 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1039 // Update the console variable with the connect type
1041 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1042 EfiBootManagerUpdateConsoleVariable (ConIn
,
1043 PlatformConsole
[Index
].DevicePath
, NULL
);
1045 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1046 EfiBootManagerUpdateConsoleVariable (ConOut
,
1047 PlatformConsole
[Index
].DevicePath
, NULL
);
1049 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1050 EfiBootManagerUpdateConsoleVariable (ErrOut
,
1051 PlatformConsole
[Index
].DevicePath
, NULL
);
1058 Configure PCI Interrupt Line register for applicable devices
1059 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1061 @param[in] Handle - Handle of PCI device instance
1062 @param[in] PciIo - PCI IO protocol instance
1063 @param[in] PciHdr - PCI Header register block
1065 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1071 IN EFI_HANDLE Handle
,
1072 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1073 IN PCI_TYPE00
*PciHdr
1076 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1077 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1082 UINT32 RootBusNumber
;
1084 Status
= EFI_SUCCESS
;
1086 if (PciHdr
->Device
.InterruptPin
!= 0) {
1088 DevPathNode
= DevicePathFromHandle (Handle
);
1089 ASSERT (DevPathNode
!= NULL
);
1090 DevPath
= DevPathNode
;
1093 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1094 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1095 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1096 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1100 // Compute index into PciHostIrqs[] table by walking
1101 // the device path and adding up all device numbers
1103 Status
= EFI_NOT_FOUND
;
1105 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1106 while (!IsDevicePathEnd (DevPathNode
)) {
1107 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1108 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1110 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1113 // Unlike SeaBIOS, which starts climbing from the leaf device
1114 // up toward the root, we traverse the device path starting at
1115 // the root moving toward the leaf node.
1116 // The slot number of the top-level parent bridge is needed for
1117 // Q35 cases with more than 24 slots on the root bus.
1119 if (Status
!= EFI_SUCCESS
) {
1120 Status
= EFI_SUCCESS
;
1121 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1125 DevPathNode
= NextDevicePathNode (DevPathNode
);
1127 if (EFI_ERROR (Status
)) {
1130 if (RootBusNumber
== 0 && RootSlot
== 0) {
1133 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1140 // Final PciHostIrqs[] index calculation depends on the platform
1141 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1143 switch (mHostBridgeDevId
) {
1144 case INTEL_82441_DEVICE_ID
:
1147 case INTEL_Q35_MCH_DEVICE_ID
:
1149 // SeaBIOS contains the following comment:
1150 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1151 // with a different starting index - see q35-acpi-dsdt.dsl.
1153 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1155 if (RootSlot
> 24) {
1157 // in this case, subtract back out RootSlot from Idx
1158 // (SeaBIOS never adds it to begin with, but that would make our
1159 // device path traversal loop above too awkward)
1165 ASSERT (FALSE
); // should never get here
1167 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1168 IrqLine
= PciHostIrqs
[Idx
];
1170 DEBUG_CODE_BEGIN ();
1172 CHAR16
*DevPathString
;
1173 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1174 UINTN Segment
, Bus
, Device
, Function
;
1176 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1177 if (DevPathString
== NULL
) {
1178 DevPathString
= Fallback
;
1180 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1181 ASSERT_EFI_ERROR (Status
);
1183 DEBUG ((DEBUG_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1184 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1187 if (DevPathString
!= Fallback
) {
1188 FreePool (DevPathString
);
1194 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1196 Status
= PciIo
->Pci
.Write (
1199 PCI_INT_LINE_OFFSET
,
1210 PciAcpiInitialization (
1216 // Query Host Bridge DID to determine platform type
1218 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1219 switch (mHostBridgeDevId
) {
1220 case INTEL_82441_DEVICE_ID
:
1221 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1223 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1225 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), PciHostIrqs
[0]); // A
1226 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), PciHostIrqs
[1]); // B
1227 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), PciHostIrqs
[2]); // C
1228 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), PciHostIrqs
[3]); // D
1230 case INTEL_Q35_MCH_DEVICE_ID
:
1231 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1233 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1235 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), PciHostIrqs
[0]); // A
1236 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), PciHostIrqs
[1]); // B
1237 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), PciHostIrqs
[2]); // C
1238 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), PciHostIrqs
[3]); // D
1239 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), PciHostIrqs
[0]); // E
1240 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), PciHostIrqs
[1]); // F
1241 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), PciHostIrqs
[2]); // G
1242 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), PciHostIrqs
[3]); // H
1244 case MICROVM_PSEUDO_DEVICE_ID
:
1247 if (XenDetected ()) {
1249 // There is no PCI bus in this case.
1253 DEBUG ((DEBUG_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1254 __FUNCTION__
, mHostBridgeDevId
));
1260 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1262 VisitAllPciInstances (SetPciIntLine
);
1265 // Set ACPI SCI_EN bit in PMCNTRL
1267 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1272 ConnectRecursivelyIfPciMassStorage (
1273 IN EFI_HANDLE Handle
,
1274 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1275 IN PCI_TYPE00
*PciHeader
1279 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1283 // Recognize PCI Mass Storage, and Xen PCI devices
1285 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1286 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1288 Status
= gBS
->HandleProtocol (
1290 &gEfiDevicePathProtocolGuid
,
1293 if (EFI_ERROR (Status
)) {
1298 // Print Device Path
1300 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1301 if (DevPathStr
!= NULL
) {
1304 "Found %s device: %s\n",
1305 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1311 FreePool(DevPathStr
);
1314 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1315 if (EFI_ERROR (Status
)) {
1326 This notification function is invoked when the
1327 EMU Variable FVB has been changed.
1329 @param Event The event that occurred
1330 @param Context For EFI compatibility. Not used.
1335 EmuVariablesUpdatedCallback (
1340 DEBUG ((DEBUG_INFO
, "EmuVariablesUpdatedCallback\n"));
1341 UpdateNvVarsOnFileSystem ();
1347 VisitingFileSystemInstance (
1348 IN EFI_HANDLE Handle
,
1354 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1355 RETURN_STATUS PcdStatus
;
1357 if (ConnectedToFileSystem
) {
1358 return EFI_ALREADY_STARTED
;
1361 Status
= ConnectNvVarsToFileSystem (Handle
);
1362 if (EFI_ERROR (Status
)) {
1366 ConnectedToFileSystem
= TRUE
;
1368 EfiCreateProtocolNotifyEvent (
1369 &gEfiDevicePathProtocolGuid
,
1371 EmuVariablesUpdatedCallback
,
1373 &mEmuVariableEventReg
1375 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1376 (UINT64
)(UINTN
) mEmuVariableEvent
);
1377 ASSERT_RETURN_ERROR (PcdStatus
);
1384 PlatformBdsRestoreNvVarsFromHardDisk (
1387 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1388 VisitAllInstancesOfProtocol (
1389 &gEfiSimpleFileSystemProtocolGuid
,
1390 VisitingFileSystemInstance
,
1397 Connect with predefined platform connect sequence.
1399 The OEM/IBV can customize with their own connect sequence.
1402 PlatformBdsConnectSequence (
1407 RETURN_STATUS Status
;
1409 DEBUG ((DEBUG_INFO
, "PlatformBdsConnectSequence\n"));
1414 // Here we can get the customized platform connect sequence
1415 // Notes: we can connect with new variable which record the
1416 // last time boots connect device path sequence
1418 while (gPlatformConnectSequence
[Index
] != NULL
) {
1420 // Build the platform boot option
1422 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1426 Status
= ConnectDevicesFromQemu ();
1427 if (RETURN_ERROR (Status
)) {
1429 // Just use the simple policy to connect all devices
1431 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1432 EfiBootManagerConnectAll ();
1437 Save the S3 boot script.
1439 Note that DxeSmmReadyToLock must be signaled after this function returns;
1440 otherwise the script wouldn't be saved actually.
1449 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1450 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1452 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1453 (VOID
**) &BootScript
);
1454 ASSERT_EFI_ERROR (Status
);
1457 // Despite the opcode documentation in the PI spec, the protocol
1458 // implementation embeds a deep copy of the info in the boot script, rather
1459 // than storing just a pointer to runtime or NVS storage.
1461 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1462 (UINT32
) sizeof Info
,
1463 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1464 ASSERT_EFI_ERROR (Status
);
1469 Do the platform specific action after the console is ready
1471 Possible things that can be done in PlatformBootManagerAfterConsole:
1473 > Console post action:
1474 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1475 > Signal console ready platform customized event
1476 > Run diagnostics like memory testing
1477 > Connect certain devices
1478 > Dispatch aditional option roms
1479 > Special boot: e.g.: USB boot, enter UI
1483 PlatformBootManagerAfterConsole (
1487 EFI_BOOT_MODE BootMode
;
1489 DEBUG ((DEBUG_INFO
, "PlatformBootManagerAfterConsole\n"));
1491 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1492 DEBUG ((DEBUG_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1493 "from disk since flash variables appear to be supported.\n"));
1496 // Try to restore variables from the hard disk early so
1497 // they can be used for the other BDS connect operations.
1499 PlatformBdsRestoreNvVarsFromHardDisk ();
1503 // Get current Boot Mode
1505 BootMode
= GetBootModeHob ();
1506 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1509 // Go the different platform policy with different boot mode
1510 // Notes: this part code can be change with the table policy
1512 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1517 BootLogoEnableLogo ();
1520 // Set PCI Interrupt Line registers and ACPI SCI_EN
1522 PciAcpiInitialization ();
1525 // Process QEMU's -kernel command line option
1527 TryRunningQemuKernel ();
1530 // Perform some platform specific connect sequence
1532 PlatformBdsConnectSequence ();
1534 EfiBootManagerRefreshAllBootOption ();
1537 // Register UEFI Shell
1539 PlatformRegisterFvBootOption (
1540 &gUefiShellFileGuid
, L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1543 RemoveStaleFvFileOptions ();
1544 SetBootOrderFromQemu ();
1546 PlatformBmPrintScRegisterHandler ();
1550 This notification function is invoked when an instance of the
1551 EFI_DEVICE_PATH_PROTOCOL is produced.
1553 @param Event The event that occurred
1554 @param Context For EFI compatibility. Not used.
1567 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1568 ATAPI_DEVICE_PATH
*Atapi
;
1571 // Examine all new handles
1575 // Get the next handle
1577 BufferSize
= sizeof (Handle
);
1578 Status
= gBS
->LocateHandle (
1581 mEfiDevPathNotifyReg
,
1587 // If not found, we're done
1589 if (EFI_NOT_FOUND
== Status
) {
1593 if (EFI_ERROR (Status
)) {
1598 // Get the DevicePath protocol on that handle
1600 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1601 (VOID
**)&DevPathNode
);
1602 ASSERT_EFI_ERROR (Status
);
1604 while (!IsDevicePathEnd (DevPathNode
)) {
1606 // Find the handler to dump this device path node
1609 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1610 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1612 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1618 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1625 // Next device path node
1627 DevPathNode
= NextDevicePathNode (DevPathNode
);
1636 InstallDevicePathCallback (
1640 DEBUG ((DEBUG_INFO
, "Registered NotifyDevPath Event\n"));
1641 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1642 &gEfiDevicePathProtocolGuid
,
1646 &mEfiDevPathNotifyReg
1651 This function is called each second during the boot manager waits the
1654 @param TimeoutRemain The remaining timeout.
1658 PlatformBootManagerWaitCallback (
1659 UINT16 TimeoutRemain
1662 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1663 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1664 UINT16 TimeoutInitial
;
1666 TimeoutInitial
= PcdGet16 (PcdPlatformBootTimeOut
);
1669 // If PcdPlatformBootTimeOut is set to zero, then we consider
1670 // that no progress update should be enacted (since we'd only
1671 // ever display a one-shot progress of either 0% or 100%).
1673 if (TimeoutInitial
== 0) {
1677 Black
.Raw
= 0x00000000;
1678 White
.Raw
= 0x00FFFFFF;
1680 BootLogoUpdateProgress (
1683 L
"Start boot option",
1685 (TimeoutInitial
- TimeoutRemain
) * 100 / TimeoutInitial
,
1691 The function is called when no boot option could be launched,
1692 including platform recovery options and options pointing to applications
1693 built into firmware volumes.
1695 If this function returns, BDS attempts to enter an infinite loop.
1699 PlatformBootManagerUnableToBoot (
1705 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu
;
1709 // BootManagerMenu doesn't contain the correct information when return status
1710 // is EFI_NOT_FOUND.
1712 Status
= EfiBootManagerGetBootManagerMenu (&BootManagerMenu
);
1713 if (EFI_ERROR (Status
)) {
1717 // Normally BdsDxe does not print anything to the system console, but this is
1718 // a last resort -- the end-user will likely not see any DEBUG messages
1719 // logged in this situation.
1721 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1722 // here to see if it makes sense to request and wait for a keypress.
1724 if (gST
->ConIn
!= NULL
) {
1726 "%a: No bootable option or device was found.\n"
1727 "%a: Press any key to enter the Boot Manager Menu.\n",
1731 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &Index
);
1732 ASSERT_EFI_ERROR (Status
);
1733 ASSERT (Index
== 0);
1736 // Drain any queued keys.
1738 while (!EFI_ERROR (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
))) {
1740 // just throw away Key
1746 EfiBootManagerBoot (&BootManagerMenu
);