2 Platform BDS customizations.
4 Copyright (c) 2004 - 2016, 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/Tcg2PhysicalPresenceLib.h>
26 VOID
*mEfiDevPathNotifyReg
;
27 EFI_EVENT mEfiDevPathEvent
;
28 VOID
*mEmuVariableEventReg
;
29 EFI_EVENT mEmuVariableEvent
;
30 UINT16 mHostBridgeDevId
;
33 // Table of host IRQs matching PCI IRQs A-D
34 // (for configuring PCI Interrupt Line register)
36 CONST UINT8 PciHostIrqs
[] = {
37 0x0a, 0x0a, 0x0b, 0x0b
46 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
53 @param[in] Handle - Handle of PCI device instance
54 @param[in] PciIo - PCI IO protocol instance
55 @param[in] Pci - PCI Header register block
59 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
61 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
67 // Function prototypes
71 VisitAllInstancesOfProtocol (
73 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
78 VisitAllPciInstancesOfProtocol (
79 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
83 InstallDevicePathCallback (
88 PlatformRegisterFvBootOption (
96 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
97 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
98 UINTN BootOptionCount
;
99 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
100 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
101 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
103 Status
= gBS
->HandleProtocol (
105 &gEfiLoadedImageProtocolGuid
,
106 (VOID
**) &LoadedImage
108 ASSERT_EFI_ERROR (Status
);
110 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
111 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
112 ASSERT (DevicePath
!= NULL
);
113 DevicePath
= AppendDevicePathNode (
115 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
117 ASSERT (DevicePath
!= NULL
);
119 Status
= EfiBootManagerInitializeLoadOption (
121 LoadOptionNumberUnassigned
,
129 ASSERT_EFI_ERROR (Status
);
130 FreePool (DevicePath
);
132 BootOptions
= EfiBootManagerGetLoadOptions (
133 &BootOptionCount
, LoadOptionTypeBoot
136 OptionIndex
= EfiBootManagerFindLoadOption (
137 &NewOption
, BootOptions
, BootOptionCount
140 if (OptionIndex
== -1) {
141 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
142 ASSERT_EFI_ERROR (Status
);
144 EfiBootManagerFreeLoadOption (&NewOption
);
145 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
149 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
150 whose device paths do not resolve exactly to an FvFile in the system.
152 This removes any boot options that point to binaries built into the firmware
153 and have become stale due to any of the following:
154 - DXEFV's base address or size changed (historical),
155 - DXEFV's FvNameGuid changed,
156 - the FILE_GUID of the pointed-to binary changed,
157 - the referenced binary is no longer built into the firmware.
159 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
160 avoids exact duplicates.
163 RemoveStaleFvFileOptions (
167 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
168 UINTN BootOptionCount
;
171 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
,
174 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
175 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
180 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
181 // then keep the boot option.
183 Node1
= BootOptions
[Index
].FilePath
;
184 if (!(DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
&&
185 DevicePathSubType (Node1
) == HW_MEMMAP_DP
) &&
186 !(DevicePathType (Node1
) == MEDIA_DEVICE_PATH
&&
187 DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)) {
192 // If the second device path node is not FvFile(...), then keep the boot
195 Node2
= NextDevicePathNode (Node1
);
196 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
197 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
202 // Locate the Firmware Volume2 protocol instance that is denoted by the
203 // boot option. If this lookup fails (i.e., the boot option references a
204 // firmware volume that doesn't exist), then we'll proceed to delete the
208 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
,
209 &SearchNode
, &FvHandle
);
211 if (!EFI_ERROR (Status
)) {
213 // The firmware volume was found; now let's see if it contains the FvFile
214 // identified by GUID.
216 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
217 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
219 EFI_FV_FILETYPE FoundType
;
220 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
221 UINT32 AuthenticationStatus
;
223 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
,
224 (VOID
**)&FvProtocol
);
225 ASSERT_EFI_ERROR (Status
);
227 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
229 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
232 Status
= FvProtocol
->ReadFile (
234 &FvFileNode
->FvFileName
, // NameGuid
239 &AuthenticationStatus
241 if (!EFI_ERROR (Status
)) {
243 // The FvFile was found. Keep the boot option.
250 // Delete the boot option.
252 Status
= EfiBootManagerDeleteLoadOptionVariable (
253 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
255 CHAR16
*DevicePathString
;
257 DevicePathString
= ConvertDevicePathToText(BootOptions
[Index
].FilePath
,
260 EFI_ERROR (Status
) ? EFI_D_WARN
: EFI_D_VERBOSE
,
261 "%a: removing stale Boot#%04x %s: %r\n",
263 (UINT32
)BootOptions
[Index
].OptionNumber
,
264 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
267 if (DevicePathString
!= NULL
) {
268 FreePool (DevicePathString
);
273 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
277 PlatformRegisterOptionsAndKeys (
285 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
288 // Register ENTER as CONTINUE key
290 Enter
.ScanCode
= SCAN_NULL
;
291 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
292 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
293 ASSERT_EFI_ERROR (Status
);
296 // Map F2 to Boot Manager Menu
298 F2
.ScanCode
= SCAN_F2
;
299 F2
.UnicodeChar
= CHAR_NULL
;
300 Esc
.ScanCode
= SCAN_ESC
;
301 Esc
.UnicodeChar
= CHAR_NULL
;
302 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
303 ASSERT_EFI_ERROR (Status
);
304 Status
= EfiBootManagerAddKeyOptionVariable (
305 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
307 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
308 Status
= EfiBootManagerAddKeyOptionVariable (
309 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
311 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
317 IN EFI_HANDLE RootBridgeHandle
,
325 ConnectVirtioPciRng (
326 IN EFI_HANDLE Handle
,
338 // BDS Platform Functions
341 Do the platform init, can be customized by OEM/IBV
343 Possible things that can be done in PlatformBootManagerBeforeConsole:
345 > Update console variable: 1. include hot-plug devices;
346 > 2. Clear ConIn and add SOL for AMT
347 > Register new Driver#### or Boot####
348 > Register new Key####: e.g.: F12
349 > Signal ReadyToLock event
350 > Authentication action: 1. connect Auth devices;
351 > 2. Identify auto logon user.
355 PlatformBootManagerBeforeConsole (
361 RETURN_STATUS PcdStatus
;
363 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
364 InstallDevicePathCallback ();
366 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
367 ConnectRootBridge
, NULL
);
370 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
372 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
375 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
376 // the preparation of S3 system information. That logic has a hard dependency
377 // on the presence of the FACS ACPI table. Since our ACPI tables are only
378 // installed after PCI enumeration completes, we must not trigger the S3 save
379 // earlier, hence we can't signal End-of-Dxe earlier.
381 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
383 if (QemuFwCfgS3Enabled ()) {
385 // Save the boot script too. Note that this will require us to emit the
386 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
392 // Prevent further changes to LockBoxes or SMRAM.
395 Status
= gBS
->InstallProtocolInterface (&Handle
,
396 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
398 ASSERT_EFI_ERROR (Status
);
401 // Dispatch deferred images after EndOfDxe event and ReadyToLock
404 EfiBootManagerDispatchDeferredImages ();
406 PlatformInitializeConsole (gPlatformConsole
);
407 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
,
408 GetFrontPageTimeoutFromQemu ());
409 ASSERT_RETURN_ERROR (PcdStatus
);
411 PlatformRegisterOptionsAndKeys ();
414 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
415 // instances on Virtio PCI RNG devices.
417 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
425 IN EFI_HANDLE RootBridgeHandle
,
433 // Make the PCI bus driver connect the root bridge, non-recursively. This
434 // will produce a number of child handles with PciIo on them.
436 Status
= gBS
->ConnectController (
437 RootBridgeHandle
, // ControllerHandle
438 NULL
, // DriverImageHandle
439 NULL
, // RemainingDevicePath -- produce all
450 ConnectVirtioPciRng (
451 IN EFI_HANDLE Handle
,
456 EFI_PCI_IO_PROTOCOL
*PciIo
;
467 // Read and check VendorId.
469 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
471 if (EFI_ERROR (Status
)) {
474 if (VendorId
!= VIRTIO_VENDOR_ID
) {
479 // Read DeviceId and RevisionId.
481 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
483 if (EFI_ERROR (Status
)) {
486 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
488 if (EFI_ERROR (Status
)) {
493 // From DeviceId and RevisionId, determine whether the device is a
494 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
495 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
496 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
497 // only be sanity-checked, and SubsystemId will decide.
499 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
500 RevisionId
>= 0x01) {
502 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
509 // Read and check SubsystemId as dictated by Virtio10.
511 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
512 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
513 if (EFI_ERROR (Status
)) {
516 if ((Virtio10
&& SubsystemId
>= 0x40) ||
517 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
518 Status
= gBS
->ConnectController (
519 Handle
, // ControllerHandle
520 NULL
, // DriverImageHandle -- connect all drivers
521 NULL
, // RemainingDevicePath -- produce all child handles
522 FALSE
// Recursive -- don't follow child handles
524 if (EFI_ERROR (Status
)) {
531 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
537 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
539 @param[in] DeviceHandle Handle of the LPC Bridge device.
541 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
542 ConOut, ConIn, and ErrOut.
544 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
548 PrepareLpcBridgeDevicePath (
549 IN EFI_HANDLE DeviceHandle
553 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
554 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
558 Status
= gBS
->HandleProtocol (
560 &gEfiDevicePathProtocolGuid
,
563 if (EFI_ERROR (Status
)) {
566 TempDevicePath
= DevicePath
;
571 DevicePath
= AppendDevicePathNode (DevicePath
,
572 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
574 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
579 DevicePath
= TempDevicePath
;
580 gPnp16550ComPortDeviceNode
.UID
= 0;
582 DevicePath
= AppendDevicePathNode (DevicePath
,
583 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
584 DevicePath
= AppendDevicePathNode (DevicePath
,
585 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
586 DevicePath
= AppendDevicePathNode (DevicePath
,
587 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
592 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
593 if (DevPathStr
!= NULL
) {
596 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
598 gPnp16550ComPortDeviceNode
.UID
+ 1,
601 FreePool(DevPathStr
);
604 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
605 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
606 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
611 DevicePath
= TempDevicePath
;
612 gPnp16550ComPortDeviceNode
.UID
= 1;
614 DevicePath
= AppendDevicePathNode (DevicePath
,
615 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
616 DevicePath
= AppendDevicePathNode (DevicePath
,
617 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
618 DevicePath
= AppendDevicePathNode (DevicePath
,
619 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
624 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
625 if (DevPathStr
!= NULL
) {
628 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
630 gPnp16550ComPortDeviceNode
.UID
+ 1,
633 FreePool(DevPathStr
);
636 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
637 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
638 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
645 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
646 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
651 EFI_HANDLE PciDeviceHandle
;
652 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
653 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
654 UINTN GopHandleCount
;
655 EFI_HANDLE
*GopHandleBuffer
;
657 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
658 return EFI_INVALID_PARAMETER
;
662 // Initialize the GopDevicePath to be PciDevicePath
664 *GopDevicePath
= PciDevicePath
;
665 TempPciDevicePath
= PciDevicePath
;
667 Status
= gBS
->LocateDevicePath (
668 &gEfiDevicePathProtocolGuid
,
672 if (EFI_ERROR (Status
)) {
677 // Try to connect this handle, so that GOP driver could start on this
678 // device and create child handles with GraphicsOutput Protocol installed
679 // on them, then we get device paths of these child handles and select
680 // them as possible console device.
682 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
684 Status
= gBS
->LocateHandleBuffer (
686 &gEfiGraphicsOutputProtocolGuid
,
691 if (!EFI_ERROR (Status
)) {
693 // Add all the child handles as possible Console Device
695 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
696 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
697 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
698 if (EFI_ERROR (Status
)) {
704 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
707 // In current implementation, we only enable one of the child handles
708 // as console device, i.e. sotre one of the child handle's device
709 // path to variable "ConOut"
710 // In future, we could select all child handles to be console device
713 *GopDevicePath
= TempDevicePath
;
716 // Delete the PCI device's path that added by
717 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
719 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
720 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
723 gBS
->FreePool (GopHandleBuffer
);
730 Add PCI display to ConOut.
732 @param[in] DeviceHandle Handle of the PCI display device.
734 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
736 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
740 PreparePciDisplayDevicePath (
741 IN EFI_HANDLE DeviceHandle
745 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
746 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
749 GopDevicePath
= NULL
;
750 Status
= gBS
->HandleProtocol (
752 &gEfiDevicePathProtocolGuid
,
755 if (EFI_ERROR (Status
)) {
759 GetGopDevicePath (DevicePath
, &GopDevicePath
);
760 DevicePath
= GopDevicePath
;
762 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
768 Add PCI Serial to ConOut, ConIn, ErrOut.
770 @param[in] DeviceHandle Handle of the PCI serial device.
772 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
775 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
779 PreparePciSerialDevicePath (
780 IN EFI_HANDLE DeviceHandle
784 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
787 Status
= gBS
->HandleProtocol (
789 &gEfiDevicePathProtocolGuid
,
792 if (EFI_ERROR (Status
)) {
796 DevicePath
= AppendDevicePathNode (DevicePath
,
797 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
798 DevicePath
= AppendDevicePathNode (DevicePath
,
799 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
801 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
802 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
803 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
809 VisitAllInstancesOfProtocol (
811 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
817 EFI_HANDLE
*HandleBuffer
;
822 // Start to check all the PciIo to find all possible device
826 Status
= gBS
->LocateHandleBuffer (
833 if (EFI_ERROR (Status
)) {
837 for (Index
= 0; Index
< HandleCount
; Index
++) {
838 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
839 if (EFI_ERROR (Status
)) {
843 Status
= (*CallBackFunction
) (
850 gBS
->FreePool (HandleBuffer
);
858 VisitingAPciInstance (
859 IN EFI_HANDLE Handle
,
865 EFI_PCI_IO_PROTOCOL
*PciIo
;
868 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
871 // Check for all PCI device
873 Status
= PciIo
->Pci
.Read (
877 sizeof (Pci
) / sizeof (UINT32
),
880 if (EFI_ERROR (Status
)) {
884 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
895 VisitAllPciInstances (
896 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
899 return VisitAllInstancesOfProtocol (
900 &gEfiPciIoProtocolGuid
,
901 VisitingAPciInstance
,
902 (VOID
*)(UINTN
) CallBackFunction
908 Do platform specific PCI Device check and add them to
909 ConOut, ConIn, ErrOut.
911 @param[in] Handle - Handle of PCI device instance
912 @param[in] PciIo - PCI IO protocol instance
913 @param[in] Pci - PCI Header register block
915 @retval EFI_SUCCESS - PCI Device check and Console variable update
917 @retval EFI_STATUS - PCI Device check or Console variable update fail.
922 DetectAndPreparePlatformPciDevicePath (
923 IN EFI_HANDLE Handle
,
924 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
930 Status
= PciIo
->Attributes (
932 EfiPciIoAttributeOperationEnable
,
933 EFI_PCI_DEVICE_ENABLE
,
936 ASSERT_EFI_ERROR (Status
);
939 // Here we decide whether it is LPC Bridge
941 if ((IS_PCI_LPC (Pci
)) ||
942 ((IS_PCI_ISA_PDECODE (Pci
)) &&
943 (Pci
->Hdr
.VendorId
== 0x8086) &&
944 (Pci
->Hdr
.DeviceId
== 0x7000)
948 // Add IsaKeyboard to ConIn,
949 // add IsaSerial to ConOut, ConIn, ErrOut
951 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
952 PrepareLpcBridgeDevicePath (Handle
);
956 // Here we decide which Serial device to enable in PCI bus
958 if (IS_PCI_16550SERIAL (Pci
)) {
960 // Add them to ConOut, ConIn, ErrOut.
962 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
963 PreparePciSerialDevicePath (Handle
);
968 // Here we decide which display device to enable in PCI bus
970 if (IS_PCI_DISPLAY (Pci
)) {
972 // Add them to ConOut.
974 DEBUG ((EFI_D_INFO
, "Found PCI display device\n"));
975 PreparePciDisplayDevicePath (Handle
);
984 Connect the predefined platform default console device.
986 Always try to find and enable PCI display devices.
988 @param[in] PlatformConsole Predefined platform default console device array.
991 PlatformInitializeConsole (
992 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
998 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1001 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
1004 // Have chance to connect the platform default console,
1005 // the platform default console is the minimum device group
1006 // the platform should support
1008 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1010 // Update the console variable with the connect type
1012 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1013 EfiBootManagerUpdateConsoleVariable (ConIn
,
1014 PlatformConsole
[Index
].DevicePath
, NULL
);
1016 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1017 EfiBootManagerUpdateConsoleVariable (ConOut
,
1018 PlatformConsole
[Index
].DevicePath
, NULL
);
1020 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1021 EfiBootManagerUpdateConsoleVariable (ErrOut
,
1022 PlatformConsole
[Index
].DevicePath
, NULL
);
1029 Configure PCI Interrupt Line register for applicable devices
1030 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1032 @param[in] Handle - Handle of PCI device instance
1033 @param[in] PciIo - PCI IO protocol instance
1034 @param[in] PciHdr - PCI Header register block
1036 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1042 IN EFI_HANDLE Handle
,
1043 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1044 IN PCI_TYPE00
*PciHdr
1047 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1048 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1053 UINT32 RootBusNumber
;
1055 Status
= EFI_SUCCESS
;
1057 if (PciHdr
->Device
.InterruptPin
!= 0) {
1059 DevPathNode
= DevicePathFromHandle (Handle
);
1060 ASSERT (DevPathNode
!= NULL
);
1061 DevPath
= DevPathNode
;
1064 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1065 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1066 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1067 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1071 // Compute index into PciHostIrqs[] table by walking
1072 // the device path and adding up all device numbers
1074 Status
= EFI_NOT_FOUND
;
1076 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1077 while (!IsDevicePathEnd (DevPathNode
)) {
1078 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1079 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1081 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1084 // Unlike SeaBIOS, which starts climbing from the leaf device
1085 // up toward the root, we traverse the device path starting at
1086 // the root moving toward the leaf node.
1087 // The slot number of the top-level parent bridge is needed for
1088 // Q35 cases with more than 24 slots on the root bus.
1090 if (Status
!= EFI_SUCCESS
) {
1091 Status
= EFI_SUCCESS
;
1092 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1096 DevPathNode
= NextDevicePathNode (DevPathNode
);
1098 if (EFI_ERROR (Status
)) {
1101 if (RootBusNumber
== 0 && RootSlot
== 0) {
1104 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1111 // Final PciHostIrqs[] index calculation depends on the platform
1112 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1114 switch (mHostBridgeDevId
) {
1115 case INTEL_82441_DEVICE_ID
:
1118 case INTEL_Q35_MCH_DEVICE_ID
:
1120 // SeaBIOS contains the following comment:
1121 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1122 // with a different starting index - see q35-acpi-dsdt.dsl.
1124 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1126 if (RootSlot
> 24) {
1128 // in this case, subtract back out RootSlot from Idx
1129 // (SeaBIOS never adds it to begin with, but that would make our
1130 // device path traversal loop above too awkward)
1136 ASSERT (FALSE
); // should never get here
1138 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1139 IrqLine
= PciHostIrqs
[Idx
];
1141 DEBUG_CODE_BEGIN ();
1143 CHAR16
*DevPathString
;
1144 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1145 UINTN Segment
, Bus
, Device
, Function
;
1147 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1148 if (DevPathString
== NULL
) {
1149 DevPathString
= Fallback
;
1151 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1152 ASSERT_EFI_ERROR (Status
);
1154 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1155 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1158 if (DevPathString
!= Fallback
) {
1159 FreePool (DevPathString
);
1165 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1167 Status
= PciIo
->Pci
.Write (
1170 PCI_INT_LINE_OFFSET
,
1181 PciAcpiInitialization (
1187 // Query Host Bridge DID to determine platform type
1189 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1190 switch (mHostBridgeDevId
) {
1191 case INTEL_82441_DEVICE_ID
:
1192 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1194 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1196 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1197 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1198 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1199 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1201 case INTEL_Q35_MCH_DEVICE_ID
:
1202 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1204 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1206 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1207 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1208 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1209 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1210 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1211 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1212 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1213 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1216 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1217 __FUNCTION__
, mHostBridgeDevId
));
1223 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1225 VisitAllPciInstances (SetPciIntLine
);
1228 // Set ACPI SCI_EN bit in PMCNTRL
1230 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1234 This function detects if OVMF is running on Xen.
1243 EFI_HOB_GUID_TYPE
*GuidHob
;
1244 STATIC INTN FoundHob
= -1;
1246 if (FoundHob
== 0) {
1248 } else if (FoundHob
== 1) {
1253 // See if a XenInfo HOB is available
1255 GuidHob
= GetFirstGuidHob (&gEfiXenInfoGuid
);
1256 if (GuidHob
== NULL
) {
1267 ConnectRecursivelyIfPciMassStorage (
1268 IN EFI_HANDLE Handle
,
1269 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1270 IN PCI_TYPE00
*PciHeader
1274 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1278 // Recognize PCI Mass Storage, and Xen PCI devices
1280 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1281 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1283 Status
= gBS
->HandleProtocol (
1285 &gEfiDevicePathProtocolGuid
,
1288 if (EFI_ERROR (Status
)) {
1293 // Print Device Path
1295 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1296 if (DevPathStr
!= NULL
) {
1299 "Found %s device: %s\n",
1300 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1306 FreePool(DevPathStr
);
1309 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1310 if (EFI_ERROR (Status
)) {
1321 This notification function is invoked when the
1322 EMU Variable FVB has been changed.
1324 @param Event The event that occurred
1325 @param Context For EFI compatibility. Not used.
1330 EmuVariablesUpdatedCallback (
1335 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1336 UpdateNvVarsOnFileSystem ();
1342 VisitingFileSystemInstance (
1343 IN EFI_HANDLE Handle
,
1349 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1350 RETURN_STATUS PcdStatus
;
1352 if (ConnectedToFileSystem
) {
1353 return EFI_ALREADY_STARTED
;
1356 Status
= ConnectNvVarsToFileSystem (Handle
);
1357 if (EFI_ERROR (Status
)) {
1361 ConnectedToFileSystem
= TRUE
;
1363 EfiCreateProtocolNotifyEvent (
1364 &gEfiDevicePathProtocolGuid
,
1366 EmuVariablesUpdatedCallback
,
1368 &mEmuVariableEventReg
1370 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1371 (UINT64
)(UINTN
) mEmuVariableEvent
);
1372 ASSERT_RETURN_ERROR (PcdStatus
);
1379 PlatformBdsRestoreNvVarsFromHardDisk (
1382 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1383 VisitAllInstancesOfProtocol (
1384 &gEfiSimpleFileSystemProtocolGuid
,
1385 VisitingFileSystemInstance
,
1392 Connect with predefined platform connect sequence.
1394 The OEM/IBV can customize with their own connect sequence.
1397 PlatformBdsConnectSequence (
1402 RETURN_STATUS Status
;
1404 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1409 // Here we can get the customized platform connect sequence
1410 // Notes: we can connect with new variable which record the
1411 // last time boots connect device path sequence
1413 while (gPlatformConnectSequence
[Index
] != NULL
) {
1415 // Build the platform boot option
1417 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1421 Status
= ConnectDevicesFromQemu ();
1422 if (RETURN_ERROR (Status
)) {
1424 // Just use the simple policy to connect all devices
1426 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1427 EfiBootManagerConnectAll ();
1432 Save the S3 boot script.
1434 Note that DxeSmmReadyToLock must be signaled after this function returns;
1435 otherwise the script wouldn't be saved actually.
1444 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1445 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1447 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1448 (VOID
**) &BootScript
);
1449 ASSERT_EFI_ERROR (Status
);
1452 // Despite the opcode documentation in the PI spec, the protocol
1453 // implementation embeds a deep copy of the info in the boot script, rather
1454 // than storing just a pointer to runtime or NVS storage.
1456 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1457 (UINT32
) sizeof Info
,
1458 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1459 ASSERT_EFI_ERROR (Status
);
1464 Do the platform specific action after the console is ready
1466 Possible things that can be done in PlatformBootManagerAfterConsole:
1468 > Console post action:
1469 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1470 > Signal console ready platform customized event
1471 > Run diagnostics like memory testing
1472 > Connect certain devices
1473 > Dispatch aditional option roms
1474 > Special boot: e.g.: USB boot, enter UI
1478 PlatformBootManagerAfterConsole (
1482 EFI_BOOT_MODE BootMode
;
1484 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1486 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1487 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1488 "from disk since flash variables appear to be supported.\n"));
1491 // Try to restore variables from the hard disk early so
1492 // they can be used for the other BDS connect operations.
1494 PlatformBdsRestoreNvVarsFromHardDisk ();
1498 // Get current Boot Mode
1500 BootMode
= GetBootModeHob ();
1501 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1504 // Go the different platform policy with different boot mode
1505 // Notes: this part code can be change with the table policy
1507 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1512 BootLogoEnableLogo ();
1515 // Set PCI Interrupt Line registers and ACPI SCI_EN
1517 PciAcpiInitialization ();
1520 // Process TPM PPI request
1522 Tcg2PhysicalPresenceLibProcessRequest (NULL
);
1525 // Process QEMU's -kernel command line option
1527 TryRunningQemuKernel ();
1530 // Perform some platform specific connect sequence
1532 PlatformBdsConnectSequence ();
1534 EfiBootManagerRefreshAllBootOption ();
1537 // Register UEFI Shell
1539 PlatformRegisterFvBootOption (
1540 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1543 RemoveStaleFvFileOptions ();
1544 SetBootOrderFromQemu ();
1548 This notification function is invoked when an instance of the
1549 EFI_DEVICE_PATH_PROTOCOL is produced.
1551 @param Event The event that occurred
1552 @param Context For EFI compatibility. Not used.
1565 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1566 ATAPI_DEVICE_PATH
*Atapi
;
1569 // Examine all new handles
1573 // Get the next handle
1575 BufferSize
= sizeof (Handle
);
1576 Status
= gBS
->LocateHandle (
1579 mEfiDevPathNotifyReg
,
1585 // If not found, we're done
1587 if (EFI_NOT_FOUND
== Status
) {
1591 if (EFI_ERROR (Status
)) {
1596 // Get the DevicePath protocol on that handle
1598 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1599 (VOID
**)&DevPathNode
);
1600 ASSERT_EFI_ERROR (Status
);
1602 while (!IsDevicePathEnd (DevPathNode
)) {
1604 // Find the handler to dump this device path node
1607 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1608 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1610 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1616 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1623 // Next device path node
1625 DevPathNode
= NextDevicePathNode (DevPathNode
);
1634 InstallDevicePathCallback (
1638 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1639 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1640 &gEfiDevicePathProtocolGuid
,
1644 &mEfiDevPathNotifyReg
1649 This function is called each second during the boot manager waits the
1652 @param TimeoutRemain The remaining timeout.
1656 PlatformBootManagerWaitCallback (
1657 UINT16 TimeoutRemain
1660 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1661 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1664 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1666 Black
.Raw
= 0x00000000;
1667 White
.Raw
= 0x00FFFFFF;
1669 BootLogoUpdateProgress (
1672 L
"Start boot option",
1674 (Timeout
- TimeoutRemain
) * 100 / Timeout
,