2 Platform BDS customizations.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
11 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "BdsPlatform.h"
16 #include <Guid/XenInfo.h>
17 #include <Guid/RootBridgesConnectedEventGroup.h>
18 #include <Protocol/FirmwareVolume2.h>
19 #include <Library/PlatformBmPrintScLib.h>
20 #include <Library/Tcg2PhysicalPresenceLib.h>
27 VOID
*mEfiDevPathNotifyReg
;
28 EFI_EVENT mEfiDevPathEvent
;
29 VOID
*mEmuVariableEventReg
;
30 EFI_EVENT mEmuVariableEvent
;
31 UINT16 mHostBridgeDevId
;
34 // Table of host IRQs matching PCI IRQs A-D
35 // (for configuring PCI Interrupt Line register)
37 CONST UINT8 PciHostIrqs
[] = {
38 0x0a, 0x0a, 0x0b, 0x0b
47 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
54 @param[in] Handle - Handle of PCI device instance
55 @param[in] PciIo - PCI IO protocol instance
56 @param[in] Pci - PCI Header register block
60 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
62 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
68 // Function prototypes
72 VisitAllInstancesOfProtocol (
74 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
79 VisitAllPciInstancesOfProtocol (
80 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
84 InstallDevicePathCallback (
89 PlatformRegisterFvBootOption (
97 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
98 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
99 UINTN BootOptionCount
;
100 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
101 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
102 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
104 Status
= gBS
->HandleProtocol (
106 &gEfiLoadedImageProtocolGuid
,
107 (VOID
**) &LoadedImage
109 ASSERT_EFI_ERROR (Status
);
111 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
112 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
113 ASSERT (DevicePath
!= NULL
);
114 DevicePath
= AppendDevicePathNode (
116 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
118 ASSERT (DevicePath
!= NULL
);
120 Status
= EfiBootManagerInitializeLoadOption (
122 LoadOptionNumberUnassigned
,
130 ASSERT_EFI_ERROR (Status
);
131 FreePool (DevicePath
);
133 BootOptions
= EfiBootManagerGetLoadOptions (
134 &BootOptionCount
, LoadOptionTypeBoot
137 OptionIndex
= EfiBootManagerFindLoadOption (
138 &NewOption
, BootOptions
, BootOptionCount
141 if (OptionIndex
== -1) {
142 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
143 ASSERT_EFI_ERROR (Status
);
145 EfiBootManagerFreeLoadOption (&NewOption
);
146 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
150 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
151 whose device paths do not resolve exactly to an FvFile in the system.
153 This removes any boot options that point to binaries built into the firmware
154 and have become stale due to any of the following:
155 - DXEFV's base address or size changed (historical),
156 - DXEFV's FvNameGuid changed,
157 - the FILE_GUID of the pointed-to binary changed,
158 - the referenced binary is no longer built into the firmware.
160 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
161 avoids exact duplicates.
164 RemoveStaleFvFileOptions (
168 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
169 UINTN BootOptionCount
;
172 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
,
175 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
176 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
181 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
182 // then keep the boot option.
184 Node1
= BootOptions
[Index
].FilePath
;
185 if (!(DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
&&
186 DevicePathSubType (Node1
) == HW_MEMMAP_DP
) &&
187 !(DevicePathType (Node1
) == MEDIA_DEVICE_PATH
&&
188 DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)) {
193 // If the second device path node is not FvFile(...), then keep the boot
196 Node2
= NextDevicePathNode (Node1
);
197 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
198 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
203 // Locate the Firmware Volume2 protocol instance that is denoted by the
204 // boot option. If this lookup fails (i.e., the boot option references a
205 // firmware volume that doesn't exist), then we'll proceed to delete the
209 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
,
210 &SearchNode
, &FvHandle
);
212 if (!EFI_ERROR (Status
)) {
214 // The firmware volume was found; now let's see if it contains the FvFile
215 // identified by GUID.
217 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
218 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
220 EFI_FV_FILETYPE FoundType
;
221 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
222 UINT32 AuthenticationStatus
;
224 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
,
225 (VOID
**)&FvProtocol
);
226 ASSERT_EFI_ERROR (Status
);
228 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
230 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
233 Status
= FvProtocol
->ReadFile (
235 &FvFileNode
->FvFileName
, // NameGuid
240 &AuthenticationStatus
242 if (!EFI_ERROR (Status
)) {
244 // The FvFile was found. Keep the boot option.
251 // Delete the boot option.
253 Status
= EfiBootManagerDeleteLoadOptionVariable (
254 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
256 CHAR16
*DevicePathString
;
258 DevicePathString
= ConvertDevicePathToText(BootOptions
[Index
].FilePath
,
261 EFI_ERROR (Status
) ? EFI_D_WARN
: EFI_D_VERBOSE
,
262 "%a: removing stale Boot#%04x %s: %r\n",
264 (UINT32
)BootOptions
[Index
].OptionNumber
,
265 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
268 if (DevicePathString
!= NULL
) {
269 FreePool (DevicePathString
);
274 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
278 PlatformRegisterOptionsAndKeys (
286 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
289 // Register ENTER as CONTINUE key
291 Enter
.ScanCode
= SCAN_NULL
;
292 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
293 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
294 ASSERT_EFI_ERROR (Status
);
297 // Map F2 to Boot Manager Menu
299 F2
.ScanCode
= SCAN_F2
;
300 F2
.UnicodeChar
= CHAR_NULL
;
301 Esc
.ScanCode
= SCAN_ESC
;
302 Esc
.UnicodeChar
= CHAR_NULL
;
303 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
304 ASSERT_EFI_ERROR (Status
);
305 Status
= EfiBootManagerAddKeyOptionVariable (
306 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
308 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
309 Status
= EfiBootManagerAddKeyOptionVariable (
310 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
312 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
318 IN EFI_HANDLE RootBridgeHandle
,
326 ConnectVirtioPciRng (
327 IN EFI_HANDLE Handle
,
339 // BDS Platform Functions
342 Do the platform init, can be customized by OEM/IBV
344 Possible things that can be done in PlatformBootManagerBeforeConsole:
346 > Update console variable: 1. include hot-plug devices;
347 > 2. Clear ConIn and add SOL for AMT
348 > Register new Driver#### or Boot####
349 > Register new Key####: e.g.: F12
350 > Signal ReadyToLock event
351 > Authentication action: 1. connect Auth devices;
352 > 2. Identify auto logon user.
356 PlatformBootManagerBeforeConsole (
362 RETURN_STATUS PcdStatus
;
364 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
365 InstallDevicePathCallback ();
367 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
368 ConnectRootBridge
, NULL
);
371 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
373 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
376 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
377 // the preparation of S3 system information. That logic has a hard dependency
378 // on the presence of the FACS ACPI table. Since our ACPI tables are only
379 // installed after PCI enumeration completes, we must not trigger the S3 save
380 // earlier, hence we can't signal End-of-Dxe earlier.
382 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
384 if (QemuFwCfgS3Enabled ()) {
386 // Save the boot script too. Note that this will require us to emit the
387 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
393 // Prevent further changes to LockBoxes or SMRAM.
396 Status
= gBS
->InstallProtocolInterface (&Handle
,
397 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
399 ASSERT_EFI_ERROR (Status
);
402 // Dispatch deferred images after EndOfDxe event and ReadyToLock
405 EfiBootManagerDispatchDeferredImages ();
407 PlatformInitializeConsole (gPlatformConsole
);
408 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
,
409 GetFrontPageTimeoutFromQemu ());
410 ASSERT_RETURN_ERROR (PcdStatus
);
412 PlatformRegisterOptionsAndKeys ();
415 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
416 // instances on Virtio PCI RNG devices.
418 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
426 IN EFI_HANDLE RootBridgeHandle
,
434 // Make the PCI bus driver connect the root bridge, non-recursively. This
435 // will produce a number of child handles with PciIo on them.
437 Status
= gBS
->ConnectController (
438 RootBridgeHandle
, // ControllerHandle
439 NULL
, // DriverImageHandle
440 NULL
, // RemainingDevicePath -- produce all
451 ConnectVirtioPciRng (
452 IN EFI_HANDLE Handle
,
457 EFI_PCI_IO_PROTOCOL
*PciIo
;
468 // Read and check VendorId.
470 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
472 if (EFI_ERROR (Status
)) {
475 if (VendorId
!= VIRTIO_VENDOR_ID
) {
480 // Read DeviceId and RevisionId.
482 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
484 if (EFI_ERROR (Status
)) {
487 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
489 if (EFI_ERROR (Status
)) {
494 // From DeviceId and RevisionId, determine whether the device is a
495 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
496 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
497 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
498 // only be sanity-checked, and SubsystemId will decide.
500 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
501 RevisionId
>= 0x01) {
503 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
510 // Read and check SubsystemId as dictated by Virtio10.
512 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
513 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
514 if (EFI_ERROR (Status
)) {
517 if ((Virtio10
&& SubsystemId
>= 0x40) ||
518 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
519 Status
= gBS
->ConnectController (
520 Handle
, // ControllerHandle
521 NULL
, // DriverImageHandle -- connect all drivers
522 NULL
, // RemainingDevicePath -- produce all child handles
523 FALSE
// Recursive -- don't follow child handles
525 if (EFI_ERROR (Status
)) {
532 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
538 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
540 @param[in] DeviceHandle Handle of the LPC Bridge device.
542 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
543 ConOut, ConIn, and ErrOut.
545 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
549 PrepareLpcBridgeDevicePath (
550 IN EFI_HANDLE DeviceHandle
554 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
555 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
559 Status
= gBS
->HandleProtocol (
561 &gEfiDevicePathProtocolGuid
,
564 if (EFI_ERROR (Status
)) {
567 TempDevicePath
= DevicePath
;
572 DevicePath
= AppendDevicePathNode (DevicePath
,
573 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
575 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
580 DevicePath
= TempDevicePath
;
581 gPnp16550ComPortDeviceNode
.UID
= 0;
583 DevicePath
= AppendDevicePathNode (DevicePath
,
584 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
585 DevicePath
= AppendDevicePathNode (DevicePath
,
586 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
587 DevicePath
= AppendDevicePathNode (DevicePath
,
588 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
593 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
594 if (DevPathStr
!= NULL
) {
597 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
599 gPnp16550ComPortDeviceNode
.UID
+ 1,
602 FreePool(DevPathStr
);
605 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
606 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
607 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
612 DevicePath
= TempDevicePath
;
613 gPnp16550ComPortDeviceNode
.UID
= 1;
615 DevicePath
= AppendDevicePathNode (DevicePath
,
616 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
617 DevicePath
= AppendDevicePathNode (DevicePath
,
618 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
619 DevicePath
= AppendDevicePathNode (DevicePath
,
620 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
625 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
626 if (DevPathStr
!= NULL
) {
629 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
631 gPnp16550ComPortDeviceNode
.UID
+ 1,
634 FreePool(DevPathStr
);
637 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
638 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
639 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
646 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
647 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
652 EFI_HANDLE PciDeviceHandle
;
653 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
654 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
655 UINTN GopHandleCount
;
656 EFI_HANDLE
*GopHandleBuffer
;
658 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
659 return EFI_INVALID_PARAMETER
;
663 // Initialize the GopDevicePath to be PciDevicePath
665 *GopDevicePath
= PciDevicePath
;
666 TempPciDevicePath
= PciDevicePath
;
668 Status
= gBS
->LocateDevicePath (
669 &gEfiDevicePathProtocolGuid
,
673 if (EFI_ERROR (Status
)) {
678 // Try to connect this handle, so that GOP driver could start on this
679 // device and create child handles with GraphicsOutput Protocol installed
680 // on them, then we get device paths of these child handles and select
681 // them as possible console device.
683 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
685 Status
= gBS
->LocateHandleBuffer (
687 &gEfiGraphicsOutputProtocolGuid
,
692 if (!EFI_ERROR (Status
)) {
694 // Add all the child handles as possible Console Device
696 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
697 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
698 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
699 if (EFI_ERROR (Status
)) {
705 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
708 // In current implementation, we only enable one of the child handles
709 // as console device, i.e. sotre one of the child handle's device
710 // path to variable "ConOut"
711 // In future, we could select all child handles to be console device
714 *GopDevicePath
= TempDevicePath
;
717 // Delete the PCI device's path that added by
718 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
720 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
721 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
724 gBS
->FreePool (GopHandleBuffer
);
731 Add PCI display to ConOut.
733 @param[in] DeviceHandle Handle of the PCI display device.
735 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
737 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
741 PreparePciDisplayDevicePath (
742 IN EFI_HANDLE DeviceHandle
746 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
747 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
750 GopDevicePath
= NULL
;
751 Status
= gBS
->HandleProtocol (
753 &gEfiDevicePathProtocolGuid
,
756 if (EFI_ERROR (Status
)) {
760 GetGopDevicePath (DevicePath
, &GopDevicePath
);
761 DevicePath
= GopDevicePath
;
763 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
769 Add PCI Serial to ConOut, ConIn, ErrOut.
771 @param[in] DeviceHandle Handle of the PCI serial device.
773 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
776 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
780 PreparePciSerialDevicePath (
781 IN EFI_HANDLE DeviceHandle
785 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
788 Status
= gBS
->HandleProtocol (
790 &gEfiDevicePathProtocolGuid
,
793 if (EFI_ERROR (Status
)) {
797 DevicePath
= AppendDevicePathNode (DevicePath
,
798 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
799 DevicePath
= AppendDevicePathNode (DevicePath
,
800 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
802 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
803 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
804 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
810 VisitAllInstancesOfProtocol (
812 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
818 EFI_HANDLE
*HandleBuffer
;
823 // Start to check all the PciIo to find all possible device
827 Status
= gBS
->LocateHandleBuffer (
834 if (EFI_ERROR (Status
)) {
838 for (Index
= 0; Index
< HandleCount
; Index
++) {
839 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
840 if (EFI_ERROR (Status
)) {
844 Status
= (*CallBackFunction
) (
851 gBS
->FreePool (HandleBuffer
);
859 VisitingAPciInstance (
860 IN EFI_HANDLE Handle
,
866 EFI_PCI_IO_PROTOCOL
*PciIo
;
869 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
872 // Check for all PCI device
874 Status
= PciIo
->Pci
.Read (
878 sizeof (Pci
) / sizeof (UINT32
),
881 if (EFI_ERROR (Status
)) {
885 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
896 VisitAllPciInstances (
897 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
900 return VisitAllInstancesOfProtocol (
901 &gEfiPciIoProtocolGuid
,
902 VisitingAPciInstance
,
903 (VOID
*)(UINTN
) CallBackFunction
909 Do platform specific PCI Device check and add them to
910 ConOut, ConIn, ErrOut.
912 @param[in] Handle - Handle of PCI device instance
913 @param[in] PciIo - PCI IO protocol instance
914 @param[in] Pci - PCI Header register block
916 @retval EFI_SUCCESS - PCI Device check and Console variable update
918 @retval EFI_STATUS - PCI Device check or Console variable update fail.
923 DetectAndPreparePlatformPciDevicePath (
924 IN EFI_HANDLE Handle
,
925 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
931 Status
= PciIo
->Attributes (
933 EfiPciIoAttributeOperationEnable
,
934 EFI_PCI_DEVICE_ENABLE
,
937 ASSERT_EFI_ERROR (Status
);
940 // Here we decide whether it is LPC Bridge
942 if ((IS_PCI_LPC (Pci
)) ||
943 ((IS_PCI_ISA_PDECODE (Pci
)) &&
944 (Pci
->Hdr
.VendorId
== 0x8086) &&
945 (Pci
->Hdr
.DeviceId
== 0x7000)
949 // Add IsaKeyboard to ConIn,
950 // add IsaSerial to ConOut, ConIn, ErrOut
952 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
953 PrepareLpcBridgeDevicePath (Handle
);
957 // Here we decide which Serial device to enable in PCI bus
959 if (IS_PCI_16550SERIAL (Pci
)) {
961 // Add them to ConOut, ConIn, ErrOut.
963 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
964 PreparePciSerialDevicePath (Handle
);
969 // Here we decide which display device to enable in PCI bus
971 if (IS_PCI_DISPLAY (Pci
)) {
973 // Add them to ConOut.
975 DEBUG ((EFI_D_INFO
, "Found PCI display device\n"));
976 PreparePciDisplayDevicePath (Handle
);
985 Connect the predefined platform default console device.
987 Always try to find and enable PCI display devices.
989 @param[in] PlatformConsole Predefined platform default console device array.
992 PlatformInitializeConsole (
993 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
999 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1002 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
1005 // Have chance to connect the platform default console,
1006 // the platform default console is the minimum device group
1007 // the platform should support
1009 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1011 // Update the console variable with the connect type
1013 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1014 EfiBootManagerUpdateConsoleVariable (ConIn
,
1015 PlatformConsole
[Index
].DevicePath
, NULL
);
1017 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1018 EfiBootManagerUpdateConsoleVariable (ConOut
,
1019 PlatformConsole
[Index
].DevicePath
, NULL
);
1021 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1022 EfiBootManagerUpdateConsoleVariable (ErrOut
,
1023 PlatformConsole
[Index
].DevicePath
, NULL
);
1030 Configure PCI Interrupt Line register for applicable devices
1031 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1033 @param[in] Handle - Handle of PCI device instance
1034 @param[in] PciIo - PCI IO protocol instance
1035 @param[in] PciHdr - PCI Header register block
1037 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1043 IN EFI_HANDLE Handle
,
1044 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1045 IN PCI_TYPE00
*PciHdr
1048 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1049 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1054 UINT32 RootBusNumber
;
1056 Status
= EFI_SUCCESS
;
1058 if (PciHdr
->Device
.InterruptPin
!= 0) {
1060 DevPathNode
= DevicePathFromHandle (Handle
);
1061 ASSERT (DevPathNode
!= NULL
);
1062 DevPath
= DevPathNode
;
1065 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1066 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1067 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1068 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1072 // Compute index into PciHostIrqs[] table by walking
1073 // the device path and adding up all device numbers
1075 Status
= EFI_NOT_FOUND
;
1077 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1078 while (!IsDevicePathEnd (DevPathNode
)) {
1079 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1080 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1082 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1085 // Unlike SeaBIOS, which starts climbing from the leaf device
1086 // up toward the root, we traverse the device path starting at
1087 // the root moving toward the leaf node.
1088 // The slot number of the top-level parent bridge is needed for
1089 // Q35 cases with more than 24 slots on the root bus.
1091 if (Status
!= EFI_SUCCESS
) {
1092 Status
= EFI_SUCCESS
;
1093 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1097 DevPathNode
= NextDevicePathNode (DevPathNode
);
1099 if (EFI_ERROR (Status
)) {
1102 if (RootBusNumber
== 0 && RootSlot
== 0) {
1105 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1112 // Final PciHostIrqs[] index calculation depends on the platform
1113 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1115 switch (mHostBridgeDevId
) {
1116 case INTEL_82441_DEVICE_ID
:
1119 case INTEL_Q35_MCH_DEVICE_ID
:
1121 // SeaBIOS contains the following comment:
1122 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1123 // with a different starting index - see q35-acpi-dsdt.dsl.
1125 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1127 if (RootSlot
> 24) {
1129 // in this case, subtract back out RootSlot from Idx
1130 // (SeaBIOS never adds it to begin with, but that would make our
1131 // device path traversal loop above too awkward)
1137 ASSERT (FALSE
); // should never get here
1139 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1140 IrqLine
= PciHostIrqs
[Idx
];
1142 DEBUG_CODE_BEGIN ();
1144 CHAR16
*DevPathString
;
1145 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1146 UINTN Segment
, Bus
, Device
, Function
;
1148 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1149 if (DevPathString
== NULL
) {
1150 DevPathString
= Fallback
;
1152 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1153 ASSERT_EFI_ERROR (Status
);
1155 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1156 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1159 if (DevPathString
!= Fallback
) {
1160 FreePool (DevPathString
);
1166 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1168 Status
= PciIo
->Pci
.Write (
1171 PCI_INT_LINE_OFFSET
,
1182 PciAcpiInitialization (
1188 // Query Host Bridge DID to determine platform type
1190 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1191 switch (mHostBridgeDevId
) {
1192 case INTEL_82441_DEVICE_ID
:
1193 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1195 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1197 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1198 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1199 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1200 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1202 case INTEL_Q35_MCH_DEVICE_ID
:
1203 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1205 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1207 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1208 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1209 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1210 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1211 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1212 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1213 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1214 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1217 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1218 __FUNCTION__
, mHostBridgeDevId
));
1224 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1226 VisitAllPciInstances (SetPciIntLine
);
1229 // Set ACPI SCI_EN bit in PMCNTRL
1231 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1235 This function detects if OVMF is running on Xen.
1244 EFI_HOB_GUID_TYPE
*GuidHob
;
1245 STATIC INTN FoundHob
= -1;
1247 if (FoundHob
== 0) {
1249 } else if (FoundHob
== 1) {
1254 // See if a XenInfo HOB is available
1256 GuidHob
= GetFirstGuidHob (&gEfiXenInfoGuid
);
1257 if (GuidHob
== NULL
) {
1268 ConnectRecursivelyIfPciMassStorage (
1269 IN EFI_HANDLE Handle
,
1270 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1271 IN PCI_TYPE00
*PciHeader
1275 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1279 // Recognize PCI Mass Storage, and Xen PCI devices
1281 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1282 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1284 Status
= gBS
->HandleProtocol (
1286 &gEfiDevicePathProtocolGuid
,
1289 if (EFI_ERROR (Status
)) {
1294 // Print Device Path
1296 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1297 if (DevPathStr
!= NULL
) {
1300 "Found %s device: %s\n",
1301 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1307 FreePool(DevPathStr
);
1310 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1311 if (EFI_ERROR (Status
)) {
1322 This notification function is invoked when the
1323 EMU Variable FVB has been changed.
1325 @param Event The event that occurred
1326 @param Context For EFI compatibility. Not used.
1331 EmuVariablesUpdatedCallback (
1336 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1337 UpdateNvVarsOnFileSystem ();
1343 VisitingFileSystemInstance (
1344 IN EFI_HANDLE Handle
,
1350 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1351 RETURN_STATUS PcdStatus
;
1353 if (ConnectedToFileSystem
) {
1354 return EFI_ALREADY_STARTED
;
1357 Status
= ConnectNvVarsToFileSystem (Handle
);
1358 if (EFI_ERROR (Status
)) {
1362 ConnectedToFileSystem
= TRUE
;
1364 EfiCreateProtocolNotifyEvent (
1365 &gEfiDevicePathProtocolGuid
,
1367 EmuVariablesUpdatedCallback
,
1369 &mEmuVariableEventReg
1371 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1372 (UINT64
)(UINTN
) mEmuVariableEvent
);
1373 ASSERT_RETURN_ERROR (PcdStatus
);
1380 PlatformBdsRestoreNvVarsFromHardDisk (
1383 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1384 VisitAllInstancesOfProtocol (
1385 &gEfiSimpleFileSystemProtocolGuid
,
1386 VisitingFileSystemInstance
,
1393 Connect with predefined platform connect sequence.
1395 The OEM/IBV can customize with their own connect sequence.
1398 PlatformBdsConnectSequence (
1403 RETURN_STATUS Status
;
1405 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1410 // Here we can get the customized platform connect sequence
1411 // Notes: we can connect with new variable which record the
1412 // last time boots connect device path sequence
1414 while (gPlatformConnectSequence
[Index
] != NULL
) {
1416 // Build the platform boot option
1418 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1422 Status
= ConnectDevicesFromQemu ();
1423 if (RETURN_ERROR (Status
)) {
1425 // Just use the simple policy to connect all devices
1427 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1428 EfiBootManagerConnectAll ();
1433 Save the S3 boot script.
1435 Note that DxeSmmReadyToLock must be signaled after this function returns;
1436 otherwise the script wouldn't be saved actually.
1445 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1446 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1448 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1449 (VOID
**) &BootScript
);
1450 ASSERT_EFI_ERROR (Status
);
1453 // Despite the opcode documentation in the PI spec, the protocol
1454 // implementation embeds a deep copy of the info in the boot script, rather
1455 // than storing just a pointer to runtime or NVS storage.
1457 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1458 (UINT32
) sizeof Info
,
1459 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1460 ASSERT_EFI_ERROR (Status
);
1465 Do the platform specific action after the console is ready
1467 Possible things that can be done in PlatformBootManagerAfterConsole:
1469 > Console post action:
1470 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1471 > Signal console ready platform customized event
1472 > Run diagnostics like memory testing
1473 > Connect certain devices
1474 > Dispatch aditional option roms
1475 > Special boot: e.g.: USB boot, enter UI
1479 PlatformBootManagerAfterConsole (
1483 EFI_BOOT_MODE BootMode
;
1485 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1487 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1488 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1489 "from disk since flash variables appear to be supported.\n"));
1492 // Try to restore variables from the hard disk early so
1493 // they can be used for the other BDS connect operations.
1495 PlatformBdsRestoreNvVarsFromHardDisk ();
1499 // Get current Boot Mode
1501 BootMode
= GetBootModeHob ();
1502 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1505 // Go the different platform policy with different boot mode
1506 // Notes: this part code can be change with the table policy
1508 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1513 BootLogoEnableLogo ();
1516 // Set PCI Interrupt Line registers and ACPI SCI_EN
1518 PciAcpiInitialization ();
1521 // Process TPM PPI request
1523 Tcg2PhysicalPresenceLibProcessRequest (NULL
);
1526 // Process QEMU's -kernel command line option
1528 TryRunningQemuKernel ();
1531 // Perform some platform specific connect sequence
1533 PlatformBdsConnectSequence ();
1535 EfiBootManagerRefreshAllBootOption ();
1538 // Register UEFI Shell
1540 PlatformRegisterFvBootOption (
1541 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1544 RemoveStaleFvFileOptions ();
1545 SetBootOrderFromQemu ();
1547 PlatformBmPrintScRegisterHandler ();
1551 This notification function is invoked when an instance of the
1552 EFI_DEVICE_PATH_PROTOCOL is produced.
1554 @param Event The event that occurred
1555 @param Context For EFI compatibility. Not used.
1568 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1569 ATAPI_DEVICE_PATH
*Atapi
;
1572 // Examine all new handles
1576 // Get the next handle
1578 BufferSize
= sizeof (Handle
);
1579 Status
= gBS
->LocateHandle (
1582 mEfiDevPathNotifyReg
,
1588 // If not found, we're done
1590 if (EFI_NOT_FOUND
== Status
) {
1594 if (EFI_ERROR (Status
)) {
1599 // Get the DevicePath protocol on that handle
1601 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1602 (VOID
**)&DevPathNode
);
1603 ASSERT_EFI_ERROR (Status
);
1605 while (!IsDevicePathEnd (DevPathNode
)) {
1607 // Find the handler to dump this device path node
1610 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1611 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1613 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1619 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1626 // Next device path node
1628 DevPathNode
= NextDevicePathNode (DevPathNode
);
1637 InstallDevicePathCallback (
1641 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1642 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1643 &gEfiDevicePathProtocolGuid
,
1647 &mEfiDevPathNotifyReg
1652 This function is called each second during the boot manager waits the
1655 @param TimeoutRemain The remaining timeout.
1659 PlatformBootManagerWaitCallback (
1660 UINT16 TimeoutRemain
1663 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1664 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1667 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1669 Black
.Raw
= 0x00000000;
1670 White
.Raw
= 0x00FFFFFF;
1672 BootLogoUpdateProgress (
1675 L
"Start boot option",
1677 (Timeout
- TimeoutRemain
) * 100 / Timeout
,
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
);