2 Platform BDS customizations.
4 Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
5 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "BdsPlatform.h"
11 #include <Guid/RootBridgesConnectedEventGroup.h>
12 #include <Protocol/FirmwareVolume2.h>
13 #include <Library/PlatformBmPrintScLib.h>
14 #include <Library/Tcg2PhysicalPresenceLib.h>
16 #include <Protocol/BlockIo.h>
22 VOID
*mEfiDevPathNotifyReg
;
23 EFI_EVENT mEfiDevPathEvent
;
24 VOID
*mEmuVariableEventReg
;
25 EFI_EVENT mEmuVariableEvent
;
26 UINT16 mHostBridgeDevId
;
29 // Table of host IRQs matching PCI IRQs A-D
30 // (for configuring PCI Interrupt Line register)
32 CONST UINT8 PciHostIrqs
[] = {
33 0x0a, 0x0a, 0x0b, 0x0b
42 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
49 @param[in] Handle - Handle of PCI device instance
50 @param[in] PciIo - PCI IO protocol instance
51 @param[in] Pci - PCI Header register block
55 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
57 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
63 // Function prototypes
67 VisitAllInstancesOfProtocol (
69 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
74 VisitAllPciInstancesOfProtocol (
75 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
79 InstallDevicePathCallback (
84 PlatformRegisterFvBootOption (
92 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
93 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
94 UINTN BootOptionCount
;
95 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
96 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
97 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
99 Status
= gBS
->HandleProtocol (
101 &gEfiLoadedImageProtocolGuid
,
102 (VOID
**) &LoadedImage
104 ASSERT_EFI_ERROR (Status
);
106 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
107 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
108 ASSERT (DevicePath
!= NULL
);
109 DevicePath
= AppendDevicePathNode (
111 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
113 ASSERT (DevicePath
!= NULL
);
115 Status
= EfiBootManagerInitializeLoadOption (
117 LoadOptionNumberUnassigned
,
125 ASSERT_EFI_ERROR (Status
);
126 FreePool (DevicePath
);
128 BootOptions
= EfiBootManagerGetLoadOptions (
129 &BootOptionCount
, LoadOptionTypeBoot
132 OptionIndex
= EfiBootManagerFindLoadOption (
133 &NewOption
, BootOptions
, BootOptionCount
136 if (OptionIndex
== -1) {
137 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
138 ASSERT_EFI_ERROR (Status
);
140 EfiBootManagerFreeLoadOption (&NewOption
);
141 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
145 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
146 whose device paths do not resolve exactly to an FvFile in the system.
148 This removes any boot options that point to binaries built into the firmware
149 and have become stale due to any of the following:
150 - DXEFV's base address or size changed (historical),
151 - DXEFV's FvNameGuid changed,
152 - the FILE_GUID of the pointed-to binary changed,
153 - the referenced binary is no longer built into the firmware.
155 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
156 avoids exact duplicates.
159 RemoveStaleFvFileOptions (
163 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
164 UINTN BootOptionCount
;
167 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
,
170 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
171 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
176 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
177 // then keep the boot option.
179 Node1
= BootOptions
[Index
].FilePath
;
180 if (!(DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
&&
181 DevicePathSubType (Node1
) == HW_MEMMAP_DP
) &&
182 !(DevicePathType (Node1
) == MEDIA_DEVICE_PATH
&&
183 DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)) {
188 // If the second device path node is not FvFile(...), then keep the boot
191 Node2
= NextDevicePathNode (Node1
);
192 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
193 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
198 // Locate the Firmware Volume2 protocol instance that is denoted by the
199 // boot option. If this lookup fails (i.e., the boot option references a
200 // firmware volume that doesn't exist), then we'll proceed to delete the
204 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
,
205 &SearchNode
, &FvHandle
);
207 if (!EFI_ERROR (Status
)) {
209 // The firmware volume was found; now let's see if it contains the FvFile
210 // identified by GUID.
212 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
213 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
215 EFI_FV_FILETYPE FoundType
;
216 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
217 UINT32 AuthenticationStatus
;
219 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
,
220 (VOID
**)&FvProtocol
);
221 ASSERT_EFI_ERROR (Status
);
223 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
225 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
228 Status
= FvProtocol
->ReadFile (
230 &FvFileNode
->FvFileName
, // NameGuid
235 &AuthenticationStatus
237 if (!EFI_ERROR (Status
)) {
239 // The FvFile was found. Keep the boot option.
246 // Delete the boot option.
248 Status
= EfiBootManagerDeleteLoadOptionVariable (
249 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
251 CHAR16
*DevicePathString
;
253 DevicePathString
= ConvertDevicePathToText(BootOptions
[Index
].FilePath
,
256 EFI_ERROR (Status
) ? EFI_D_WARN
: DEBUG_VERBOSE
,
257 "%a: removing stale Boot#%04x %s: %r\n",
259 (UINT32
)BootOptions
[Index
].OptionNumber
,
260 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
263 if (DevicePathString
!= NULL
) {
264 FreePool (DevicePathString
);
269 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
273 PlatformRegisterOptionsAndKeys (
281 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
284 // Register ENTER as CONTINUE key
286 Enter
.ScanCode
= SCAN_NULL
;
287 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
288 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
289 ASSERT_EFI_ERROR (Status
);
292 // Map F2 to Boot Manager Menu
294 F2
.ScanCode
= SCAN_F2
;
295 F2
.UnicodeChar
= CHAR_NULL
;
296 Esc
.ScanCode
= SCAN_ESC
;
297 Esc
.UnicodeChar
= CHAR_NULL
;
298 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
299 ASSERT_EFI_ERROR (Status
);
300 Status
= EfiBootManagerAddKeyOptionVariable (
301 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
303 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
304 Status
= EfiBootManagerAddKeyOptionVariable (
305 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
307 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
313 IN EFI_HANDLE RootBridgeHandle
,
321 ConnectVirtioPciRng (
322 IN EFI_HANDLE Handle
,
334 // BDS Platform Functions
337 Do the platform init, can be customized by OEM/IBV
339 Possible things that can be done in PlatformBootManagerBeforeConsole:
341 > Update console variable: 1. include hot-plug devices;
342 > 2. Clear ConIn and add SOL for AMT
343 > Register new Driver#### or Boot####
344 > Register new Key####: e.g.: F12
345 > Signal ReadyToLock event
346 > Authentication action: 1. connect Auth devices;
347 > 2. Identify auto logon user.
351 PlatformBootManagerBeforeConsole (
358 DEBUG ((DEBUG_INFO
, "PlatformBootManagerBeforeConsole\n"));
359 InstallDevicePathCallback ();
361 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
362 ConnectRootBridge
, NULL
);
365 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
367 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
370 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
371 // the preparation of S3 system information. That logic has a hard dependency
372 // on the presence of the FACS ACPI table. Since our ACPI tables are only
373 // installed after PCI enumeration completes, we must not trigger the S3 save
374 // earlier, hence we can't signal End-of-Dxe earlier.
376 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
378 // We need to connect all trusted consoles for TCG PP. Here we treat all
379 // consoles in OVMF to be trusted consoles.
380 PlatformInitializeConsole (gPlatformConsole
);
383 // Process TPM PPI request
385 Tcg2PhysicalPresenceLibProcessRequest (NULL
);
388 // Prevent further changes to LockBoxes or SMRAM.
389 // Any TPM 2 Physical Presence Interface opcode must be handled before.
392 Status
= gBS
->InstallProtocolInterface (&Handle
,
393 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
395 ASSERT_EFI_ERROR (Status
);
398 // Dispatch deferred images after EndOfDxe event and ReadyToLock
401 EfiBootManagerDispatchDeferredImages ();
403 PlatformRegisterOptionsAndKeys ();
406 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
407 // instances on Virtio PCI RNG devices.
409 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
417 IN EFI_HANDLE RootBridgeHandle
,
425 // Make the PCI bus driver connect the root bridge, non-recursively. This
426 // will produce a number of child handles with PciIo on them.
428 Status
= gBS
->ConnectController (
429 RootBridgeHandle
, // ControllerHandle
430 NULL
, // DriverImageHandle
431 NULL
, // RemainingDevicePath -- produce all
442 ConnectVirtioPciRng (
443 IN EFI_HANDLE Handle
,
448 EFI_PCI_IO_PROTOCOL
*PciIo
;
459 // Read and check VendorId.
461 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
463 if (EFI_ERROR (Status
)) {
466 if (VendorId
!= VIRTIO_VENDOR_ID
) {
471 // Read DeviceId and RevisionId.
473 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
475 if (EFI_ERROR (Status
)) {
478 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
480 if (EFI_ERROR (Status
)) {
485 // From DeviceId and RevisionId, determine whether the device is a
486 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
487 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
488 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
489 // only be sanity-checked, and SubsystemId will decide.
491 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
492 RevisionId
>= 0x01) {
494 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
501 // Read and check SubsystemId as dictated by Virtio10.
503 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
504 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
505 if (EFI_ERROR (Status
)) {
508 if ((Virtio10
&& SubsystemId
>= 0x40) ||
509 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
510 Status
= gBS
->ConnectController (
511 Handle
, // ControllerHandle
512 NULL
, // DriverImageHandle -- connect all drivers
513 NULL
, // RemainingDevicePath -- produce all child handles
514 FALSE
// Recursive -- don't follow child handles
516 if (EFI_ERROR (Status
)) {
523 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
529 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
531 @param[in] DeviceHandle Handle of the LPC Bridge device.
533 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
534 ConOut, ConIn, and ErrOut.
536 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
540 PrepareLpcBridgeDevicePath (
541 IN EFI_HANDLE DeviceHandle
545 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
546 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
550 Status
= gBS
->HandleProtocol (
552 &gEfiDevicePathProtocolGuid
,
555 if (EFI_ERROR (Status
)) {
558 TempDevicePath
= DevicePath
;
563 DevicePath
= AppendDevicePathNode (DevicePath
,
564 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
566 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
571 DevicePath
= TempDevicePath
;
572 gPnp16550ComPortDeviceNode
.UID
= 0;
574 DevicePath
= AppendDevicePathNode (DevicePath
,
575 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
576 DevicePath
= AppendDevicePathNode (DevicePath
,
577 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
578 DevicePath
= AppendDevicePathNode (DevicePath
,
579 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
584 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
585 if (DevPathStr
!= NULL
) {
588 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
590 gPnp16550ComPortDeviceNode
.UID
+ 1,
593 FreePool(DevPathStr
);
596 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
597 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
598 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
600 // Don't register COM2 which can be used for DBG instead so keep it clean
607 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
608 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
613 EFI_HANDLE PciDeviceHandle
;
614 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
615 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
616 UINTN GopHandleCount
;
617 EFI_HANDLE
*GopHandleBuffer
;
619 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
620 return EFI_INVALID_PARAMETER
;
624 // Initialize the GopDevicePath to be PciDevicePath
626 *GopDevicePath
= PciDevicePath
;
627 TempPciDevicePath
= PciDevicePath
;
629 Status
= gBS
->LocateDevicePath (
630 &gEfiDevicePathProtocolGuid
,
634 if (EFI_ERROR (Status
)) {
639 // Try to connect this handle, so that GOP driver could start on this
640 // device and create child handles with GraphicsOutput Protocol installed
641 // on them, then we get device paths of these child handles and select
642 // them as possible console device.
644 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
646 Status
= gBS
->LocateHandleBuffer (
648 &gEfiGraphicsOutputProtocolGuid
,
653 if (!EFI_ERROR (Status
)) {
655 // Add all the child handles as possible Console Device
657 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
658 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
659 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
660 if (EFI_ERROR (Status
)) {
666 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
669 // In current implementation, we only enable one of the child handles
670 // as console device, i.e. sotre one of the child handle's device
671 // path to variable "ConOut"
672 // In future, we could select all child handles to be console device
675 *GopDevicePath
= TempDevicePath
;
678 // Delete the PCI device's path that added by
679 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
681 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
682 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
685 gBS
->FreePool (GopHandleBuffer
);
692 Add PCI display to ConOut.
694 @param[in] DeviceHandle Handle of the PCI display device.
696 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
698 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
702 PreparePciDisplayDevicePath (
703 IN EFI_HANDLE DeviceHandle
707 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
708 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
711 GopDevicePath
= NULL
;
712 Status
= gBS
->HandleProtocol (
714 &gEfiDevicePathProtocolGuid
,
717 if (EFI_ERROR (Status
)) {
721 GetGopDevicePath (DevicePath
, &GopDevicePath
);
722 DevicePath
= GopDevicePath
;
724 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
730 Add PCI Serial to ConOut, ConIn, ErrOut.
732 @param[in] DeviceHandle Handle of the PCI serial device.
734 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
737 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
741 PreparePciSerialDevicePath (
742 IN EFI_HANDLE DeviceHandle
746 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
749 Status
= gBS
->HandleProtocol (
751 &gEfiDevicePathProtocolGuid
,
754 if (EFI_ERROR (Status
)) {
758 DevicePath
= AppendDevicePathNode (DevicePath
,
759 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
760 DevicePath
= AppendDevicePathNode (DevicePath
,
761 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
763 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
764 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
765 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
771 VisitAllInstancesOfProtocol (
773 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
779 EFI_HANDLE
*HandleBuffer
;
784 // Start to check all the PciIo to find all possible device
788 Status
= gBS
->LocateHandleBuffer (
795 if (EFI_ERROR (Status
)) {
799 for (Index
= 0; Index
< HandleCount
; Index
++) {
800 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
801 if (EFI_ERROR (Status
)) {
805 Status
= (*CallBackFunction
) (
812 gBS
->FreePool (HandleBuffer
);
820 VisitingAPciInstance (
821 IN EFI_HANDLE Handle
,
827 EFI_PCI_IO_PROTOCOL
*PciIo
;
830 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
833 // Check for all PCI device
835 Status
= PciIo
->Pci
.Read (
839 sizeof (Pci
) / sizeof (UINT32
),
842 if (EFI_ERROR (Status
)) {
846 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
857 VisitAllPciInstances (
858 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
861 return VisitAllInstancesOfProtocol (
862 &gEfiPciIoProtocolGuid
,
863 VisitingAPciInstance
,
864 (VOID
*)(UINTN
) CallBackFunction
870 Do platform specific PCI Device check and add them to
871 ConOut, ConIn, ErrOut.
873 @param[in] Handle - Handle of PCI device instance
874 @param[in] PciIo - PCI IO protocol instance
875 @param[in] Pci - PCI Header register block
877 @retval EFI_SUCCESS - PCI Device check and Console variable update
879 @retval EFI_STATUS - PCI Device check or Console variable update fail.
884 DetectAndPreparePlatformPciDevicePath (
885 IN EFI_HANDLE Handle
,
886 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
892 Status
= PciIo
->Attributes (
894 EfiPciIoAttributeOperationEnable
,
895 EFI_PCI_DEVICE_ENABLE
,
898 ASSERT_EFI_ERROR (Status
);
901 // Here we decide whether it is LPC Bridge
903 if ((IS_PCI_LPC (Pci
)) ||
904 ((IS_PCI_ISA_PDECODE (Pci
)) &&
905 (Pci
->Hdr
.VendorId
== 0x8086) &&
906 (Pci
->Hdr
.DeviceId
== 0x7000)
910 // Add IsaKeyboard to ConIn,
911 // add IsaSerial to ConOut, ConIn, ErrOut
913 DEBUG ((DEBUG_INFO
, "Found LPC Bridge device\n"));
914 PrepareLpcBridgeDevicePath (Handle
);
918 // Here we decide which Serial device to enable in PCI bus
920 if (IS_PCI_16550SERIAL (Pci
)) {
922 // Add them to ConOut, ConIn, ErrOut.
924 DEBUG ((DEBUG_INFO
, "Found PCI 16550 SERIAL device\n"));
925 PreparePciSerialDevicePath (Handle
);
930 // Here we decide which display device to enable in PCI bus
932 if (IS_PCI_DISPLAY (Pci
)) {
934 // Add them to ConOut.
936 DEBUG ((DEBUG_INFO
, "Found PCI display device\n"));
937 PreparePciDisplayDevicePath (Handle
);
946 Connect the predefined platform default console device.
948 Always try to find and enable PCI display devices.
950 @param[in] PlatformConsole Predefined platform default console device array.
953 PlatformInitializeConsole (
954 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
960 // Do platform specific PCI Device check and add them to ConOut, ConIn,
963 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
966 // Have chance to connect the platform default console,
967 // the platform default console is the minimum device group
968 // the platform should support
970 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
972 // Update the console variable with the connect type
974 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
975 EfiBootManagerUpdateConsoleVariable (ConIn
,
976 PlatformConsole
[Index
].DevicePath
, NULL
);
978 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
979 EfiBootManagerUpdateConsoleVariable (ConOut
,
980 PlatformConsole
[Index
].DevicePath
, NULL
);
982 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
983 EfiBootManagerUpdateConsoleVariable (ErrOut
,
984 PlatformConsole
[Index
].DevicePath
, NULL
);
991 Configure PCI Interrupt Line register for applicable devices
992 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
994 @param[in] Handle - Handle of PCI device instance
995 @param[in] PciIo - PCI IO protocol instance
996 @param[in] PciHdr - PCI Header register block
998 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1004 IN EFI_HANDLE Handle
,
1005 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1006 IN PCI_TYPE00
*PciHdr
1009 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1010 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1015 UINT32 RootBusNumber
;
1017 Status
= EFI_SUCCESS
;
1019 if (PciHdr
->Device
.InterruptPin
!= 0) {
1021 DevPathNode
= DevicePathFromHandle (Handle
);
1022 ASSERT (DevPathNode
!= NULL
);
1023 DevPath
= DevPathNode
;
1026 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1027 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1028 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1029 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1033 // Compute index into PciHostIrqs[] table by walking
1034 // the device path and adding up all device numbers
1036 Status
= EFI_NOT_FOUND
;
1038 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1039 while (!IsDevicePathEnd (DevPathNode
)) {
1040 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1041 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1043 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1046 // Unlike SeaBIOS, which starts climbing from the leaf device
1047 // up toward the root, we traverse the device path starting at
1048 // the root moving toward the leaf node.
1049 // The slot number of the top-level parent bridge is needed for
1050 // Q35 cases with more than 24 slots on the root bus.
1052 if (Status
!= EFI_SUCCESS
) {
1053 Status
= EFI_SUCCESS
;
1054 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1058 DevPathNode
= NextDevicePathNode (DevPathNode
);
1060 if (EFI_ERROR (Status
)) {
1063 if (RootBusNumber
== 0 && RootSlot
== 0) {
1066 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1073 // Final PciHostIrqs[] index calculation depends on the platform
1074 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1076 switch (mHostBridgeDevId
) {
1077 case 0x7432: // BHYVE (AMD hostbridge)
1078 case 0x1275: // BHYVE (Intel hostbridge)
1079 case INTEL_82441_DEVICE_ID
:
1082 case INTEL_Q35_MCH_DEVICE_ID
:
1084 // SeaBIOS contains the following comment:
1085 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1086 // with a different starting index - see q35-acpi-dsdt.dsl.
1088 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1090 if (RootSlot
> 24) {
1092 // in this case, subtract back out RootSlot from Idx
1093 // (SeaBIOS never adds it to begin with, but that would make our
1094 // device path traversal loop above too awkward)
1100 ASSERT (FALSE
); // should never get here
1102 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1103 IrqLine
= PciHostIrqs
[Idx
];
1105 DEBUG_CODE_BEGIN ();
1107 CHAR16
*DevPathString
;
1108 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1109 UINTN Segment
, Bus
, Device
, Function
;
1111 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1112 if (DevPathString
== NULL
) {
1113 DevPathString
= Fallback
;
1115 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1116 ASSERT_EFI_ERROR (Status
);
1118 DEBUG ((DEBUG_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1119 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1122 if (DevPathString
!= Fallback
) {
1123 FreePool (DevPathString
);
1129 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1131 Status
= PciIo
->Pci
.Write (
1134 PCI_INT_LINE_OFFSET
,
1145 PciAcpiInitialization (
1151 // Query Host Bridge DID to determine platform type
1153 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1154 switch (mHostBridgeDevId
) {
1155 case 0x7432: // BHYVE (AMD hostbridge)
1156 case 0x1275: // BHYVE (Intel hostbridge)
1157 case INTEL_82441_DEVICE_ID
:
1158 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1160 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1162 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1163 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1164 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1165 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1167 case INTEL_Q35_MCH_DEVICE_ID
:
1168 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1170 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1172 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1173 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1174 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1175 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1176 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1177 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1178 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1179 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1182 DEBUG ((DEBUG_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1183 __FUNCTION__
, mHostBridgeDevId
));
1189 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1191 VisitAllPciInstances (SetPciIntLine
);
1194 // Set ACPI SCI_EN bit in PMCNTRL
1196 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1201 ConnectRecursivelyIfPciMassStorage (
1202 IN EFI_HANDLE Handle
,
1203 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1204 IN PCI_TYPE00
*PciHeader
1208 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1212 // Recognize PCI Mass Storage, and Xen PCI devices
1214 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
)) {
1216 Status
= gBS
->HandleProtocol (
1218 &gEfiDevicePathProtocolGuid
,
1221 if (EFI_ERROR (Status
)) {
1226 // Print Device Path
1228 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1229 if (DevPathStr
!= NULL
) {
1232 "Found %s device: %s\n",
1233 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1239 FreePool(DevPathStr
);
1242 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1243 if (EFI_ERROR (Status
)) {
1254 This notification function is invoked when the
1255 EMU Variable FVB has been changed.
1257 @param Event The event that occurred
1258 @param Context For EFI compatibility. Not used.
1263 EmuVariablesUpdatedCallback (
1268 DEBUG ((DEBUG_INFO
, "EmuVariablesUpdatedCallback\n"));
1269 UpdateNvVarsOnFileSystem ();
1275 VisitingFileSystemInstance (
1276 IN EFI_HANDLE Handle
,
1282 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1283 RETURN_STATUS PcdStatus
;
1285 if (ConnectedToFileSystem
) {
1286 return EFI_ALREADY_STARTED
;
1289 Status
= ConnectNvVarsToFileSystem (Handle
);
1290 if (EFI_ERROR (Status
)) {
1294 ConnectedToFileSystem
= TRUE
;
1296 EfiCreateProtocolNotifyEvent (
1297 &gEfiDevicePathProtocolGuid
,
1299 EmuVariablesUpdatedCallback
,
1301 &mEmuVariableEventReg
1303 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1304 (UINT64
)(UINTN
) mEmuVariableEvent
);
1305 ASSERT_RETURN_ERROR (PcdStatus
);
1312 PlatformBdsRestoreNvVarsFromHardDisk (
1315 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1316 VisitAllInstancesOfProtocol (
1317 &gEfiSimpleFileSystemProtocolGuid
,
1318 VisitingFileSystemInstance
,
1325 Connect with predefined platform connect sequence.
1327 The OEM/IBV can customize with their own connect sequence.
1330 PlatformBdsConnectSequence (
1336 DEBUG ((DEBUG_INFO
, "PlatformBdsConnectSequence\n"));
1341 // Here we can get the customized platform connect sequence
1342 // Notes: we can connect with new variable which record the
1343 // last time boots connect device path sequence
1345 while (gPlatformConnectSequence
[Index
] != NULL
) {
1347 // Build the platform boot option
1349 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1354 // Just use the simple policy to connect all devices
1356 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1357 EfiBootManagerConnectAll ();
1361 Save the S3 boot script.
1363 Note that DxeSmmReadyToLock must be signaled after this function returns;
1364 otherwise the script wouldn't be saved actually.
1366 #if defined(__GNUC__)
1367 __attribute__((unused
))
1376 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1377 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1379 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1380 (VOID
**) &BootScript
);
1381 ASSERT_EFI_ERROR (Status
);
1384 // Despite the opcode documentation in the PI spec, the protocol
1385 // implementation embeds a deep copy of the info in the boot script, rather
1386 // than storing just a pointer to runtime or NVS storage.
1388 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1389 (UINT32
) sizeof Info
,
1390 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1391 ASSERT_EFI_ERROR (Status
);
1396 Do the platform specific action after the console is ready
1398 Possible things that can be done in PlatformBootManagerAfterConsole:
1400 > Console post action:
1401 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1402 > Signal console ready platform customized event
1403 > Run diagnostics like memory testing
1404 > Connect certain devices
1405 > Dispatch aditional option roms
1406 > Special boot: e.g.: USB boot, enter UI
1410 PlatformBootManagerAfterConsole (
1414 EFI_BOOT_MODE BootMode
;
1416 DEBUG ((DEBUG_INFO
, "PlatformBootManagerAfterConsole\n"));
1418 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1419 DEBUG ((DEBUG_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1420 "from disk since flash variables appear to be supported.\n"));
1423 // Try to restore variables from the hard disk early so
1424 // they can be used for the other BDS connect operations.
1426 /* XXX Calling this causes Keyboard to be removed from ConIn which
1427 results in unresponsive guest boot loaders in the GUI. Restore it
1428 when we figure out what is needed to get NvVars storage done
1431 /*PlatformBdsRestoreNvVarsFromHardDisk ();*/
1435 // Get current Boot Mode
1437 BootMode
= GetBootModeHob ();
1438 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1441 // Go the different platform policy with different boot mode
1442 // Notes: this part code can be change with the table policy
1444 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1449 BootLogoEnableLogo ();
1452 // Set PCI Interrupt Line registers and ACPI SCI_EN
1454 PciAcpiInitialization ();
1457 // Perform some platform specific connect sequence
1459 PlatformBdsConnectSequence ();
1461 EfiBootManagerRefreshAllBootOption ();
1464 // Register UEFI Shell
1466 PlatformRegisterFvBootOption (
1467 &gUefiShellFileGuid
, L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1470 RemoveStaleFvFileOptions ();
1472 PlatformBmPrintScRegisterHandler ();
1476 This notification function is invoked when an instance of the
1477 EFI_DEVICE_PATH_PROTOCOL is produced.
1479 @param Event The event that occurred
1480 @param Context For EFI compatibility. Not used.
1493 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1494 ATAPI_DEVICE_PATH
*Atapi
;
1497 // Examine all new handles
1501 // Get the next handle
1503 BufferSize
= sizeof (Handle
);
1504 Status
= gBS
->LocateHandle (
1507 mEfiDevPathNotifyReg
,
1513 // If not found, we're done
1515 if (EFI_NOT_FOUND
== Status
) {
1519 if (EFI_ERROR (Status
)) {
1524 // Get the DevicePath protocol on that handle
1526 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1527 (VOID
**)&DevPathNode
);
1528 ASSERT_EFI_ERROR (Status
);
1530 while (!IsDevicePathEnd (DevPathNode
)) {
1532 // Find the handler to dump this device path node
1535 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1536 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1538 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1544 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1551 // Next device path node
1553 DevPathNode
= NextDevicePathNode (DevPathNode
);
1562 InstallDevicePathCallback (
1566 DEBUG ((DEBUG_INFO
, "Registered NotifyDevPath Event\n"));
1567 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1568 &gEfiDevicePathProtocolGuid
,
1572 &mEfiDevPathNotifyReg
1577 This function is called each second during the boot manager waits the
1580 @param TimeoutRemain The remaining timeout.
1584 PlatformBootManagerWaitCallback (
1585 UINT16 TimeoutRemain
1588 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1589 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1592 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1594 Black
.Raw
= 0x00000000;
1595 White
.Raw
= 0x00FFFFFF;
1597 BootLogoUpdateProgress (
1600 L
"Start boot option",
1602 (Timeout
- TimeoutRemain
) * 100 / Timeout
,
1608 The function is called when no boot option could be launched,
1609 including platform recovery options and options pointing to applications
1610 built into firmware volumes.
1612 If this function returns, BDS attempts to enter an infinite loop.
1616 PlatformBootManagerUnableToBoot (
1622 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu
;
1626 // BootManagerMenu doesn't contain the correct information when return status
1627 // is EFI_NOT_FOUND.
1629 Status
= EfiBootManagerGetBootManagerMenu (&BootManagerMenu
);
1630 if (EFI_ERROR (Status
)) {
1634 // Normally BdsDxe does not print anything to the system console, but this is
1635 // a last resort -- the end-user will likely not see any DEBUG messages
1636 // logged in this situation.
1638 // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
1639 // here to see if it makes sense to request and wait for a keypress.
1641 if (gST
->ConIn
!= NULL
) {
1643 "%a: No bootable option or device was found.\n"
1644 "%a: Press any key to enter the Boot Manager Menu.\n",
1648 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &Index
);
1649 ASSERT_EFI_ERROR (Status
);
1650 ASSERT (Index
== 0);
1653 // Drain any queued keys.
1655 while (!EFI_ERROR (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
))) {
1657 // just throw away Key
1663 EfiBootManagerBoot (&BootManagerMenu
);