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>
25 VOID
*mEfiDevPathNotifyReg
;
26 EFI_EVENT mEfiDevPathEvent
;
27 VOID
*mEmuVariableEventReg
;
28 EFI_EVENT mEmuVariableEvent
;
29 UINT16 mHostBridgeDevId
;
32 // Table of host IRQs matching PCI IRQs A-D
33 // (for configuring PCI Interrupt Line register)
35 CONST UINT8 PciHostIrqs
[] = {
36 0x0a, 0x0a, 0x0b, 0x0b
45 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
52 @param[in] Handle - Handle of PCI device instance
53 @param[in] PciIo - PCI IO protocol instance
54 @param[in] Pci - PCI Header register block
58 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
60 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
66 // Function prototypes
70 VisitAllInstancesOfProtocol (
72 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
77 VisitAllPciInstancesOfProtocol (
78 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
82 InstallDevicePathCallback (
87 PlatformRegisterFvBootOption (
95 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
96 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
97 UINTN BootOptionCount
;
98 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
99 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
100 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
102 Status
= gBS
->HandleProtocol (
104 &gEfiLoadedImageProtocolGuid
,
105 (VOID
**) &LoadedImage
107 ASSERT_EFI_ERROR (Status
);
109 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
110 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
111 ASSERT (DevicePath
!= NULL
);
112 DevicePath
= AppendDevicePathNode (
114 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
116 ASSERT (DevicePath
!= NULL
);
118 Status
= EfiBootManagerInitializeLoadOption (
120 LoadOptionNumberUnassigned
,
128 ASSERT_EFI_ERROR (Status
);
129 FreePool (DevicePath
);
131 BootOptions
= EfiBootManagerGetLoadOptions (
132 &BootOptionCount
, LoadOptionTypeBoot
135 OptionIndex
= EfiBootManagerFindLoadOption (
136 &NewOption
, BootOptions
, BootOptionCount
139 if (OptionIndex
== -1) {
140 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
141 ASSERT_EFI_ERROR (Status
);
143 EfiBootManagerFreeLoadOption (&NewOption
);
144 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
148 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
149 whose device paths do not resolve exactly to an FvFile in the system.
151 This removes any boot options that point to binaries built into the firmware
152 and have become stale due to any of the following:
153 - DXEFV's base address or size changed (historical),
154 - DXEFV's FvNameGuid changed,
155 - the FILE_GUID of the pointed-to binary changed,
156 - the referenced binary is no longer built into the firmware.
158 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
159 avoids exact duplicates.
162 RemoveStaleFvFileOptions (
166 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
167 UINTN BootOptionCount
;
170 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
,
173 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
174 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
179 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
180 // then keep the boot option.
182 Node1
= BootOptions
[Index
].FilePath
;
183 if (!(DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
&&
184 DevicePathSubType (Node1
) == HW_MEMMAP_DP
) &&
185 !(DevicePathType (Node1
) == MEDIA_DEVICE_PATH
&&
186 DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)) {
191 // If the second device path node is not FvFile(...), then keep the boot
194 Node2
= NextDevicePathNode (Node1
);
195 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
196 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
201 // Locate the Firmware Volume2 protocol instance that is denoted by the
202 // boot option. If this lookup fails (i.e., the boot option references a
203 // firmware volume that doesn't exist), then we'll proceed to delete the
207 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
,
208 &SearchNode
, &FvHandle
);
210 if (!EFI_ERROR (Status
)) {
212 // The firmware volume was found; now let's see if it contains the FvFile
213 // identified by GUID.
215 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
216 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
218 EFI_FV_FILETYPE FoundType
;
219 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
220 UINT32 AuthenticationStatus
;
222 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
,
223 (VOID
**)&FvProtocol
);
224 ASSERT_EFI_ERROR (Status
);
226 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
228 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
231 Status
= FvProtocol
->ReadFile (
233 &FvFileNode
->FvFileName
, // NameGuid
238 &AuthenticationStatus
240 if (!EFI_ERROR (Status
)) {
242 // The FvFile was found. Keep the boot option.
249 // Delete the boot option.
251 Status
= EfiBootManagerDeleteLoadOptionVariable (
252 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
254 CHAR16
*DevicePathString
;
256 DevicePathString
= ConvertDevicePathToText(BootOptions
[Index
].FilePath
,
259 EFI_ERROR (Status
) ? EFI_D_WARN
: EFI_D_VERBOSE
,
260 "%a: removing stale Boot#%04x %s: %r\n",
262 (UINT32
)BootOptions
[Index
].OptionNumber
,
263 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
266 if (DevicePathString
!= NULL
) {
267 FreePool (DevicePathString
);
272 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
276 PlatformRegisterOptionsAndKeys (
284 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
287 // Register ENTER as CONTINUE key
289 Enter
.ScanCode
= SCAN_NULL
;
290 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
291 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
292 ASSERT_EFI_ERROR (Status
);
295 // Map F2 to Boot Manager Menu
297 F2
.ScanCode
= SCAN_F2
;
298 F2
.UnicodeChar
= CHAR_NULL
;
299 Esc
.ScanCode
= SCAN_ESC
;
300 Esc
.UnicodeChar
= CHAR_NULL
;
301 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
302 ASSERT_EFI_ERROR (Status
);
303 Status
= EfiBootManagerAddKeyOptionVariable (
304 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
306 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
307 Status
= EfiBootManagerAddKeyOptionVariable (
308 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
310 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
316 IN EFI_HANDLE RootBridgeHandle
,
324 ConnectVirtioPciRng (
325 IN EFI_HANDLE Handle
,
337 // BDS Platform Functions
340 Do the platform init, can be customized by OEM/IBV
342 Possible things that can be done in PlatformBootManagerBeforeConsole:
344 > Update console variable: 1. include hot-plug devices;
345 > 2. Clear ConIn and add SOL for AMT
346 > Register new Driver#### or Boot####
347 > Register new Key####: e.g.: F12
348 > Signal ReadyToLock event
349 > Authentication action: 1. connect Auth devices;
350 > 2. Identify auto logon user.
354 PlatformBootManagerBeforeConsole (
360 RETURN_STATUS PcdStatus
;
362 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
363 InstallDevicePathCallback ();
365 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
366 ConnectRootBridge
, NULL
);
369 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
371 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
374 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
375 // the preparation of S3 system information. That logic has a hard dependency
376 // on the presence of the FACS ACPI table. Since our ACPI tables are only
377 // installed after PCI enumeration completes, we must not trigger the S3 save
378 // earlier, hence we can't signal End-of-Dxe earlier.
380 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
382 if (QemuFwCfgS3Enabled ()) {
384 // Save the boot script too. Note that this will require us to emit the
385 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
391 // Prevent further changes to LockBoxes or SMRAM.
394 Status
= gBS
->InstallProtocolInterface (&Handle
,
395 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
397 ASSERT_EFI_ERROR (Status
);
400 // Dispatch deferred images after EndOfDxe event and ReadyToLock
403 EfiBootManagerDispatchDeferredImages ();
405 PlatformInitializeConsole (gPlatformConsole
);
406 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
,
407 GetFrontPageTimeoutFromQemu ());
408 ASSERT_RETURN_ERROR (PcdStatus
);
410 PlatformRegisterOptionsAndKeys ();
413 // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
414 // instances on Virtio PCI RNG devices.
416 VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid
, ConnectVirtioPciRng
,
424 IN EFI_HANDLE RootBridgeHandle
,
432 // Make the PCI bus driver connect the root bridge, non-recursively. This
433 // will produce a number of child handles with PciIo on them.
435 Status
= gBS
->ConnectController (
436 RootBridgeHandle
, // ControllerHandle
437 NULL
, // DriverImageHandle
438 NULL
, // RemainingDevicePath -- produce all
449 ConnectVirtioPciRng (
450 IN EFI_HANDLE Handle
,
455 EFI_PCI_IO_PROTOCOL
*PciIo
;
466 // Read and check VendorId.
468 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_VENDOR_ID_OFFSET
,
470 if (EFI_ERROR (Status
)) {
473 if (VendorId
!= VIRTIO_VENDOR_ID
) {
478 // Read DeviceId and RevisionId.
480 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
, PCI_DEVICE_ID_OFFSET
,
482 if (EFI_ERROR (Status
)) {
485 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, PCI_REVISION_ID_OFFSET
,
487 if (EFI_ERROR (Status
)) {
492 // From DeviceId and RevisionId, determine whether the device is a
493 // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
494 // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
495 // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
496 // only be sanity-checked, and SubsystemId will decide.
498 if (DeviceId
== 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
&&
499 RevisionId
>= 0x01) {
501 } else if (DeviceId
>= 0x1000 && DeviceId
<= 0x103F && RevisionId
== 0x00) {
508 // Read and check SubsystemId as dictated by Virtio10.
510 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint16
,
511 PCI_SUBSYSTEM_ID_OFFSET
, 1, &SubsystemId
);
512 if (EFI_ERROR (Status
)) {
515 if ((Virtio10
&& SubsystemId
>= 0x40) ||
516 (!Virtio10
&& SubsystemId
== VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
)) {
517 Status
= gBS
->ConnectController (
518 Handle
, // ControllerHandle
519 NULL
, // DriverImageHandle -- connect all drivers
520 NULL
, // RemainingDevicePath -- produce all child handles
521 FALSE
// Recursive -- don't follow child handles
523 if (EFI_ERROR (Status
)) {
530 DEBUG ((DEBUG_ERROR
, "%a: %r\n", __FUNCTION__
, Status
));
536 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
538 @param[in] DeviceHandle Handle of the LPC Bridge device.
540 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
541 ConOut, ConIn, and ErrOut.
543 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
547 PrepareLpcBridgeDevicePath (
548 IN EFI_HANDLE DeviceHandle
552 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
553 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
557 Status
= gBS
->HandleProtocol (
559 &gEfiDevicePathProtocolGuid
,
562 if (EFI_ERROR (Status
)) {
565 TempDevicePath
= DevicePath
;
570 DevicePath
= AppendDevicePathNode (DevicePath
,
571 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
573 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
578 DevicePath
= TempDevicePath
;
579 gPnp16550ComPortDeviceNode
.UID
= 0;
581 DevicePath
= AppendDevicePathNode (DevicePath
,
582 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
583 DevicePath
= AppendDevicePathNode (DevicePath
,
584 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
585 DevicePath
= AppendDevicePathNode (DevicePath
,
586 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
591 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
592 if (DevPathStr
!= NULL
) {
595 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
597 gPnp16550ComPortDeviceNode
.UID
+ 1,
600 FreePool(DevPathStr
);
603 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
604 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
605 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
610 DevicePath
= TempDevicePath
;
611 gPnp16550ComPortDeviceNode
.UID
= 1;
613 DevicePath
= AppendDevicePathNode (DevicePath
,
614 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
615 DevicePath
= AppendDevicePathNode (DevicePath
,
616 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
617 DevicePath
= AppendDevicePathNode (DevicePath
,
618 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
623 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
624 if (DevPathStr
!= NULL
) {
627 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
629 gPnp16550ComPortDeviceNode
.UID
+ 1,
632 FreePool(DevPathStr
);
635 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
636 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
637 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
644 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
645 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
650 EFI_HANDLE PciDeviceHandle
;
651 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
652 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
653 UINTN GopHandleCount
;
654 EFI_HANDLE
*GopHandleBuffer
;
656 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
657 return EFI_INVALID_PARAMETER
;
661 // Initialize the GopDevicePath to be PciDevicePath
663 *GopDevicePath
= PciDevicePath
;
664 TempPciDevicePath
= PciDevicePath
;
666 Status
= gBS
->LocateDevicePath (
667 &gEfiDevicePathProtocolGuid
,
671 if (EFI_ERROR (Status
)) {
676 // Try to connect this handle, so that GOP driver could start on this
677 // device and create child handles with GraphicsOutput Protocol installed
678 // on them, then we get device paths of these child handles and select
679 // them as possible console device.
681 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
683 Status
= gBS
->LocateHandleBuffer (
685 &gEfiGraphicsOutputProtocolGuid
,
690 if (!EFI_ERROR (Status
)) {
692 // Add all the child handles as possible Console Device
694 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
695 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
696 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
697 if (EFI_ERROR (Status
)) {
703 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
706 // In current implementation, we only enable one of the child handles
707 // as console device, i.e. sotre one of the child handle's device
708 // path to variable "ConOut"
709 // In future, we could select all child handles to be console device
712 *GopDevicePath
= TempDevicePath
;
715 // Delete the PCI device's path that added by
716 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
718 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
719 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
722 gBS
->FreePool (GopHandleBuffer
);
729 Add PCI display to ConOut.
731 @param[in] DeviceHandle Handle of the PCI display device.
733 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
735 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
739 PreparePciDisplayDevicePath (
740 IN EFI_HANDLE DeviceHandle
744 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
745 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
748 GopDevicePath
= NULL
;
749 Status
= gBS
->HandleProtocol (
751 &gEfiDevicePathProtocolGuid
,
754 if (EFI_ERROR (Status
)) {
758 GetGopDevicePath (DevicePath
, &GopDevicePath
);
759 DevicePath
= GopDevicePath
;
761 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
767 Add PCI Serial to ConOut, ConIn, ErrOut.
769 @param[in] DeviceHandle Handle of the PCI serial device.
771 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
774 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
778 PreparePciSerialDevicePath (
779 IN EFI_HANDLE DeviceHandle
783 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
786 Status
= gBS
->HandleProtocol (
788 &gEfiDevicePathProtocolGuid
,
791 if (EFI_ERROR (Status
)) {
795 DevicePath
= AppendDevicePathNode (DevicePath
,
796 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
797 DevicePath
= AppendDevicePathNode (DevicePath
,
798 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
800 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
801 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
802 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
808 VisitAllInstancesOfProtocol (
810 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
816 EFI_HANDLE
*HandleBuffer
;
821 // Start to check all the PciIo to find all possible device
825 Status
= gBS
->LocateHandleBuffer (
832 if (EFI_ERROR (Status
)) {
836 for (Index
= 0; Index
< HandleCount
; Index
++) {
837 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
838 if (EFI_ERROR (Status
)) {
842 Status
= (*CallBackFunction
) (
849 gBS
->FreePool (HandleBuffer
);
857 VisitingAPciInstance (
858 IN EFI_HANDLE Handle
,
864 EFI_PCI_IO_PROTOCOL
*PciIo
;
867 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
870 // Check for all PCI device
872 Status
= PciIo
->Pci
.Read (
876 sizeof (Pci
) / sizeof (UINT32
),
879 if (EFI_ERROR (Status
)) {
883 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
894 VisitAllPciInstances (
895 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
898 return VisitAllInstancesOfProtocol (
899 &gEfiPciIoProtocolGuid
,
900 VisitingAPciInstance
,
901 (VOID
*)(UINTN
) CallBackFunction
907 Do platform specific PCI Device check and add them to
908 ConOut, ConIn, ErrOut.
910 @param[in] Handle - Handle of PCI device instance
911 @param[in] PciIo - PCI IO protocol instance
912 @param[in] Pci - PCI Header register block
914 @retval EFI_SUCCESS - PCI Device check and Console variable update
916 @retval EFI_STATUS - PCI Device check or Console variable update fail.
921 DetectAndPreparePlatformPciDevicePath (
922 IN EFI_HANDLE Handle
,
923 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
929 Status
= PciIo
->Attributes (
931 EfiPciIoAttributeOperationEnable
,
932 EFI_PCI_DEVICE_ENABLE
,
935 ASSERT_EFI_ERROR (Status
);
938 // Here we decide whether it is LPC Bridge
940 if ((IS_PCI_LPC (Pci
)) ||
941 ((IS_PCI_ISA_PDECODE (Pci
)) &&
942 (Pci
->Hdr
.VendorId
== 0x8086) &&
943 (Pci
->Hdr
.DeviceId
== 0x7000)
947 // Add IsaKeyboard to ConIn,
948 // add IsaSerial to ConOut, ConIn, ErrOut
950 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
951 PrepareLpcBridgeDevicePath (Handle
);
955 // Here we decide which Serial device to enable in PCI bus
957 if (IS_PCI_16550SERIAL (Pci
)) {
959 // Add them to ConOut, ConIn, ErrOut.
961 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
962 PreparePciSerialDevicePath (Handle
);
967 // Here we decide which display device to enable in PCI bus
969 if (IS_PCI_DISPLAY (Pci
)) {
971 // Add them to ConOut.
973 DEBUG ((EFI_D_INFO
, "Found PCI display device\n"));
974 PreparePciDisplayDevicePath (Handle
);
983 Connect the predefined platform default console device.
985 Always try to find and enable PCI display devices.
987 @param[in] PlatformConsole Predefined platform default console device array.
990 PlatformInitializeConsole (
991 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
997 // Do platform specific PCI Device check and add them to ConOut, ConIn,
1000 VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
1003 // Have chance to connect the platform default console,
1004 // the platform default console is the minimum device group
1005 // the platform should support
1007 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
1009 // Update the console variable with the connect type
1011 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
1012 EfiBootManagerUpdateConsoleVariable (ConIn
,
1013 PlatformConsole
[Index
].DevicePath
, NULL
);
1015 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
1016 EfiBootManagerUpdateConsoleVariable (ConOut
,
1017 PlatformConsole
[Index
].DevicePath
, NULL
);
1019 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
1020 EfiBootManagerUpdateConsoleVariable (ErrOut
,
1021 PlatformConsole
[Index
].DevicePath
, NULL
);
1028 Configure PCI Interrupt Line register for applicable devices
1029 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
1031 @param[in] Handle - Handle of PCI device instance
1032 @param[in] PciIo - PCI IO protocol instance
1033 @param[in] PciHdr - PCI Header register block
1035 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1041 IN EFI_HANDLE Handle
,
1042 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1043 IN PCI_TYPE00
*PciHdr
1046 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1047 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1052 UINT32 RootBusNumber
;
1054 Status
= EFI_SUCCESS
;
1056 if (PciHdr
->Device
.InterruptPin
!= 0) {
1058 DevPathNode
= DevicePathFromHandle (Handle
);
1059 ASSERT (DevPathNode
!= NULL
);
1060 DevPath
= DevPathNode
;
1063 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1064 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1065 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1066 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1070 // Compute index into PciHostIrqs[] table by walking
1071 // the device path and adding up all device numbers
1073 Status
= EFI_NOT_FOUND
;
1075 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1076 while (!IsDevicePathEnd (DevPathNode
)) {
1077 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1078 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1080 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1083 // Unlike SeaBIOS, which starts climbing from the leaf device
1084 // up toward the root, we traverse the device path starting at
1085 // the root moving toward the leaf node.
1086 // The slot number of the top-level parent bridge is needed for
1087 // Q35 cases with more than 24 slots on the root bus.
1089 if (Status
!= EFI_SUCCESS
) {
1090 Status
= EFI_SUCCESS
;
1091 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1095 DevPathNode
= NextDevicePathNode (DevPathNode
);
1097 if (EFI_ERROR (Status
)) {
1100 if (RootBusNumber
== 0 && RootSlot
== 0) {
1103 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1110 // Final PciHostIrqs[] index calculation depends on the platform
1111 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1113 switch (mHostBridgeDevId
) {
1114 case INTEL_82441_DEVICE_ID
:
1117 case INTEL_Q35_MCH_DEVICE_ID
:
1119 // SeaBIOS contains the following comment:
1120 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1121 // with a different starting index - see q35-acpi-dsdt.dsl.
1123 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1125 if (RootSlot
> 24) {
1127 // in this case, subtract back out RootSlot from Idx
1128 // (SeaBIOS never adds it to begin with, but that would make our
1129 // device path traversal loop above too awkward)
1135 ASSERT (FALSE
); // should never get here
1137 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1138 IrqLine
= PciHostIrqs
[Idx
];
1140 DEBUG_CODE_BEGIN ();
1142 CHAR16
*DevPathString
;
1143 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1144 UINTN Segment
, Bus
, Device
, Function
;
1146 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1147 if (DevPathString
== NULL
) {
1148 DevPathString
= Fallback
;
1150 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1151 ASSERT_EFI_ERROR (Status
);
1153 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1154 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1157 if (DevPathString
!= Fallback
) {
1158 FreePool (DevPathString
);
1164 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1166 Status
= PciIo
->Pci
.Write (
1169 PCI_INT_LINE_OFFSET
,
1180 PciAcpiInitialization (
1186 // Query Host Bridge DID to determine platform type
1188 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1189 switch (mHostBridgeDevId
) {
1190 case INTEL_82441_DEVICE_ID
:
1191 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1193 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1195 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1196 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1197 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1198 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1200 case INTEL_Q35_MCH_DEVICE_ID
:
1201 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1203 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1205 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1206 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1207 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1208 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1209 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1210 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1211 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1212 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1215 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1216 __FUNCTION__
, mHostBridgeDevId
));
1222 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1224 VisitAllPciInstances (SetPciIntLine
);
1227 // Set ACPI SCI_EN bit in PMCNTRL
1229 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1233 This function detects if OVMF is running on Xen.
1242 EFI_HOB_GUID_TYPE
*GuidHob
;
1243 STATIC INTN FoundHob
= -1;
1245 if (FoundHob
== 0) {
1247 } else if (FoundHob
== 1) {
1252 // See if a XenInfo HOB is available
1254 GuidHob
= GetFirstGuidHob (&gEfiXenInfoGuid
);
1255 if (GuidHob
== NULL
) {
1266 ConnectRecursivelyIfPciMassStorage (
1267 IN EFI_HANDLE Handle
,
1268 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1269 IN PCI_TYPE00
*PciHeader
1273 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1277 // Recognize PCI Mass Storage, and Xen PCI devices
1279 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1280 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1282 Status
= gBS
->HandleProtocol (
1284 &gEfiDevicePathProtocolGuid
,
1287 if (EFI_ERROR (Status
)) {
1292 // Print Device Path
1294 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1295 if (DevPathStr
!= NULL
) {
1298 "Found %s device: %s\n",
1299 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1305 FreePool(DevPathStr
);
1308 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1309 if (EFI_ERROR (Status
)) {
1320 This notification function is invoked when the
1321 EMU Variable FVB has been changed.
1323 @param Event The event that occurred
1324 @param Context For EFI compatibility. Not used.
1329 EmuVariablesUpdatedCallback (
1334 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1335 UpdateNvVarsOnFileSystem ();
1341 VisitingFileSystemInstance (
1342 IN EFI_HANDLE Handle
,
1348 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1349 RETURN_STATUS PcdStatus
;
1351 if (ConnectedToFileSystem
) {
1352 return EFI_ALREADY_STARTED
;
1355 Status
= ConnectNvVarsToFileSystem (Handle
);
1356 if (EFI_ERROR (Status
)) {
1360 ConnectedToFileSystem
= TRUE
;
1362 EfiCreateProtocolNotifyEvent (
1363 &gEfiDevicePathProtocolGuid
,
1365 EmuVariablesUpdatedCallback
,
1367 &mEmuVariableEventReg
1369 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1370 (UINT64
)(UINTN
) mEmuVariableEvent
);
1371 ASSERT_RETURN_ERROR (PcdStatus
);
1378 PlatformBdsRestoreNvVarsFromHardDisk (
1381 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1382 VisitAllInstancesOfProtocol (
1383 &gEfiSimpleFileSystemProtocolGuid
,
1384 VisitingFileSystemInstance
,
1391 Connect with predefined platform connect sequence.
1393 The OEM/IBV can customize with their own connect sequence.
1396 PlatformBdsConnectSequence (
1401 RETURN_STATUS Status
;
1403 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1408 // Here we can get the customized platform connect sequence
1409 // Notes: we can connect with new variable which record the
1410 // last time boots connect device path sequence
1412 while (gPlatformConnectSequence
[Index
] != NULL
) {
1414 // Build the platform boot option
1416 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1420 Status
= ConnectDevicesFromQemu ();
1421 if (RETURN_ERROR (Status
)) {
1423 // Just use the simple policy to connect all devices
1425 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1426 EfiBootManagerConnectAll ();
1431 Save the S3 boot script.
1433 Note that DxeSmmReadyToLock must be signaled after this function returns;
1434 otherwise the script wouldn't be saved actually.
1443 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1444 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1446 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1447 (VOID
**) &BootScript
);
1448 ASSERT_EFI_ERROR (Status
);
1451 // Despite the opcode documentation in the PI spec, the protocol
1452 // implementation embeds a deep copy of the info in the boot script, rather
1453 // than storing just a pointer to runtime or NVS storage.
1455 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1456 (UINT32
) sizeof Info
,
1457 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1458 ASSERT_EFI_ERROR (Status
);
1463 Do the platform specific action after the console is ready
1465 Possible things that can be done in PlatformBootManagerAfterConsole:
1467 > Console post action:
1468 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1469 > Signal console ready platform customized event
1470 > Run diagnostics like memory testing
1471 > Connect certain devices
1472 > Dispatch aditional option roms
1473 > Special boot: e.g.: USB boot, enter UI
1477 PlatformBootManagerAfterConsole (
1481 EFI_BOOT_MODE BootMode
;
1483 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1485 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1486 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1487 "from disk since flash variables appear to be supported.\n"));
1490 // Try to restore variables from the hard disk early so
1491 // they can be used for the other BDS connect operations.
1493 PlatformBdsRestoreNvVarsFromHardDisk ();
1497 // Get current Boot Mode
1499 BootMode
= GetBootModeHob ();
1500 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1503 // Go the different platform policy with different boot mode
1504 // Notes: this part code can be change with the table policy
1506 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1511 BootLogoEnableLogo ();
1514 // Set PCI Interrupt Line registers and ACPI SCI_EN
1516 PciAcpiInitialization ();
1519 // Process QEMU's -kernel command line option
1521 TryRunningQemuKernel ();
1524 // Perform some platform specific connect sequence
1526 PlatformBdsConnectSequence ();
1528 EfiBootManagerRefreshAllBootOption ();
1531 // Register UEFI Shell
1533 PlatformRegisterFvBootOption (
1534 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1537 RemoveStaleFvFileOptions ();
1538 SetBootOrderFromQemu ();
1542 This notification function is invoked when an instance of the
1543 EFI_DEVICE_PATH_PROTOCOL is produced.
1545 @param Event The event that occurred
1546 @param Context For EFI compatibility. Not used.
1559 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1560 ATAPI_DEVICE_PATH
*Atapi
;
1563 // Examine all new handles
1567 // Get the next handle
1569 BufferSize
= sizeof (Handle
);
1570 Status
= gBS
->LocateHandle (
1573 mEfiDevPathNotifyReg
,
1579 // If not found, we're done
1581 if (EFI_NOT_FOUND
== Status
) {
1585 if (EFI_ERROR (Status
)) {
1590 // Get the DevicePath protocol on that handle
1592 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1593 (VOID
**)&DevPathNode
);
1594 ASSERT_EFI_ERROR (Status
);
1596 while (!IsDevicePathEnd (DevPathNode
)) {
1598 // Find the handler to dump this device path node
1601 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1602 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1604 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1610 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1617 // Next device path node
1619 DevPathNode
= NextDevicePathNode (DevPathNode
);
1628 InstallDevicePathCallback (
1632 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1633 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1634 &gEfiDevicePathProtocolGuid
,
1638 &mEfiDevPathNotifyReg
1643 This function is called each second during the boot manager waits the
1646 @param TimeoutRemain The remaining timeout.
1650 PlatformBootManagerWaitCallback (
1651 UINT16 TimeoutRemain
1654 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1655 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1658 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1660 Black
.Raw
= 0x00000000;
1661 White
.Raw
= 0x00FFFFFF;
1663 BootLogoUpdateProgress (
1666 L
"Start boot option",
1668 (Timeout
- TimeoutRemain
) * 100 / Timeout
,