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 BOOLEAN mDetectVgaOnly
;
30 UINT16 mHostBridgeDevId
;
33 // Table of host IRQs matching PCI IRQs A-D
34 // (for configuring PCI Interrupt Line register)
36 CONST UINT8 PciHostIrqs
[] = {
37 0x0a, 0x0a, 0x0b, 0x0b
46 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
53 @param[in] Handle - Handle of PCI device instance
54 @param[in] PciIo - PCI IO protocol instance
55 @param[in] Pci - PCI Header register block
59 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
61 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
67 // Function prototypes
71 VisitAllInstancesOfProtocol (
73 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
78 VisitAllPciInstancesOfProtocol (
79 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
83 InstallDevicePathCallback (
88 PlatformRegisterFvBootOption (
96 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
97 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
98 UINTN BootOptionCount
;
99 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
100 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
101 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
103 Status
= gBS
->HandleProtocol (
105 &gEfiLoadedImageProtocolGuid
,
106 (VOID
**) &LoadedImage
108 ASSERT_EFI_ERROR (Status
);
110 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
111 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
112 ASSERT (DevicePath
!= NULL
);
113 DevicePath
= AppendDevicePathNode (
115 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
117 ASSERT (DevicePath
!= NULL
);
119 Status
= EfiBootManagerInitializeLoadOption (
121 LoadOptionNumberUnassigned
,
129 ASSERT_EFI_ERROR (Status
);
130 FreePool (DevicePath
);
132 BootOptions
= EfiBootManagerGetLoadOptions (
133 &BootOptionCount
, LoadOptionTypeBoot
136 OptionIndex
= EfiBootManagerFindLoadOption (
137 &NewOption
, BootOptions
, BootOptionCount
140 if (OptionIndex
== -1) {
141 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
142 ASSERT_EFI_ERROR (Status
);
144 EfiBootManagerFreeLoadOption (&NewOption
);
145 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
149 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
150 whose device paths do not resolve exactly to an FvFile in the system.
152 This removes any boot options that point to binaries built into the firmware
153 and have become stale due to any of the following:
154 - DXEFV's base address or size changed (historical),
155 - DXEFV's FvNameGuid changed,
156 - the FILE_GUID of the pointed-to binary changed,
157 - the referenced binary is no longer built into the firmware.
159 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
160 avoids exact duplicates.
163 RemoveStaleFvFileOptions (
167 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
168 UINTN BootOptionCount
;
171 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
,
174 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
175 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
180 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
181 // then keep the boot option.
183 Node1
= BootOptions
[Index
].FilePath
;
184 if (!(DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
&&
185 DevicePathSubType (Node1
) == HW_MEMMAP_DP
) &&
186 !(DevicePathType (Node1
) == MEDIA_DEVICE_PATH
&&
187 DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)) {
192 // If the second device path node is not FvFile(...), then keep the boot
195 Node2
= NextDevicePathNode (Node1
);
196 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
197 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
202 // Locate the Firmware Volume2 protocol instance that is denoted by the
203 // boot option. If this lookup fails (i.e., the boot option references a
204 // firmware volume that doesn't exist), then we'll proceed to delete the
208 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
,
209 &SearchNode
, &FvHandle
);
211 if (!EFI_ERROR (Status
)) {
213 // The firmware volume was found; now let's see if it contains the FvFile
214 // identified by GUID.
216 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
217 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
219 EFI_FV_FILETYPE FoundType
;
220 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
221 UINT32 AuthenticationStatus
;
223 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
,
224 (VOID
**)&FvProtocol
);
225 ASSERT_EFI_ERROR (Status
);
227 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
229 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
232 Status
= FvProtocol
->ReadFile (
234 &FvFileNode
->FvFileName
, // NameGuid
239 &AuthenticationStatus
241 if (!EFI_ERROR (Status
)) {
243 // The FvFile was found. Keep the boot option.
250 // Delete the boot option.
252 Status
= EfiBootManagerDeleteLoadOptionVariable (
253 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
255 CHAR16
*DevicePathString
;
257 DevicePathString
= ConvertDevicePathToText(BootOptions
[Index
].FilePath
,
260 EFI_ERROR (Status
) ? EFI_D_WARN
: EFI_D_VERBOSE
,
261 "%a: removing stale Boot#%04x %s: %r\n",
263 (UINT32
)BootOptions
[Index
].OptionNumber
,
264 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
267 if (DevicePathString
!= NULL
) {
268 FreePool (DevicePathString
);
273 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
277 PlatformRegisterOptionsAndKeys (
285 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
288 // Register ENTER as CONTINUE key
290 Enter
.ScanCode
= SCAN_NULL
;
291 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
292 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
293 ASSERT_EFI_ERROR (Status
);
296 // Map F2 to Boot Manager Menu
298 F2
.ScanCode
= SCAN_F2
;
299 F2
.UnicodeChar
= CHAR_NULL
;
300 Esc
.ScanCode
= SCAN_ESC
;
301 Esc
.UnicodeChar
= CHAR_NULL
;
302 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
303 ASSERT_EFI_ERROR (Status
);
304 Status
= EfiBootManagerAddKeyOptionVariable (
305 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
307 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
308 Status
= EfiBootManagerAddKeyOptionVariable (
309 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
311 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
317 IN EFI_HANDLE RootBridgeHandle
,
329 // BDS Platform Functions
333 PlatformBootManagerBeforeConsole (
340 Platform Bds init. Include the platform firmware vendor, revision
353 RETURN_STATUS PcdStatus
;
355 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
356 InstallDevicePathCallback ();
358 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
359 ConnectRootBridge
, NULL
);
362 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
364 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
367 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
368 // the preparation of S3 system information. That logic has a hard dependency
369 // on the presence of the FACS ACPI table. Since our ACPI tables are only
370 // installed after PCI enumeration completes, we must not trigger the S3 save
371 // earlier, hence we can't signal End-of-Dxe earlier.
373 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
375 if (QemuFwCfgS3Enabled ()) {
377 // Save the boot script too. Note that this will require us to emit the
378 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
384 // Prevent further changes to LockBoxes or SMRAM.
387 Status
= gBS
->InstallProtocolInterface (&Handle
,
388 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
390 ASSERT_EFI_ERROR (Status
);
393 // Dispatch deferred images after EndOfDxe event and ReadyToLock
396 EfiBootManagerDispatchDeferredImages ();
398 PlatformInitializeConsole (gPlatformConsole
);
399 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
,
400 GetFrontPageTimeoutFromQemu ());
401 ASSERT_RETURN_ERROR (PcdStatus
);
403 PlatformRegisterOptionsAndKeys ();
410 IN EFI_HANDLE RootBridgeHandle
,
418 // Make the PCI bus driver connect the root bridge, non-recursively. This
419 // will produce a number of child handles with PciIo on them.
421 Status
= gBS
->ConnectController (
422 RootBridgeHandle
, // ControllerHandle
423 NULL
, // DriverImageHandle
424 NULL
, // RemainingDevicePath -- produce all
433 PrepareLpcBridgeDevicePath (
434 IN EFI_HANDLE DeviceHandle
440 Add IsaKeyboard to ConIn,
441 add IsaSerial to ConOut, ConIn, ErrOut.
446 DeviceHandle - Handle of PCIIO protocol.
450 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
451 EFI_STATUS - No LPC bridge is added.
456 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
457 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
461 Status
= gBS
->HandleProtocol (
463 &gEfiDevicePathProtocolGuid
,
466 if (EFI_ERROR (Status
)) {
469 TempDevicePath
= DevicePath
;
474 DevicePath
= AppendDevicePathNode (DevicePath
,
475 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
477 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
482 DevicePath
= TempDevicePath
;
483 gPnp16550ComPortDeviceNode
.UID
= 0;
485 DevicePath
= AppendDevicePathNode (DevicePath
,
486 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
487 DevicePath
= AppendDevicePathNode (DevicePath
,
488 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
489 DevicePath
= AppendDevicePathNode (DevicePath
,
490 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
495 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
496 if (DevPathStr
!= NULL
) {
499 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
501 gPnp16550ComPortDeviceNode
.UID
+ 1,
504 FreePool(DevPathStr
);
507 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
508 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
509 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
514 DevicePath
= TempDevicePath
;
515 gPnp16550ComPortDeviceNode
.UID
= 1;
517 DevicePath
= AppendDevicePathNode (DevicePath
,
518 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
519 DevicePath
= AppendDevicePathNode (DevicePath
,
520 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
521 DevicePath
= AppendDevicePathNode (DevicePath
,
522 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
527 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
528 if (DevPathStr
!= NULL
) {
531 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
533 gPnp16550ComPortDeviceNode
.UID
+ 1,
536 FreePool(DevPathStr
);
539 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
540 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
541 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
548 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
549 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
554 EFI_HANDLE PciDeviceHandle
;
555 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
556 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
557 UINTN GopHandleCount
;
558 EFI_HANDLE
*GopHandleBuffer
;
560 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
561 return EFI_INVALID_PARAMETER
;
565 // Initialize the GopDevicePath to be PciDevicePath
567 *GopDevicePath
= PciDevicePath
;
568 TempPciDevicePath
= PciDevicePath
;
570 Status
= gBS
->LocateDevicePath (
571 &gEfiDevicePathProtocolGuid
,
575 if (EFI_ERROR (Status
)) {
580 // Try to connect this handle, so that GOP driver could start on this
581 // device and create child handles with GraphicsOutput Protocol installed
582 // on them, then we get device paths of these child handles and select
583 // them as possible console device.
585 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
587 Status
= gBS
->LocateHandleBuffer (
589 &gEfiGraphicsOutputProtocolGuid
,
594 if (!EFI_ERROR (Status
)) {
596 // Add all the child handles as possible Console Device
598 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
599 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
600 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
601 if (EFI_ERROR (Status
)) {
607 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
610 // In current implementation, we only enable one of the child handles
611 // as console device, i.e. sotre one of the child handle's device
612 // path to variable "ConOut"
613 // In future, we could select all child handles to be console device
616 *GopDevicePath
= TempDevicePath
;
619 // Delete the PCI device's path that added by
620 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
622 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
623 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
626 gBS
->FreePool (GopHandleBuffer
);
633 PreparePciDisplayDevicePath (
634 IN EFI_HANDLE DeviceHandle
640 Add PCI VGA to ConOut.
645 DeviceHandle - Handle of PCIIO protocol.
649 EFI_SUCCESS - PCI VGA is added to ConOut.
650 EFI_STATUS - No PCI VGA device is added.
655 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
656 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
659 GopDevicePath
= NULL
;
660 Status
= gBS
->HandleProtocol (
662 &gEfiDevicePathProtocolGuid
,
665 if (EFI_ERROR (Status
)) {
669 GetGopDevicePath (DevicePath
, &GopDevicePath
);
670 DevicePath
= GopDevicePath
;
672 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
678 PreparePciSerialDevicePath (
679 IN EFI_HANDLE DeviceHandle
685 Add PCI Serial to ConOut, ConIn, ErrOut.
690 DeviceHandle - Handle of PCIIO protocol.
694 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
695 EFI_STATUS - No PCI Serial device is added.
700 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
703 Status
= gBS
->HandleProtocol (
705 &gEfiDevicePathProtocolGuid
,
708 if (EFI_ERROR (Status
)) {
712 DevicePath
= AppendDevicePathNode (DevicePath
,
713 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
714 DevicePath
= AppendDevicePathNode (DevicePath
,
715 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
717 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
718 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
719 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
725 VisitAllInstancesOfProtocol (
727 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
733 EFI_HANDLE
*HandleBuffer
;
738 // Start to check all the PciIo to find all possible device
742 Status
= gBS
->LocateHandleBuffer (
749 if (EFI_ERROR (Status
)) {
753 for (Index
= 0; Index
< HandleCount
; Index
++) {
754 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
755 if (EFI_ERROR (Status
)) {
759 Status
= (*CallBackFunction
) (
766 gBS
->FreePool (HandleBuffer
);
774 VisitingAPciInstance (
775 IN EFI_HANDLE Handle
,
781 EFI_PCI_IO_PROTOCOL
*PciIo
;
784 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
787 // Check for all PCI device
789 Status
= PciIo
->Pci
.Read (
793 sizeof (Pci
) / sizeof (UINT32
),
796 if (EFI_ERROR (Status
)) {
800 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
811 VisitAllPciInstances (
812 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
815 return VisitAllInstancesOfProtocol (
816 &gEfiPciIoProtocolGuid
,
817 VisitingAPciInstance
,
818 (VOID
*)(UINTN
) CallBackFunction
824 Do platform specific PCI Device check and add them to
825 ConOut, ConIn, ErrOut.
827 @param[in] Handle - Handle of PCI device instance
828 @param[in] PciIo - PCI IO protocol instance
829 @param[in] Pci - PCI Header register block
831 @retval EFI_SUCCESS - PCI Device check and Console variable update
833 @retval EFI_STATUS - PCI Device check or Console variable update fail.
838 DetectAndPreparePlatformPciDevicePath (
839 IN EFI_HANDLE Handle
,
840 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
846 Status
= PciIo
->Attributes (
848 EfiPciIoAttributeOperationEnable
,
849 EFI_PCI_DEVICE_ENABLE
,
852 ASSERT_EFI_ERROR (Status
);
854 if (!mDetectVgaOnly
) {
856 // Here we decide whether it is LPC Bridge
858 if ((IS_PCI_LPC (Pci
)) ||
859 ((IS_PCI_ISA_PDECODE (Pci
)) &&
860 (Pci
->Hdr
.VendorId
== 0x8086) &&
861 (Pci
->Hdr
.DeviceId
== 0x7000)
865 // Add IsaKeyboard to ConIn,
866 // add IsaSerial to ConOut, ConIn, ErrOut
868 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
869 PrepareLpcBridgeDevicePath (Handle
);
873 // Here we decide which Serial device to enable in PCI bus
875 if (IS_PCI_16550SERIAL (Pci
)) {
877 // Add them to ConOut, ConIn, ErrOut.
879 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
880 PreparePciSerialDevicePath (Handle
);
886 // Here we decide which display device to enable in PCI bus
888 if (IS_PCI_DISPLAY (Pci
)) {
890 // Add them to ConOut.
892 DEBUG ((EFI_D_INFO
, "Found PCI display device\n"));
893 PreparePciDisplayDevicePath (Handle
);
902 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
904 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
906 @retval EFI_SUCCESS - PCI Device check and Console variable update
908 @retval EFI_STATUS - PCI Device check or Console variable update fail.
912 DetectAndPreparePlatformPciDevicePaths (
913 BOOLEAN DetectVgaOnly
916 mDetectVgaOnly
= DetectVgaOnly
;
917 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
922 PlatformInitializeConsole (
923 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
929 Connect the predefined platform default console device. Always try to find
930 and enable the vga device if have.
934 PlatformConsole - Predefined platform default console device array.
938 EFI_DEVICE_PATH_PROTOCOL
*VarConout
;
939 EFI_DEVICE_PATH_PROTOCOL
*VarConin
;
942 // Connect RootBridge
944 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME
, (VOID
**) &VarConout
,
946 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME
, (VOID
**) &VarConin
, NULL
);
948 if (VarConout
== NULL
|| VarConin
== NULL
) {
950 // Do platform specific PCI Device check and add them to ConOut, ConIn,
953 DetectAndPreparePlatformPciDevicePaths (FALSE
);
956 // Have chance to connect the platform default console,
957 // the platform default console is the minimum device group
958 // the platform should support
960 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
962 // Update the console variable with the connect type
964 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
965 EfiBootManagerUpdateConsoleVariable (ConIn
,
966 PlatformConsole
[Index
].DevicePath
, NULL
);
968 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
969 EfiBootManagerUpdateConsoleVariable (ConOut
,
970 PlatformConsole
[Index
].DevicePath
, NULL
);
972 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
973 EfiBootManagerUpdateConsoleVariable (ErrOut
,
974 PlatformConsole
[Index
].DevicePath
, NULL
);
979 // Only detect VGA device and add them to ConOut
981 DetectAndPreparePlatformPciDevicePaths (TRUE
);
987 Configure PCI Interrupt Line register for applicable devices
988 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
990 @param[in] Handle - Handle of PCI device instance
991 @param[in] PciIo - PCI IO protocol instance
992 @param[in] PciHdr - PCI Header register block
994 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
1000 IN EFI_HANDLE Handle
,
1001 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1002 IN PCI_TYPE00
*PciHdr
1005 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1006 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1011 UINT32 RootBusNumber
;
1013 Status
= EFI_SUCCESS
;
1015 if (PciHdr
->Device
.InterruptPin
!= 0) {
1017 DevPathNode
= DevicePathFromHandle (Handle
);
1018 ASSERT (DevPathNode
!= NULL
);
1019 DevPath
= DevPathNode
;
1022 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1023 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1024 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1025 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1029 // Compute index into PciHostIrqs[] table by walking
1030 // the device path and adding up all device numbers
1032 Status
= EFI_NOT_FOUND
;
1034 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1035 while (!IsDevicePathEnd (DevPathNode
)) {
1036 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1037 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1039 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1042 // Unlike SeaBIOS, which starts climbing from the leaf device
1043 // up toward the root, we traverse the device path starting at
1044 // the root moving toward the leaf node.
1045 // The slot number of the top-level parent bridge is needed for
1046 // Q35 cases with more than 24 slots on the root bus.
1048 if (Status
!= EFI_SUCCESS
) {
1049 Status
= EFI_SUCCESS
;
1050 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1054 DevPathNode
= NextDevicePathNode (DevPathNode
);
1056 if (EFI_ERROR (Status
)) {
1059 if (RootBusNumber
== 0 && RootSlot
== 0) {
1062 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1069 // Final PciHostIrqs[] index calculation depends on the platform
1070 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1072 switch (mHostBridgeDevId
) {
1073 case INTEL_82441_DEVICE_ID
:
1076 case INTEL_Q35_MCH_DEVICE_ID
:
1078 // SeaBIOS contains the following comment:
1079 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1080 // with a different starting index - see q35-acpi-dsdt.dsl.
1082 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1084 if (RootSlot
> 24) {
1086 // in this case, subtract back out RootSlot from Idx
1087 // (SeaBIOS never adds it to begin with, but that would make our
1088 // device path traversal loop above too awkward)
1094 ASSERT (FALSE
); // should never get here
1096 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1097 IrqLine
= PciHostIrqs
[Idx
];
1099 DEBUG_CODE_BEGIN ();
1101 CHAR16
*DevPathString
;
1102 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1103 UINTN Segment
, Bus
, Device
, Function
;
1105 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1106 if (DevPathString
== NULL
) {
1107 DevPathString
= Fallback
;
1109 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1110 ASSERT_EFI_ERROR (Status
);
1112 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1113 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1116 if (DevPathString
!= Fallback
) {
1117 FreePool (DevPathString
);
1123 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1125 Status
= PciIo
->Pci
.Write (
1128 PCI_INT_LINE_OFFSET
,
1139 PciAcpiInitialization (
1145 // Query Host Bridge DID to determine platform type
1147 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1148 switch (mHostBridgeDevId
) {
1149 case INTEL_82441_DEVICE_ID
:
1150 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1152 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1154 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1155 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1156 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1157 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1159 case INTEL_Q35_MCH_DEVICE_ID
:
1160 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1162 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1164 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1165 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1166 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1167 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1168 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1169 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1170 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1171 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1174 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1175 __FUNCTION__
, mHostBridgeDevId
));
1181 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1183 VisitAllPciInstances (SetPciIntLine
);
1186 // Set ACPI SCI_EN bit in PMCNTRL
1188 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1192 This function detects if OVMF is running on Xen.
1201 EFI_HOB_GUID_TYPE
*GuidHob
;
1202 STATIC INTN FoundHob
= -1;
1204 if (FoundHob
== 0) {
1206 } else if (FoundHob
== 1) {
1211 // See if a XenInfo HOB is available
1213 GuidHob
= GetFirstGuidHob (&gEfiXenInfoGuid
);
1214 if (GuidHob
== NULL
) {
1225 ConnectRecursivelyIfPciMassStorage (
1226 IN EFI_HANDLE Handle
,
1227 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1228 IN PCI_TYPE00
*PciHeader
1232 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1236 // Recognize PCI Mass Storage, and Xen PCI devices
1238 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1239 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1241 Status
= gBS
->HandleProtocol (
1243 &gEfiDevicePathProtocolGuid
,
1246 if (EFI_ERROR (Status
)) {
1251 // Print Device Path
1253 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1254 if (DevPathStr
!= NULL
) {
1257 "Found %s device: %s\n",
1258 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1264 FreePool(DevPathStr
);
1267 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1268 if (EFI_ERROR (Status
)) {
1279 This notification function is invoked when the
1280 EMU Variable FVB has been changed.
1282 @param Event The event that occurred
1283 @param Context For EFI compatibility. Not used.
1288 EmuVariablesUpdatedCallback (
1293 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1294 UpdateNvVarsOnFileSystem ();
1300 VisitingFileSystemInstance (
1301 IN EFI_HANDLE Handle
,
1307 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1308 RETURN_STATUS PcdStatus
;
1310 if (ConnectedToFileSystem
) {
1311 return EFI_ALREADY_STARTED
;
1314 Status
= ConnectNvVarsToFileSystem (Handle
);
1315 if (EFI_ERROR (Status
)) {
1319 ConnectedToFileSystem
= TRUE
;
1321 EfiCreateProtocolNotifyEvent (
1322 &gEfiDevicePathProtocolGuid
,
1324 EmuVariablesUpdatedCallback
,
1326 &mEmuVariableEventReg
1328 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1329 (UINT64
)(UINTN
) mEmuVariableEvent
);
1330 ASSERT_RETURN_ERROR (PcdStatus
);
1337 PlatformBdsRestoreNvVarsFromHardDisk (
1340 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1341 VisitAllInstancesOfProtocol (
1342 &gEfiSimpleFileSystemProtocolGuid
,
1343 VisitingFileSystemInstance
,
1350 PlatformBdsConnectSequence (
1355 Routine Description:
1357 Connect with predefined platform connect sequence,
1358 the OEM/IBV can customize with their own connect sequence.
1371 RETURN_STATUS Status
;
1373 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1378 // Here we can get the customized platform connect sequence
1379 // Notes: we can connect with new variable which record the
1380 // last time boots connect device path sequence
1382 while (gPlatformConnectSequence
[Index
] != NULL
) {
1384 // Build the platform boot option
1386 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1390 Status
= ConnectDevicesFromQemu ();
1391 if (RETURN_ERROR (Status
)) {
1393 // Just use the simple policy to connect all devices
1395 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1396 EfiBootManagerConnectAll ();
1399 PciAcpiInitialization ();
1403 Save the S3 boot script.
1405 Note that DxeSmmReadyToLock must be signaled after this function returns;
1406 otherwise the script wouldn't be saved actually.
1415 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1416 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1418 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1419 (VOID
**) &BootScript
);
1420 ASSERT_EFI_ERROR (Status
);
1423 // Despite the opcode documentation in the PI spec, the protocol
1424 // implementation embeds a deep copy of the info in the boot script, rather
1425 // than storing just a pointer to runtime or NVS storage.
1427 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1428 (UINT32
) sizeof Info
,
1429 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1430 ASSERT_EFI_ERROR (Status
);
1436 PlatformBootManagerAfterConsole (
1441 Routine Description:
1443 The function will execute with as the platform policy, current policy
1444 is driven by boot mode. IBV/OEM can customize this code for their specific
1449 EFI_BOOT_MODE BootMode
;
1451 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1453 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1454 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1455 "from disk since flash variables appear to be supported.\n"));
1458 // Try to restore variables from the hard disk early so
1459 // they can be used for the other BDS connect operations.
1461 PlatformBdsRestoreNvVarsFromHardDisk ();
1465 // Get current Boot Mode
1467 BootMode
= GetBootModeHob ();
1468 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1471 // Go the different platform policy with different boot mode
1472 // Notes: this part code can be change with the table policy
1474 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1479 BootLogoEnableLogo ();
1482 // Perform some platform specific connect sequence
1484 PlatformBdsConnectSequence ();
1487 // Process QEMU's -kernel command line option
1489 TryRunningQemuKernel ();
1491 EfiBootManagerRefreshAllBootOption ();
1494 // Register UEFI Shell
1496 PlatformRegisterFvBootOption (
1497 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1500 RemoveStaleFvFileOptions ();
1501 SetBootOrderFromQemu ();
1505 This notification function is invoked when an instance of the
1506 EFI_DEVICE_PATH_PROTOCOL is produced.
1508 @param Event The event that occurred
1509 @param Context For EFI compatibility. Not used.
1522 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1523 ATAPI_DEVICE_PATH
*Atapi
;
1526 // Examine all new handles
1530 // Get the next handle
1532 BufferSize
= sizeof (Handle
);
1533 Status
= gBS
->LocateHandle (
1536 mEfiDevPathNotifyReg
,
1542 // If not found, we're done
1544 if (EFI_NOT_FOUND
== Status
) {
1548 if (EFI_ERROR (Status
)) {
1553 // Get the DevicePath protocol on that handle
1555 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1556 (VOID
**)&DevPathNode
);
1557 ASSERT_EFI_ERROR (Status
);
1559 while (!IsDevicePathEnd (DevPathNode
)) {
1561 // Find the handler to dump this device path node
1564 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1565 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1567 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1573 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1580 // Next device path node
1582 DevPathNode
= NextDevicePathNode (DevPathNode
);
1591 InstallDevicePathCallback (
1595 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1596 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1597 &gEfiDevicePathProtocolGuid
,
1601 &mEfiDevPathNotifyReg
1606 This function is called each second during the boot manager waits the
1609 @param TimeoutRemain The remaining timeout.
1613 PlatformBootManagerWaitCallback (
1614 UINT16 TimeoutRemain
1617 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1618 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1621 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1623 Black
.Raw
= 0x00000000;
1624 White
.Raw
= 0x00FFFFFF;
1626 BootLogoUpdateProgress (
1629 L
"Start boot option",
1631 (Timeout
- TimeoutRemain
) * 100 / Timeout
,