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.
391 // Prevent further changes to LockBoxes or SMRAM.
394 Status
= gBS
->InstallProtocolInterface (&Handle
,
395 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
397 ASSERT_EFI_ERROR (Status
);
400 // Dispatch deferred images after EndOfDxe event and ReadyToLock
403 EfiBootManagerDispatchDeferredImages ();
405 PlatformInitializeConsole (
406 XenDetected() ? gXenPlatformConsole
: gPlatformConsole
);
408 FrontPageTimeout
= GetFrontPageTimeoutFromQemu ();
409 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
, FrontPageTimeout
);
410 ASSERT_RETURN_ERROR (PcdStatus
);
412 // Reflect the PCD in the standard Timeout variable.
414 Status
= gRT
->SetVariable (
415 EFI_TIME_OUT_VARIABLE_NAME
,
416 &gEfiGlobalVariableGuid
,
417 (EFI_VARIABLE_NON_VOLATILE
|
418 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
419 EFI_VARIABLE_RUNTIME_ACCESS
),
420 sizeof FrontPageTimeout
,
424 EFI_ERROR (Status
) ? DEBUG_ERROR
: DEBUG_VERBOSE
,
425 "%a: SetVariable(%s, %u): %r\n",
427 EFI_TIME_OUT_VARIABLE_NAME
,
432 PlatformRegisterOptionsAndKeys ();
435 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
436 // instances on Virtio PCI RNG devices.
438 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
446 IN EFI_HANDLE RootBridgeHandle
,
454 // Make the PCI bus driver connect the root bridge, non-recursively. This
455 // will produce a number of child handles with PciIo on them.
457 Status
= gBS
->ConnectController (
458 RootBridgeHandle
, // ControllerHandle
459 NULL
, // DriverImageHandle
460 NULL
, // RemainingDevicePath -- produce all
471 ConnectVirtioPciRng (
472 IN EFI_HANDLE Handle
,
477 EFI_PCI_IO_PROTOCOL
*PciIo
;
488 // Read and check VendorId.
490 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
492 if (EFI_ERROR (Status
)) {
495 if (VendorId
!= VIRTIO_VENDOR_ID
) {
500 // Read DeviceId and RevisionId.
502 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
504 if (EFI_ERROR (Status
)) {
507 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
509 if (EFI_ERROR (Status
)) {
514 // From DeviceId and RevisionId, determine whether the device is a
515 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
516 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
517 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
518 // only be sanity-checked, and SubsystemId will decide.
520 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
521 RevisionId
>= 0x01) {
523 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
530 // Read and check SubsystemId as dictated by Virtio10.
532 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
533 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
534 if (EFI_ERROR (Status
)) {
537 if ((Virtio10
&& SubsystemId
>= 0x40) ||
538 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
539 Status
= gBS
->ConnectController (
540 Handle
, // ControllerHandle
541 NULL
, // DriverImageHandle -- connect all drivers
542 NULL
, // RemainingDevicePath -- produce all child handles
543 FALSE
// Recursive -- don't follow child handles
545 if (EFI_ERROR (Status
)) {
552 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
558 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
560 @param[in] DeviceHandle Handle of the LPC Bridge device.
562 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
563 ConOut, ConIn, and ErrOut.
565 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
569 PrepareLpcBridgeDevicePath (
570 IN EFI_HANDLE DeviceHandle
574 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
575 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
579 Status
= gBS
->HandleProtocol (
581 &gEfiDevicePathProtocolGuid
,
584 if (EFI_ERROR (Status
)) {
587 TempDevicePath
= DevicePath
;
592 DevicePath
= AppendDevicePathNode (DevicePath
,
593 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
595 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
600 DevicePath
= TempDevicePath
;
601 gPnp16550ComPortDeviceNode
.UID
= 0;
603 DevicePath
= AppendDevicePathNode (DevicePath
,
604 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
605 DevicePath
= AppendDevicePathNode (DevicePath
,
606 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
607 DevicePath
= AppendDevicePathNode (DevicePath
,
608 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
613 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
614 if (DevPathStr
!= NULL
) {
617 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
619 gPnp16550ComPortDeviceNode
.UID
+ 1,
622 FreePool(DevPathStr
);
625 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
626 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
627 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
632 DevicePath
= TempDevicePath
;
633 gPnp16550ComPortDeviceNode
.UID
= 1;
635 DevicePath
= AppendDevicePathNode (DevicePath
,
636 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
637 DevicePath
= AppendDevicePathNode (DevicePath
,
638 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
639 DevicePath
= AppendDevicePathNode (DevicePath
,
640 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
645 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
646 if (DevPathStr
!= NULL
) {
649 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
651 gPnp16550ComPortDeviceNode
.UID
+ 1,
654 FreePool(DevPathStr
);
657 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
658 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
659 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
666 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
667 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
672 EFI_HANDLE PciDeviceHandle
;
673 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
674 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
675 UINTN GopHandleCount
;
676 EFI_HANDLE
*GopHandleBuffer
;
678 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
679 return EFI_INVALID_PARAMETER
;
683 // Initialize the GopDevicePath to be PciDevicePath
685 *GopDevicePath
= PciDevicePath
;
686 TempPciDevicePath
= PciDevicePath
;
688 Status
= gBS
->LocateDevicePath (
689 &gEfiDevicePathProtocolGuid
,
693 if (EFI_ERROR (Status
)) {
698 // Try to connect this handle, so that GOP driver could start on this
699 // device and create child handles with GraphicsOutput Protocol installed
700 // on them, then we get device paths of these child handles and select
701 // them as possible console device.
703 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
705 Status
= gBS
->LocateHandleBuffer (
707 &gEfiGraphicsOutputProtocolGuid
,
712 if (!EFI_ERROR (Status
)) {
714 // Add all the child handles as possible Console Device
716 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
717 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
718 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
719 if (EFI_ERROR (Status
)) {
725 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
728 // In current implementation, we only enable one of the child handles
729 // as console device, i.e. sotre one of the child handle's device
730 // path to variable "ConOut"
731 // In future, we could select all child handles to be console device
734 *GopDevicePath
= TempDevicePath
;
737 // Delete the PCI device's path that added by
738 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
740 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
741 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
744 gBS
->FreePool (GopHandleBuffer
);
751 Add PCI display to ConOut.
753 @param[in] DeviceHandle Handle of the PCI display device.
755 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
757 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
761 PreparePciDisplayDevicePath (
762 IN EFI_HANDLE DeviceHandle
766 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
767 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
770 GopDevicePath
= NULL
;
771 Status
= gBS
->HandleProtocol (
773 &gEfiDevicePathProtocolGuid
,
776 if (EFI_ERROR (Status
)) {
780 GetGopDevicePath (DevicePath
, &GopDevicePath
);
781 DevicePath
= GopDevicePath
;
783 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
789 Add PCI Serial to ConOut, ConIn, ErrOut.
791 @param[in] DeviceHandle Handle of the PCI serial device.
793 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
796 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
800 PreparePciSerialDevicePath (
801 IN EFI_HANDLE DeviceHandle
805 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
808 Status
= gBS
->HandleProtocol (
810 &gEfiDevicePathProtocolGuid
,
813 if (EFI_ERROR (Status
)) {
817 DevicePath
= AppendDevicePathNode (DevicePath
,
818 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
819 DevicePath
= AppendDevicePathNode (DevicePath
,
820 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
822 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
823 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
824 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
830 VisitAllInstancesOfProtocol (
832 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
838 EFI_HANDLE
*HandleBuffer
;
843 // Start to check all the PciIo to find all possible device
847 Status
= gBS
->LocateHandleBuffer (
854 if (EFI_ERROR (Status
)) {
858 for (Index
= 0; Index
< HandleCount
; Index
++) {
859 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
860 if (EFI_ERROR (Status
)) {
864 Status
= (*CallBackFunction
) (
871 gBS
->FreePool (HandleBuffer
);
879 VisitingAPciInstance (
880 IN EFI_HANDLE Handle
,
886 EFI_PCI_IO_PROTOCOL
*PciIo
;
889 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
892 // Check for all PCI device
894 Status
= PciIo
->Pci
.Read (
898 sizeof (Pci
) / sizeof (UINT32
),
901 if (EFI_ERROR (Status
)) {
905 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
916 VisitAllPciInstances (
917 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
920 return VisitAllInstancesOfProtocol (
921 &gEfiPciIoProtocolGuid
,
922 VisitingAPciInstance
,
923 (VOID
*)(UINTN
) CallBackFunction
929 Do platform specific PCI Device check and add them to
930 ConOut, ConIn, ErrOut.
932 @param[in] Handle - Handle of PCI device instance
933 @param[in] PciIo - PCI IO protocol instance
934 @param[in] Pci - PCI Header register block
936 @retval EFI_SUCCESS - PCI Device check and Console variable update
938 @retval EFI_STATUS - PCI Device check or Console variable update fail.
943 DetectAndPreparePlatformPciDevicePath (
944 IN EFI_HANDLE Handle
,
945 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
951 Status
= PciIo
->Attributes (
953 EfiPciIoAttributeOperationEnable
,
954 EFI_PCI_DEVICE_ENABLE
,
957 ASSERT_EFI_ERROR (Status
);
960 // Here we decide whether it is LPC Bridge
962 if ((IS_PCI_LPC (Pci
)) ||
963 ((IS_PCI_ISA_PDECODE (Pci
)) &&
964 (Pci
->Hdr
.VendorId
== 0x8086) &&
965 (Pci
->Hdr
.DeviceId
== 0x7000)
969 // Add IsaKeyboard to ConIn,
970 // add IsaSerial to ConOut, ConIn, ErrOut
972 DEBUG ((DEBUG_INFO
, "Found LPC Bridge device\n"));
973 PrepareLpcBridgeDevicePath (Handle
);
977 // Here we decide which Serial device to enable in PCI bus
979 if (IS_PCI_16550SERIAL (Pci
)) {
981 // Add them to ConOut, ConIn, ErrOut.
983 DEBUG ((DEBUG_INFO
, "Found PCI 16550 SERIAL device\n"));
984 PreparePciSerialDevicePath (Handle
);
989 // Here we decide which display device to enable in PCI bus
991 if (IS_PCI_DISPLAY (Pci
)) {
993 // Add them to ConOut.
995 DEBUG ((DEBUG_INFO
, "Found PCI display device\n"));
996 PreparePciDisplayDevicePath (Handle
);
1005 Connect the predefined platform default console device.
1007 Always try to find and enable PCI display devices.
1009 @param[in] PlatformConsole Predefined platform default console device array.
1012 PlatformInitializeConsole (
1013 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
1019 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1022 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
1025 // Have chance to connect the platform default console,
1026 // the platform default console is the minimum device group
1027 // the platform should support
1029 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1031 // Update the console variable with the connect type
1033 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1034 EfiBootManagerUpdateConsoleVariable (ConIn
,
1035 PlatformConsole
[Index
].DevicePath
, NULL
);
1037 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1038 EfiBootManagerUpdateConsoleVariable (ConOut
,
1039 PlatformConsole
[Index
].DevicePath
, NULL
);
1041 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1042 EfiBootManagerUpdateConsoleVariable (ErrOut
,
1043 PlatformConsole
[Index
].DevicePath
, NULL
);
1050 Configure PCI Interrupt Line register for applicable devices
1051 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1053 @param[in] Handle - Handle of PCI device instance
1054 @param[in] PciIo - PCI IO protocol instance
1055 @param[in] PciHdr - PCI Header register block
1057 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1063 IN EFI_HANDLE Handle
,
1064 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1065 IN PCI_TYPE00
*PciHdr
1068 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1069 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1074 UINT32 RootBusNumber
;
1076 Status
= EFI_SUCCESS
;
1078 if (PciHdr
->Device
.InterruptPin
!= 0) {
1080 DevPathNode
= DevicePathFromHandle (Handle
);
1081 ASSERT (DevPathNode
!= NULL
);
1082 DevPath
= DevPathNode
;
1085 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1086 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1087 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1088 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1092 // Compute index into PciHostIrqs[] table by walking
1093 // the device path and adding up all device numbers
1095 Status
= EFI_NOT_FOUND
;
1097 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1098 while (!IsDevicePathEnd (DevPathNode
)) {
1099 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1100 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1102 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1105 // Unlike SeaBIOS, which starts climbing from the leaf device
1106 // up toward the root, we traverse the device path starting at
1107 // the root moving toward the leaf node.
1108 // The slot number of the top-level parent bridge is needed for
1109 // Q35 cases with more than 24 slots on the root bus.
1111 if (Status
!= EFI_SUCCESS
) {
1112 Status
= EFI_SUCCESS
;
1113 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1117 DevPathNode
= NextDevicePathNode (DevPathNode
);
1119 if (EFI_ERROR (Status
)) {
1122 if (RootBusNumber
== 0 && RootSlot
== 0) {
1125 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1132 // Final PciHostIrqs[] index calculation depends on the platform
1133 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1135 switch (mHostBridgeDevId
) {
1136 case INTEL_82441_DEVICE_ID
:
1139 case INTEL_Q35_MCH_DEVICE_ID
:
1141 // SeaBIOS contains the following comment:
1142 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1143 // with a different starting index - see q35-acpi-dsdt.dsl.
1145 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1147 if (RootSlot
> 24) {
1149 // in this case, subtract back out RootSlot from Idx
1150 // (SeaBIOS never adds it to begin with, but that would make our
1151 // device path traversal loop above too awkward)
1157 ASSERT (FALSE
); // should never get here
1159 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1160 IrqLine
= PciHostIrqs
[Idx
];
1162 DEBUG_CODE_BEGIN ();
1164 CHAR16
*DevPathString
;
1165 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1166 UINTN Segment
, Bus
, Device
, Function
;
1168 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1169 if (DevPathString
== NULL
) {
1170 DevPathString
= Fallback
;
1172 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1173 ASSERT_EFI_ERROR (Status
);
1175 DEBUG ((DEBUG_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1176 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1179 if (DevPathString
!= Fallback
) {
1180 FreePool (DevPathString
);
1186 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1188 Status
= PciIo
->Pci
.Write (
1191 PCI_INT_LINE_OFFSET
,
1202 PciAcpiInitialization (
1208 // Query Host Bridge DID to determine platform type
1210 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1211 switch (mHostBridgeDevId
) {
1212 case INTEL_82441_DEVICE_ID
:
1213 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1215 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1217 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), PciHostIrqs
[0]); // A
1218 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), PciHostIrqs
[1]); // B
1219 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), PciHostIrqs
[2]); // C
1220 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), PciHostIrqs
[3]); // D
1222 case INTEL_Q35_MCH_DEVICE_ID
:
1223 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1225 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1227 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), PciHostIrqs
[0]); // A
1228 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), PciHostIrqs
[1]); // B
1229 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), PciHostIrqs
[2]); // C
1230 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), PciHostIrqs
[3]); // D
1231 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), PciHostIrqs
[0]); // E
1232 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), PciHostIrqs
[1]); // F
1233 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), PciHostIrqs
[2]); // G
1234 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), PciHostIrqs
[3]); // H
1237 if (XenDetected ()) {
1239 // There is no PCI bus in this case.
1243 DEBUG ((DEBUG_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1244 __FUNCTION__
, mHostBridgeDevId
));
1250 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1252 VisitAllPciInstances (SetPciIntLine
);
1255 // Set ACPI SCI_EN bit in PMCNTRL
1257 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_INFO
, "PlatformBootManagerAfterConsole\n"));
1481 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1482 DEBUG ((DEBUG_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 &gUefiShellFileGuid
, 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 ((DEBUG_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
;
1659 UINT16 TimeoutInitial
;
1661 TimeoutInitial
= PcdGet16 (PcdPlatformBootTimeOut
);
1664 // If PcdPlatformBootTimeOut is set to zero, then we consider
1665 // that no progress update should be enacted (since we'd only
1666 // ever display a one-shot progress of either 0% or 100%).
1668 if (TimeoutInitial
== 0) {
1672 Black
.Raw
= 0x00000000;
1673 White
.Raw
= 0x00FFFFFF;
1675 BootLogoUpdateProgress (
1678 L
"Start boot option",
1680 (TimeoutInitial
- TimeoutRemain
) * 100 / TimeoutInitial
,
1686 The function is called when no boot option could be launched,
1687 including platform recovery options and options pointing to applications
1688 built into firmware volumes.
1690 If this function returns, BDS attempts to enter an infinite loop.
1694 PlatformBootManagerUnableToBoot (
1700 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu
;
1704 // BootManagerMenu doesn't contain the correct information when return status
1705 // is EFI_NOT_FOUND.
1707 Status
= EfiBootManagerGetBootManagerMenu (&BootManagerMenu
);
1708 if (EFI_ERROR (Status
)) {
1712 // Normally BdsDxe does not print anything to the system console, but this is
1713 // a last resort -- the end-user will likely not see any DEBUG messages
1714 // logged in this situation.
1716 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1717 // here to see if it makes sense to request and wait for a keypress.
1719 if (gST
->ConIn
!= NULL
) {
1721 "%a: No bootable option or device was found.\n"
1722 "%a: Press any key to enter the Boot Manager Menu.\n",
1726 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &Index
);
1727 ASSERT_EFI_ERROR (Status
);
1728 ASSERT (Index
== 0);
1731 // Drain any queued keys.
1733 while (!EFI_ERROR (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
))) {
1735 // just throw away Key
1741 EfiBootManagerBoot (&BootManagerMenu
);