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
[] = {
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 UINT16 FrontPageTimeout
;
357 RETURN_STATUS PcdStatus
;
359 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
360 InstallDevicePathCallback ();
362 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
363 ConnectRootBridge
, NULL
);
366 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
368 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
371 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
372 // the preparation of S3 system information. That logic has a hard dependency
373 // on the presence of the FACS ACPI table. Since our ACPI tables are only
374 // installed after PCI enumeration completes, we must not trigger the S3 save
375 // earlier, hence we can't signal End-of-Dxe earlier.
377 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
379 if (QemuFwCfgS3Enabled ()) {
381 // Save the boot script too. Note that this will require us to emit the
382 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
388 // Prevent further changes to LockBoxes or SMRAM.
391 Status
= gBS
->InstallProtocolInterface (&Handle
,
392 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
394 ASSERT_EFI_ERROR (Status
);
397 // Dispatch deferred images after EndOfDxe event and ReadyToLock
400 EfiBootManagerDispatchDeferredImages ();
402 PlatformInitializeConsole (
403 XenDetected() ? gXenPlatformConsole
: gPlatformConsole
);
405 FrontPageTimeout
= GetFrontPageTimeoutFromQemu ();
406 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
, FrontPageTimeout
);
407 ASSERT_RETURN_ERROR (PcdStatus
);
409 // Reflect the PCD in the standard Timeout variable.
411 Status
= gRT
->SetVariable (
412 EFI_TIME_OUT_VARIABLE_NAME
,
413 &gEfiGlobalVariableGuid
,
414 (EFI_VARIABLE_NON_VOLATILE
|
415 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
416 EFI_VARIABLE_RUNTIME_ACCESS
),
417 sizeof FrontPageTimeout
,
421 EFI_ERROR (Status
) ? DEBUG_ERROR
: DEBUG_VERBOSE
,
422 "%a: SetVariable(%s, %u): %r\n",
424 EFI_TIME_OUT_VARIABLE_NAME
,
429 PlatformRegisterOptionsAndKeys ();
432 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
433 // instances on Virtio PCI RNG devices.
435 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
443 IN EFI_HANDLE RootBridgeHandle
,
451 // Make the PCI bus driver connect the root bridge, non-recursively. This
452 // will produce a number of child handles with PciIo on them.
454 Status
= gBS
->ConnectController (
455 RootBridgeHandle
, // ControllerHandle
456 NULL
, // DriverImageHandle
457 NULL
, // RemainingDevicePath -- produce all
468 ConnectVirtioPciRng (
469 IN EFI_HANDLE Handle
,
474 EFI_PCI_IO_PROTOCOL
*PciIo
;
485 // Read and check VendorId.
487 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
489 if (EFI_ERROR (Status
)) {
492 if (VendorId
!= VIRTIO_VENDOR_ID
) {
497 // Read DeviceId and RevisionId.
499 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
501 if (EFI_ERROR (Status
)) {
504 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
506 if (EFI_ERROR (Status
)) {
511 // From DeviceId and RevisionId, determine whether the device is a
512 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
513 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
514 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
515 // only be sanity-checked, and SubsystemId will decide.
517 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
518 RevisionId
>= 0x01) {
520 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
527 // Read and check SubsystemId as dictated by Virtio10.
529 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
530 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
531 if (EFI_ERROR (Status
)) {
534 if ((Virtio10
&& SubsystemId
>= 0x40) ||
535 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
536 Status
= gBS
->ConnectController (
537 Handle
, // ControllerHandle
538 NULL
, // DriverImageHandle -- connect all drivers
539 NULL
, // RemainingDevicePath -- produce all child handles
540 FALSE
// Recursive -- don't follow child handles
542 if (EFI_ERROR (Status
)) {
549 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
555 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
557 @param[in] DeviceHandle Handle of the LPC Bridge device.
559 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
560 ConOut, ConIn, and ErrOut.
562 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
566 PrepareLpcBridgeDevicePath (
567 IN EFI_HANDLE DeviceHandle
571 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
572 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
576 Status
= gBS
->HandleProtocol (
578 &gEfiDevicePathProtocolGuid
,
581 if (EFI_ERROR (Status
)) {
584 TempDevicePath
= DevicePath
;
589 DevicePath
= AppendDevicePathNode (DevicePath
,
590 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
592 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
597 DevicePath
= TempDevicePath
;
598 gPnp16550ComPortDeviceNode
.UID
= 0;
600 DevicePath
= AppendDevicePathNode (DevicePath
,
601 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
602 DevicePath
= AppendDevicePathNode (DevicePath
,
603 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
604 DevicePath
= AppendDevicePathNode (DevicePath
,
605 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
610 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
611 if (DevPathStr
!= NULL
) {
614 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
616 gPnp16550ComPortDeviceNode
.UID
+ 1,
619 FreePool(DevPathStr
);
622 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
623 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
624 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
629 DevicePath
= TempDevicePath
;
630 gPnp16550ComPortDeviceNode
.UID
= 1;
632 DevicePath
= AppendDevicePathNode (DevicePath
,
633 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
634 DevicePath
= AppendDevicePathNode (DevicePath
,
635 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
636 DevicePath
= AppendDevicePathNode (DevicePath
,
637 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
642 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
643 if (DevPathStr
!= NULL
) {
646 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
648 gPnp16550ComPortDeviceNode
.UID
+ 1,
651 FreePool(DevPathStr
);
654 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
655 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
656 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
663 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
664 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
669 EFI_HANDLE PciDeviceHandle
;
670 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
671 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
672 UINTN GopHandleCount
;
673 EFI_HANDLE
*GopHandleBuffer
;
675 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
676 return EFI_INVALID_PARAMETER
;
680 // Initialize the GopDevicePath to be PciDevicePath
682 *GopDevicePath
= PciDevicePath
;
683 TempPciDevicePath
= PciDevicePath
;
685 Status
= gBS
->LocateDevicePath (
686 &gEfiDevicePathProtocolGuid
,
690 if (EFI_ERROR (Status
)) {
695 // Try to connect this handle, so that GOP driver could start on this
696 // device and create child handles with GraphicsOutput Protocol installed
697 // on them, then we get device paths of these child handles and select
698 // them as possible console device.
700 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
702 Status
= gBS
->LocateHandleBuffer (
704 &gEfiGraphicsOutputProtocolGuid
,
709 if (!EFI_ERROR (Status
)) {
711 // Add all the child handles as possible Console Device
713 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
714 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
715 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
716 if (EFI_ERROR (Status
)) {
722 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
725 // In current implementation, we only enable one of the child handles
726 // as console device, i.e. sotre one of the child handle's device
727 // path to variable "ConOut"
728 // In future, we could select all child handles to be console device
731 *GopDevicePath
= TempDevicePath
;
734 // Delete the PCI device's path that added by
735 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
737 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
738 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
741 gBS
->FreePool (GopHandleBuffer
);
748 Add PCI display to ConOut.
750 @param[in] DeviceHandle Handle of the PCI display device.
752 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
754 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
758 PreparePciDisplayDevicePath (
759 IN EFI_HANDLE DeviceHandle
763 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
764 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
767 GopDevicePath
= NULL
;
768 Status
= gBS
->HandleProtocol (
770 &gEfiDevicePathProtocolGuid
,
773 if (EFI_ERROR (Status
)) {
777 GetGopDevicePath (DevicePath
, &GopDevicePath
);
778 DevicePath
= GopDevicePath
;
780 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
786 Add PCI Serial to ConOut, ConIn, ErrOut.
788 @param[in] DeviceHandle Handle of the PCI serial device.
790 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
793 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
797 PreparePciSerialDevicePath (
798 IN EFI_HANDLE DeviceHandle
802 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
805 Status
= gBS
->HandleProtocol (
807 &gEfiDevicePathProtocolGuid
,
810 if (EFI_ERROR (Status
)) {
814 DevicePath
= AppendDevicePathNode (DevicePath
,
815 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
816 DevicePath
= AppendDevicePathNode (DevicePath
,
817 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
819 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
820 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
821 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
827 VisitAllInstancesOfProtocol (
829 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
835 EFI_HANDLE
*HandleBuffer
;
840 // Start to check all the PciIo to find all possible device
844 Status
= gBS
->LocateHandleBuffer (
851 if (EFI_ERROR (Status
)) {
855 for (Index
= 0; Index
< HandleCount
; Index
++) {
856 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
857 if (EFI_ERROR (Status
)) {
861 Status
= (*CallBackFunction
) (
868 gBS
->FreePool (HandleBuffer
);
876 VisitingAPciInstance (
877 IN EFI_HANDLE Handle
,
883 EFI_PCI_IO_PROTOCOL
*PciIo
;
886 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
889 // Check for all PCI device
891 Status
= PciIo
->Pci
.Read (
895 sizeof (Pci
) / sizeof (UINT32
),
898 if (EFI_ERROR (Status
)) {
902 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
913 VisitAllPciInstances (
914 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
917 return VisitAllInstancesOfProtocol (
918 &gEfiPciIoProtocolGuid
,
919 VisitingAPciInstance
,
920 (VOID
*)(UINTN
) CallBackFunction
926 Do platform specific PCI Device check and add them to
927 ConOut, ConIn, ErrOut.
929 @param[in] Handle - Handle of PCI device instance
930 @param[in] PciIo - PCI IO protocol instance
931 @param[in] Pci - PCI Header register block
933 @retval EFI_SUCCESS - PCI Device check and Console variable update
935 @retval EFI_STATUS - PCI Device check or Console variable update fail.
940 DetectAndPreparePlatformPciDevicePath (
941 IN EFI_HANDLE Handle
,
942 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
948 Status
= PciIo
->Attributes (
950 EfiPciIoAttributeOperationEnable
,
951 EFI_PCI_DEVICE_ENABLE
,
954 ASSERT_EFI_ERROR (Status
);
957 // Here we decide whether it is LPC Bridge
959 if ((IS_PCI_LPC (Pci
)) ||
960 ((IS_PCI_ISA_PDECODE (Pci
)) &&
961 (Pci
->Hdr
.VendorId
== 0x8086) &&
962 (Pci
->Hdr
.DeviceId
== 0x7000)
966 // Add IsaKeyboard to ConIn,
967 // add IsaSerial to ConOut, ConIn, ErrOut
969 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
970 PrepareLpcBridgeDevicePath (Handle
);
974 // Here we decide which Serial device to enable in PCI bus
976 if (IS_PCI_16550SERIAL (Pci
)) {
978 // Add them to ConOut, ConIn, ErrOut.
980 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
981 PreparePciSerialDevicePath (Handle
);
986 // Here we decide which display device to enable in PCI bus
988 if (IS_PCI_DISPLAY (Pci
)) {
990 // Add them to ConOut.
992 DEBUG ((EFI_D_INFO
, "Found PCI display device\n"));
993 PreparePciDisplayDevicePath (Handle
);
1002 Connect the predefined platform default console device.
1004 Always try to find and enable PCI display devices.
1006 @param[in] PlatformConsole Predefined platform default console device array.
1009 PlatformInitializeConsole (
1010 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
1016 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1019 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
1022 // Have chance to connect the platform default console,
1023 // the platform default console is the minimum device group
1024 // the platform should support
1026 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1028 // Update the console variable with the connect type
1030 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1031 EfiBootManagerUpdateConsoleVariable (ConIn
,
1032 PlatformConsole
[Index
].DevicePath
, NULL
);
1034 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1035 EfiBootManagerUpdateConsoleVariable (ConOut
,
1036 PlatformConsole
[Index
].DevicePath
, NULL
);
1038 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1039 EfiBootManagerUpdateConsoleVariable (ErrOut
,
1040 PlatformConsole
[Index
].DevicePath
, NULL
);
1047 Configure PCI Interrupt Line register for applicable devices
1048 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1050 @param[in] Handle - Handle of PCI device instance
1051 @param[in] PciIo - PCI IO protocol instance
1052 @param[in] PciHdr - PCI Header register block
1054 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1060 IN EFI_HANDLE Handle
,
1061 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1062 IN PCI_TYPE00
*PciHdr
1065 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1066 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1071 UINT32 RootBusNumber
;
1073 Status
= EFI_SUCCESS
;
1075 if (PciHdr
->Device
.InterruptPin
!= 0) {
1077 DevPathNode
= DevicePathFromHandle (Handle
);
1078 ASSERT (DevPathNode
!= NULL
);
1079 DevPath
= DevPathNode
;
1082 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1083 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1084 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1085 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1089 // Compute index into PciHostIrqs[] table by walking
1090 // the device path and adding up all device numbers
1092 Status
= EFI_NOT_FOUND
;
1094 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1095 while (!IsDevicePathEnd (DevPathNode
)) {
1096 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1097 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1099 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1102 // Unlike SeaBIOS, which starts climbing from the leaf device
1103 // up toward the root, we traverse the device path starting at
1104 // the root moving toward the leaf node.
1105 // The slot number of the top-level parent bridge is needed for
1106 // Q35 cases with more than 24 slots on the root bus.
1108 if (Status
!= EFI_SUCCESS
) {
1109 Status
= EFI_SUCCESS
;
1110 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1114 DevPathNode
= NextDevicePathNode (DevPathNode
);
1116 if (EFI_ERROR (Status
)) {
1119 if (RootBusNumber
== 0 && RootSlot
== 0) {
1122 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1129 // Final PciHostIrqs[] index calculation depends on the platform
1130 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1132 switch (mHostBridgeDevId
) {
1133 case INTEL_82441_DEVICE_ID
:
1136 case INTEL_Q35_MCH_DEVICE_ID
:
1138 // SeaBIOS contains the following comment:
1139 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1140 // with a different starting index - see q35-acpi-dsdt.dsl.
1142 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1144 if (RootSlot
> 24) {
1146 // in this case, subtract back out RootSlot from Idx
1147 // (SeaBIOS never adds it to begin with, but that would make our
1148 // device path traversal loop above too awkward)
1154 ASSERT (FALSE
); // should never get here
1156 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1157 IrqLine
= PciHostIrqs
[Idx
];
1159 DEBUG_CODE_BEGIN ();
1161 CHAR16
*DevPathString
;
1162 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1163 UINTN Segment
, Bus
, Device
, Function
;
1165 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1166 if (DevPathString
== NULL
) {
1167 DevPathString
= Fallback
;
1169 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1170 ASSERT_EFI_ERROR (Status
);
1172 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1173 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1176 if (DevPathString
!= Fallback
) {
1177 FreePool (DevPathString
);
1183 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1185 Status
= PciIo
->Pci
.Write (
1188 PCI_INT_LINE_OFFSET
,
1199 PciAcpiInitialization (
1205 // Query Host Bridge DID to determine platform type
1207 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1208 switch (mHostBridgeDevId
) {
1209 case INTEL_82441_DEVICE_ID
:
1210 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1212 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1214 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1215 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1216 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1217 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1219 case INTEL_Q35_MCH_DEVICE_ID
:
1220 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1222 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1224 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1225 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1226 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1227 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1228 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1229 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1230 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1231 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1234 if (XenDetected ()) {
1236 // There is no PCI bus in this case.
1240 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1241 __FUNCTION__
, mHostBridgeDevId
));
1247 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1249 VisitAllPciInstances (SetPciIntLine
);
1252 // Set ACPI SCI_EN bit in PMCNTRL
1254 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1259 ConnectRecursivelyIfPciMassStorage (
1260 IN EFI_HANDLE Handle
,
1261 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1262 IN PCI_TYPE00
*PciHeader
1266 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1270 // Recognize PCI Mass Storage, and Xen PCI devices
1272 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1273 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1275 Status
= gBS
->HandleProtocol (
1277 &gEfiDevicePathProtocolGuid
,
1280 if (EFI_ERROR (Status
)) {
1285 // Print Device Path
1287 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1288 if (DevPathStr
!= NULL
) {
1291 "Found %s device: %s\n",
1292 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1298 FreePool(DevPathStr
);
1301 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1302 if (EFI_ERROR (Status
)) {
1313 This notification function is invoked when the
1314 EMU Variable FVB has been changed.
1316 @param Event The event that occurred
1317 @param Context For EFI compatibility. Not used.
1322 EmuVariablesUpdatedCallback (
1327 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1328 UpdateNvVarsOnFileSystem ();
1334 VisitingFileSystemInstance (
1335 IN EFI_HANDLE Handle
,
1341 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1342 RETURN_STATUS PcdStatus
;
1344 if (ConnectedToFileSystem
) {
1345 return EFI_ALREADY_STARTED
;
1348 Status
= ConnectNvVarsToFileSystem (Handle
);
1349 if (EFI_ERROR (Status
)) {
1353 ConnectedToFileSystem
= TRUE
;
1355 EfiCreateProtocolNotifyEvent (
1356 &gEfiDevicePathProtocolGuid
,
1358 EmuVariablesUpdatedCallback
,
1360 &mEmuVariableEventReg
1362 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1363 (UINT64
)(UINTN
) mEmuVariableEvent
);
1364 ASSERT_RETURN_ERROR (PcdStatus
);
1371 PlatformBdsRestoreNvVarsFromHardDisk (
1374 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1375 VisitAllInstancesOfProtocol (
1376 &gEfiSimpleFileSystemProtocolGuid
,
1377 VisitingFileSystemInstance
,
1384 Connect with predefined platform connect sequence.
1386 The OEM/IBV can customize with their own connect sequence.
1389 PlatformBdsConnectSequence (
1394 RETURN_STATUS Status
;
1396 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1401 // Here we can get the customized platform connect sequence
1402 // Notes: we can connect with new variable which record the
1403 // last time boots connect device path sequence
1405 while (gPlatformConnectSequence
[Index
] != NULL
) {
1407 // Build the platform boot option
1409 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1413 Status
= ConnectDevicesFromQemu ();
1414 if (RETURN_ERROR (Status
)) {
1416 // Just use the simple policy to connect all devices
1418 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1419 EfiBootManagerConnectAll ();
1424 Save the S3 boot script.
1426 Note that DxeSmmReadyToLock must be signaled after this function returns;
1427 otherwise the script wouldn't be saved actually.
1436 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1437 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1439 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1440 (VOID
**) &BootScript
);
1441 ASSERT_EFI_ERROR (Status
);
1444 // Despite the opcode documentation in the PI spec, the protocol
1445 // implementation embeds a deep copy of the info in the boot script, rather
1446 // than storing just a pointer to runtime or NVS storage.
1448 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1449 (UINT32
) sizeof Info
,
1450 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1451 ASSERT_EFI_ERROR (Status
);
1456 Do the platform specific action after the console is ready
1458 Possible things that can be done in PlatformBootManagerAfterConsole:
1460 > Console post action:
1461 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1462 > Signal console ready platform customized event
1463 > Run diagnostics like memory testing
1464 > Connect certain devices
1465 > Dispatch aditional option roms
1466 > Special boot: e.g.: USB boot, enter UI
1470 PlatformBootManagerAfterConsole (
1474 EFI_BOOT_MODE BootMode
;
1476 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1478 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1479 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1480 "from disk since flash variables appear to be supported.\n"));
1483 // Try to restore variables from the hard disk early so
1484 // they can be used for the other BDS connect operations.
1486 PlatformBdsRestoreNvVarsFromHardDisk ();
1490 // Get current Boot Mode
1492 BootMode
= GetBootModeHob ();
1493 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1496 // Go the different platform policy with different boot mode
1497 // Notes: this part code can be change with the table policy
1499 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1504 BootLogoEnableLogo ();
1507 // Set PCI Interrupt Line registers and ACPI SCI_EN
1509 PciAcpiInitialization ();
1512 // Process TPM PPI request
1514 Tcg2PhysicalPresenceLibProcessRequest (NULL
);
1517 // Process QEMU's -kernel command line option
1519 TryRunningQemuKernel ();
1522 // Perform some platform specific connect sequence
1524 PlatformBdsConnectSequence ();
1526 EfiBootManagerRefreshAllBootOption ();
1529 // Register UEFI Shell
1531 PlatformRegisterFvBootOption (
1532 &gUefiShellFileGuid
, L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1535 RemoveStaleFvFileOptions ();
1536 SetBootOrderFromQemu ();
1538 PlatformBmPrintScRegisterHandler ();
1542 This notification function is invoked when an instance of the
1543 EFI_DEVICE_PATH_PROTOCOL is produced.
1545 @param Event The event that occurred
1546 @param Context For EFI compatibility. Not used.
1559 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1560 ATAPI_DEVICE_PATH
*Atapi
;
1563 // Examine all new handles
1567 // Get the next handle
1569 BufferSize
= sizeof (Handle
);
1570 Status
= gBS
->LocateHandle (
1573 mEfiDevPathNotifyReg
,
1579 // If not found, we're done
1581 if (EFI_NOT_FOUND
== Status
) {
1585 if (EFI_ERROR (Status
)) {
1590 // Get the DevicePath protocol on that handle
1592 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1593 (VOID
**)&DevPathNode
);
1594 ASSERT_EFI_ERROR (Status
);
1596 while (!IsDevicePathEnd (DevPathNode
)) {
1598 // Find the handler to dump this device path node
1601 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1602 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1604 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1610 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1617 // Next device path node
1619 DevPathNode
= NextDevicePathNode (DevPathNode
);
1628 InstallDevicePathCallback (
1632 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1633 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1634 &gEfiDevicePathProtocolGuid
,
1638 &mEfiDevPathNotifyReg
1643 This function is called each second during the boot manager waits the
1646 @param TimeoutRemain The remaining timeout.
1650 PlatformBootManagerWaitCallback (
1651 UINT16 TimeoutRemain
1654 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1655 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1656 UINT16 TimeoutInitial
;
1658 TimeoutInitial
= PcdGet16 (PcdPlatformBootTimeOut
);
1661 // If PcdPlatformBootTimeOut is set to zero, then we consider
1662 // that no progress update should be enacted (since we'd only
1663 // ever display a one-shot progress of either 0% or 100%).
1665 if (TimeoutInitial
== 0) {
1669 Black
.Raw
= 0x00000000;
1670 White
.Raw
= 0x00FFFFFF;
1672 BootLogoUpdateProgress (
1675 L
"Start boot option",
1677 (TimeoutInitial
- TimeoutRemain
) * 100 / TimeoutInitial
,
1683 The function is called when no boot option could be launched,
1684 including platform recovery options and options pointing to applications
1685 built into firmware volumes.
1687 If this function returns, BDS attempts to enter an infinite loop.
1691 PlatformBootManagerUnableToBoot (
1697 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu
;
1701 // BootManagerMenu doesn't contain the correct information when return status
1702 // is EFI_NOT_FOUND.
1704 Status
= EfiBootManagerGetBootManagerMenu (&BootManagerMenu
);
1705 if (EFI_ERROR (Status
)) {
1709 // Normally BdsDxe does not print anything to the system console, but this is
1710 // a last resort -- the end-user will likely not see any DEBUG messages
1711 // logged in this situation.
1713 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1714 // here to see if it makes sense to request and wait for a keypress.
1716 if (gST
->ConIn
!= NULL
) {
1718 "%a: No bootable option or device was found.\n"
1719 "%a: Press any key to enter the Boot Manager Menu.\n",
1723 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &Index
);
1724 ASSERT_EFI_ERROR (Status
);
1725 ASSERT (Index
== 0);
1728 // Drain any queued keys.
1730 while (!EFI_ERROR (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
))) {
1732 // just throw away Key
1738 EfiBootManagerBoot (&BootManagerMenu
);