2 Platform BDS customizations.
4 Copyright (C) 2020 James Bottomley, IBM Corporation.
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>
21 VOID
*mEfiDevPathNotifyReg
;
22 EFI_EVENT mEfiDevPathEvent
;
23 UINT16 mHostBridgeDevId
;
26 // Table of host IRQs matching PCI IRQs A-D
27 // (for configuring PCI Interrupt Line register)
29 CONST UINT8 PciHostIrqs
[] = {
30 0x0a, 0x0a, 0x0b, 0x0b
39 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
46 @param[in] Handle - Handle of PCI device instance
47 @param[in] PciIo - PCI IO protocol instance
48 @param[in] Pci - PCI Header register block
52 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
54 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
60 // Function prototypes
64 VisitAllInstancesOfProtocol (
66 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
71 VisitAllPciInstancesOfProtocol (
72 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
76 InstallDevicePathCallback (
81 PlatformRegisterFvBootOption (
89 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
90 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
91 UINTN BootOptionCount
;
92 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
93 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
94 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
96 Status
= gBS
->HandleProtocol (
98 &gEfiLoadedImageProtocolGuid
,
99 (VOID
**) &LoadedImage
101 ASSERT_EFI_ERROR (Status
);
103 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
104 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
105 ASSERT (DevicePath
!= NULL
);
106 DevicePath
= AppendDevicePathNode (
108 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
110 ASSERT (DevicePath
!= NULL
);
112 Status
= EfiBootManagerInitializeLoadOption (
114 LoadOptionNumberUnassigned
,
122 ASSERT_EFI_ERROR (Status
);
123 FreePool (DevicePath
);
125 BootOptions
= EfiBootManagerGetLoadOptions (
126 &BootOptionCount
, LoadOptionTypeBoot
129 OptionIndex
= EfiBootManagerFindLoadOption (
130 &NewOption
, BootOptions
, BootOptionCount
133 if (OptionIndex
== -1) {
134 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
135 ASSERT_EFI_ERROR (Status
);
137 EfiBootManagerFreeLoadOption (&NewOption
);
138 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
142 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
143 whose device paths do not resolve exactly to an FvFile in the system.
145 Also strip out every boot option that is not an FvFile, meaning the system
146 can only boot either the Grub or (if built) the shell.
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 delete 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
)) {
184 EfiBootManagerDeleteLoadOptionVariable (
185 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
190 // If the second device path node is not FvFile(...), then delete the boot
193 Node2
= NextDevicePathNode (Node1
);
194 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
195 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
196 EfiBootManagerDeleteLoadOptionVariable (
197 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
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
) ? DEBUG_WARN
: DEBUG_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
);
279 IN EFI_HANDLE RootBridgeHandle
,
287 ConnectVirtioPciRng (
288 IN EFI_HANDLE Handle
,
294 // BDS Platform Functions
297 Do the platform init, can be customized by OEM/IBV
299 Possible things that can be done in PlatformBootManagerBeforeConsole:
301 > Update console variable: 1. include hot-plug devices;
302 > 2. Clear ConIn and add SOL for AMT
303 > Register new Driver#### or Boot####
304 > Register new Key####: e.g.: F12
305 > Signal ReadyToLock event
306 > Authentication action: 1. connect Auth devices;
307 > 2. Identify auto logon user.
311 PlatformBootManagerBeforeConsole (
317 UINT16 FrontPageTimeout
;
319 FrontPageTimeout
= 0;
321 DEBUG ((DEBUG_INFO
, "PlatformBootManagerBeforeConsole\n"));
322 InstallDevicePathCallback ();
324 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
325 ConnectRootBridge
, NULL
);
328 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
330 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
333 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
334 // the preparation of S3 system information. That logic has a hard dependency
335 // on the presence of the FACS ACPI table. Since our ACPI tables are only
336 // installed after PCI enumeration completes, we must not trigger the S3 save
337 // earlier, hence we can't signal End-of-Dxe earlier.
339 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
341 // We need to connect all trusted consoles for TCG PP. Here we treat all
342 // consoles in OVMF to be trusted consoles.
343 PlatformInitializeConsole (gPlatformConsole
);
346 // Process TPM PPI request
348 Tcg2PhysicalPresenceLibProcessRequest (NULL
);
351 // Prevent further changes to LockBoxes or SMRAM.
352 // Any TPM 2 Physical Presence Interface opcode must be handled before.
355 Status
= gBS
->InstallProtocolInterface (&Handle
,
356 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
358 ASSERT_EFI_ERROR (Status
);
361 // Dispatch deferred images after EndOfDxe event and ReadyToLock
364 EfiBootManagerDispatchDeferredImages ();
366 Status
= gRT
->SetVariable (
367 EFI_TIME_OUT_VARIABLE_NAME
,
368 &gEfiGlobalVariableGuid
,
369 (EFI_VARIABLE_NON_VOLATILE
|
370 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
371 EFI_VARIABLE_RUNTIME_ACCESS
),
372 sizeof FrontPageTimeout
,
376 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
377 // instances on Virtio PCI RNG devices.
379 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
387 IN EFI_HANDLE RootBridgeHandle
,
395 // Make the PCI bus driver connect the root bridge, non-recursively. This
396 // will produce a number of child handles with PciIo on them.
398 Status
= gBS
->ConnectController (
399 RootBridgeHandle
, // ControllerHandle
400 NULL
, // DriverImageHandle
401 NULL
, // RemainingDevicePath -- produce all
412 ConnectVirtioPciRng (
413 IN EFI_HANDLE Handle
,
418 EFI_PCI_IO_PROTOCOL
*PciIo
;
429 // Read and check VendorId.
431 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
433 if (EFI_ERROR (Status
)) {
436 if (VendorId
!= VIRTIO_VENDOR_ID
) {
441 // Read DeviceId and RevisionId.
443 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
445 if (EFI_ERROR (Status
)) {
448 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
450 if (EFI_ERROR (Status
)) {
455 // From DeviceId and RevisionId, determine whether the device is a
456 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
457 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
458 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
459 // only be sanity-checked, and SubsystemId will decide.
461 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
462 RevisionId
>= 0x01) {
464 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
471 // Read and check SubsystemId as dictated by Virtio10.
473 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
474 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
475 if (EFI_ERROR (Status
)) {
478 if ((Virtio10
&& SubsystemId
>= 0x40) ||
479 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
480 Status
= gBS
->ConnectController (
481 Handle
, // ControllerHandle
482 NULL
, // DriverImageHandle -- connect all drivers
483 NULL
, // RemainingDevicePath -- produce all child handles
484 FALSE
// Recursive -- don't follow child handles
486 if (EFI_ERROR (Status
)) {
493 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
499 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
501 @param[in] DeviceHandle Handle of the LPC Bridge device.
503 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
504 ConOut, ConIn, and ErrOut.
506 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
510 PrepareLpcBridgeDevicePath (
511 IN EFI_HANDLE DeviceHandle
515 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
516 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
520 Status
= gBS
->HandleProtocol (
522 &gEfiDevicePathProtocolGuid
,
525 if (EFI_ERROR (Status
)) {
528 TempDevicePath
= DevicePath
;
533 DevicePath
= AppendDevicePathNode (DevicePath
,
534 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
536 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
541 DevicePath
= TempDevicePath
;
542 gPnp16550ComPortDeviceNode
.UID
= 0;
544 DevicePath
= AppendDevicePathNode (DevicePath
,
545 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
546 DevicePath
= AppendDevicePathNode (DevicePath
,
547 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
548 DevicePath
= AppendDevicePathNode (DevicePath
,
549 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
554 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
555 if (DevPathStr
!= NULL
) {
558 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
560 gPnp16550ComPortDeviceNode
.UID
+ 1,
563 FreePool(DevPathStr
);
566 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
567 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
568 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
573 DevicePath
= TempDevicePath
;
574 gPnp16550ComPortDeviceNode
.UID
= 1;
576 DevicePath
= AppendDevicePathNode (DevicePath
,
577 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
578 DevicePath
= AppendDevicePathNode (DevicePath
,
579 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
580 DevicePath
= AppendDevicePathNode (DevicePath
,
581 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
586 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
587 if (DevPathStr
!= NULL
) {
590 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
592 gPnp16550ComPortDeviceNode
.UID
+ 1,
595 FreePool(DevPathStr
);
598 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
599 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
600 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
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 INTEL_82441_DEVICE_ID
:
1080 case INTEL_Q35_MCH_DEVICE_ID
:
1082 // SeaBIOS contains the following comment:
1083 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1084 // with a different starting index - see q35-acpi-dsdt.dsl.
1086 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1088 if (RootSlot
> 24) {
1090 // in this case, subtract back out RootSlot from Idx
1091 // (SeaBIOS never adds it to begin with, but that would make our
1092 // device path traversal loop above too awkward)
1098 ASSERT (FALSE
); // should never get here
1100 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1101 IrqLine
= PciHostIrqs
[Idx
];
1103 DEBUG_CODE_BEGIN ();
1105 CHAR16
*DevPathString
;
1106 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1107 UINTN Segment
, Bus
, Device
, Function
;
1109 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1110 if (DevPathString
== NULL
) {
1111 DevPathString
= Fallback
;
1113 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1114 ASSERT_EFI_ERROR (Status
);
1116 DEBUG ((DEBUG_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1117 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1120 if (DevPathString
!= Fallback
) {
1121 FreePool (DevPathString
);
1127 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1129 Status
= PciIo
->Pci
.Write (
1132 PCI_INT_LINE_OFFSET
,
1143 PciAcpiInitialization (
1149 // Query Host Bridge DID to determine platform type
1151 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1152 switch (mHostBridgeDevId
) {
1153 case INTEL_82441_DEVICE_ID
:
1154 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1156 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1158 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1159 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1160 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1161 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1163 case INTEL_Q35_MCH_DEVICE_ID
:
1164 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1166 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1168 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1169 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1170 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1171 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1172 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1173 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1174 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1175 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1178 DEBUG ((DEBUG_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1179 __FUNCTION__
, mHostBridgeDevId
));
1185 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1187 VisitAllPciInstances (SetPciIntLine
);
1190 // Set ACPI SCI_EN bit in PMCNTRL
1192 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1197 ConnectRecursivelyIfPciMassStorage (
1198 IN EFI_HANDLE Handle
,
1199 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1200 IN PCI_TYPE00
*PciHeader
1204 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1208 // Recognize PCI Mass Storage
1210 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
)) {
1212 Status
= gBS
->HandleProtocol (
1214 &gEfiDevicePathProtocolGuid
,
1217 if (EFI_ERROR (Status
)) {
1222 // Print Device Path
1224 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1225 if (DevPathStr
!= NULL
) {
1228 "Found Mass Storage device: %s\n",
1231 FreePool(DevPathStr
);
1234 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1235 if (EFI_ERROR (Status
)) {
1246 Connect with predefined platform connect sequence.
1248 The OEM/IBV can customize with their own connect sequence.
1251 PlatformBdsConnectSequence (
1257 DEBUG ((DEBUG_INFO
, "PlatformBdsConnectSequence\n"));
1262 // Here we can get the customized platform connect sequence
1263 // Notes: we can connect with new variable which record the
1264 // last time boots connect device path sequence
1266 while (gPlatformConnectSequence
[Index
] != NULL
) {
1268 // Build the platform boot option
1270 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1273 EfiBootManagerConnectAll ();
1277 Do the platform specific action after the console is ready
1279 Possible things that can be done in PlatformBootManagerAfterConsole:
1281 > Console post action:
1282 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1283 > Signal console ready platform customized event
1284 > Run diagnostics like memory testing
1285 > Connect certain devices
1286 > Dispatch aditional option roms
1287 > Special boot: e.g.: USB boot, enter UI
1291 PlatformBootManagerAfterConsole (
1295 EFI_BOOT_MODE BootMode
;
1297 DEBUG ((DEBUG_INFO
, "PlatformBootManagerAfterConsole\n"));
1300 // Get current Boot Mode
1302 BootMode
= GetBootModeHob ();
1303 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1306 // Go the different platform policy with different boot mode
1307 // Notes: this part code can be change with the table policy
1309 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1314 BootLogoEnableLogo ();
1317 // Set PCI Interrupt Line registers and ACPI SCI_EN
1319 PciAcpiInitialization ();
1322 // Process QEMU's -kernel command line option
1324 TryRunningQemuKernel ();
1327 // Perform some platform specific connect sequence
1329 PlatformBdsConnectSequence ();
1331 EfiBootManagerRefreshAllBootOption ();
1334 // Register UEFI Shell (Will be removed if the Shell isn't built
1335 // which is the default)
1337 PlatformRegisterFvBootOption (
1338 &gUefiShellFileGuid
, L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1344 PlatformRegisterFvBootOption (
1345 &gGrubFileGuid
, L
"Grub Bootloader", LOAD_OPTION_ACTIVE
1348 RemoveStaleFvFileOptions ();
1350 PlatformBmPrintScRegisterHandler ();
1354 This notification function is invoked when an instance of the
1355 EFI_DEVICE_PATH_PROTOCOL is produced.
1357 @param Event The event that occurred
1358 @param Context For EFI compatibility. Not used.
1371 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1372 ATAPI_DEVICE_PATH
*Atapi
;
1375 // Examine all new handles
1379 // Get the next handle
1381 BufferSize
= sizeof (Handle
);
1382 Status
= gBS
->LocateHandle (
1385 mEfiDevPathNotifyReg
,
1391 // If not found, we're done
1393 if (EFI_NOT_FOUND
== Status
) {
1397 if (EFI_ERROR (Status
)) {
1402 // Get the DevicePath protocol on that handle
1404 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1405 (VOID
**)&DevPathNode
);
1406 ASSERT_EFI_ERROR (Status
);
1408 while (!IsDevicePathEnd (DevPathNode
)) {
1410 // Find the handler to dump this device path node
1413 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1414 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1416 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1422 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1429 // Next device path node
1431 DevPathNode
= NextDevicePathNode (DevPathNode
);
1440 InstallDevicePathCallback (
1444 DEBUG ((DEBUG_INFO
, "Registered NotifyDevPath Event\n"));
1445 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1446 &gEfiDevicePathProtocolGuid
,
1450 &mEfiDevPathNotifyReg
1455 This function is called each second during the boot manager waits the
1458 @param TimeoutRemain The remaining timeout.
1462 PlatformBootManagerWaitCallback (
1463 UINT16 TimeoutRemain
1467 // Since the timeout should be forced to zero we should never
1474 The function is called when no boot option could be launched,
1475 including platform recovery options and options pointing to applications
1476 built into firmware volumes.
1478 If this function returns, BDS attempts to enter an infinite loop.
1482 PlatformBootManagerUnableToBoot (
1487 // If we get here something failed about the grub boot but since
1488 // We're privy to the secret we must panic and not retry or loop