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
332 Do the platform init, can be customized by OEM/IBV
334 Possible things that can be done in PlatformBootManagerBeforeConsole:
336 > Update console variable: 1. include hot-plug devices;
337 > 2. Clear ConIn and add SOL for AMT
338 > Register new Driver#### or Boot####
339 > Register new Key####: e.g.: F12
340 > Signal ReadyToLock event
341 > Authentication action: 1. connect Auth devices;
342 > 2. Identify auto logon user.
346 PlatformBootManagerBeforeConsole (
352 RETURN_STATUS PcdStatus
;
354 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
355 InstallDevicePathCallback ();
357 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
358 ConnectRootBridge
, NULL
);
361 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
363 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
366 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
367 // the preparation of S3 system information. That logic has a hard dependency
368 // on the presence of the FACS ACPI table. Since our ACPI tables are only
369 // installed after PCI enumeration completes, we must not trigger the S3 save
370 // earlier, hence we can't signal End-of-Dxe earlier.
372 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
374 if (QemuFwCfgS3Enabled ()) {
376 // Save the boot script too. Note that this will require us to emit the
377 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
383 // Prevent further changes to LockBoxes or SMRAM.
386 Status
= gBS
->InstallProtocolInterface (&Handle
,
387 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
389 ASSERT_EFI_ERROR (Status
);
392 // Dispatch deferred images after EndOfDxe event and ReadyToLock
395 EfiBootManagerDispatchDeferredImages ();
397 PlatformInitializeConsole (gPlatformConsole
);
398 PcdStatus
= PcdSet16S (PcdPlatformBootTimeOut
,
399 GetFrontPageTimeoutFromQemu ());
400 ASSERT_RETURN_ERROR (PcdStatus
);
402 PlatformRegisterOptionsAndKeys ();
409 IN EFI_HANDLE RootBridgeHandle
,
417 // Make the PCI bus driver connect the root bridge, non-recursively. This
418 // will produce a number of child handles with PciIo on them.
420 Status
= gBS
->ConnectController (
421 RootBridgeHandle
, // ControllerHandle
422 NULL
, // DriverImageHandle
423 NULL
, // RemainingDevicePath -- produce all
432 Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
434 @param[in] DeviceHandle Handle of the LPC Bridge device.
436 @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
437 ConOut, ConIn, and ErrOut.
439 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
443 PrepareLpcBridgeDevicePath (
444 IN EFI_HANDLE DeviceHandle
448 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
449 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
453 Status
= gBS
->HandleProtocol (
455 &gEfiDevicePathProtocolGuid
,
458 if (EFI_ERROR (Status
)) {
461 TempDevicePath
= DevicePath
;
466 DevicePath
= AppendDevicePathNode (DevicePath
,
467 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
469 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
474 DevicePath
= TempDevicePath
;
475 gPnp16550ComPortDeviceNode
.UID
= 0;
477 DevicePath
= AppendDevicePathNode (DevicePath
,
478 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
479 DevicePath
= AppendDevicePathNode (DevicePath
,
480 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
481 DevicePath
= AppendDevicePathNode (DevicePath
,
482 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
487 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
488 if (DevPathStr
!= NULL
) {
491 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
493 gPnp16550ComPortDeviceNode
.UID
+ 1,
496 FreePool(DevPathStr
);
499 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
500 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
501 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
506 DevicePath
= TempDevicePath
;
507 gPnp16550ComPortDeviceNode
.UID
= 1;
509 DevicePath
= AppendDevicePathNode (DevicePath
,
510 (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
511 DevicePath
= AppendDevicePathNode (DevicePath
,
512 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
513 DevicePath
= AppendDevicePathNode (DevicePath
,
514 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
519 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
520 if (DevPathStr
!= NULL
) {
523 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
525 gPnp16550ComPortDeviceNode
.UID
+ 1,
528 FreePool(DevPathStr
);
531 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
532 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
533 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
540 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
541 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
546 EFI_HANDLE PciDeviceHandle
;
547 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
548 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
549 UINTN GopHandleCount
;
550 EFI_HANDLE
*GopHandleBuffer
;
552 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
553 return EFI_INVALID_PARAMETER
;
557 // Initialize the GopDevicePath to be PciDevicePath
559 *GopDevicePath
= PciDevicePath
;
560 TempPciDevicePath
= PciDevicePath
;
562 Status
= gBS
->LocateDevicePath (
563 &gEfiDevicePathProtocolGuid
,
567 if (EFI_ERROR (Status
)) {
572 // Try to connect this handle, so that GOP driver could start on this
573 // device and create child handles with GraphicsOutput Protocol installed
574 // on them, then we get device paths of these child handles and select
575 // them as possible console device.
577 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
579 Status
= gBS
->LocateHandleBuffer (
581 &gEfiGraphicsOutputProtocolGuid
,
586 if (!EFI_ERROR (Status
)) {
588 // Add all the child handles as possible Console Device
590 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
591 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
],
592 &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
593 if (EFI_ERROR (Status
)) {
599 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
602 // In current implementation, we only enable one of the child handles
603 // as console device, i.e. sotre one of the child handle's device
604 // path to variable "ConOut"
605 // In future, we could select all child handles to be console device
608 *GopDevicePath
= TempDevicePath
;
611 // Delete the PCI device's path that added by
612 // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
614 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
615 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
618 gBS
->FreePool (GopHandleBuffer
);
625 Add PCI display to ConOut.
627 @param[in] DeviceHandle Handle of the PCI display device.
629 @retval EFI_SUCCESS The PCI display device has been added to ConOut.
631 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
635 PreparePciDisplayDevicePath (
636 IN EFI_HANDLE DeviceHandle
640 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
641 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
644 GopDevicePath
= NULL
;
645 Status
= gBS
->HandleProtocol (
647 &gEfiDevicePathProtocolGuid
,
650 if (EFI_ERROR (Status
)) {
654 GetGopDevicePath (DevicePath
, &GopDevicePath
);
655 DevicePath
= GopDevicePath
;
657 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
663 Add PCI Serial to ConOut, ConIn, ErrOut.
665 @param[in] DeviceHandle Handle of the PCI serial device.
667 @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
670 @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
674 PreparePciSerialDevicePath (
675 IN EFI_HANDLE DeviceHandle
679 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
682 Status
= gBS
->HandleProtocol (
684 &gEfiDevicePathProtocolGuid
,
687 if (EFI_ERROR (Status
)) {
691 DevicePath
= AppendDevicePathNode (DevicePath
,
692 (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
693 DevicePath
= AppendDevicePathNode (DevicePath
,
694 (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
696 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
697 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
698 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
704 VisitAllInstancesOfProtocol (
706 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
712 EFI_HANDLE
*HandleBuffer
;
717 // Start to check all the PciIo to find all possible device
721 Status
= gBS
->LocateHandleBuffer (
728 if (EFI_ERROR (Status
)) {
732 for (Index
= 0; Index
< HandleCount
; Index
++) {
733 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
734 if (EFI_ERROR (Status
)) {
738 Status
= (*CallBackFunction
) (
745 gBS
->FreePool (HandleBuffer
);
753 VisitingAPciInstance (
754 IN EFI_HANDLE Handle
,
760 EFI_PCI_IO_PROTOCOL
*PciIo
;
763 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
766 // Check for all PCI device
768 Status
= PciIo
->Pci
.Read (
772 sizeof (Pci
) / sizeof (UINT32
),
775 if (EFI_ERROR (Status
)) {
779 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
790 VisitAllPciInstances (
791 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
794 return VisitAllInstancesOfProtocol (
795 &gEfiPciIoProtocolGuid
,
796 VisitingAPciInstance
,
797 (VOID
*)(UINTN
) CallBackFunction
803 Do platform specific PCI Device check and add them to
804 ConOut, ConIn, ErrOut.
806 @param[in] Handle - Handle of PCI device instance
807 @param[in] PciIo - PCI IO protocol instance
808 @param[in] Pci - PCI Header register block
810 @retval EFI_SUCCESS - PCI Device check and Console variable update
812 @retval EFI_STATUS - PCI Device check or Console variable update fail.
817 DetectAndPreparePlatformPciDevicePath (
818 IN EFI_HANDLE Handle
,
819 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
825 Status
= PciIo
->Attributes (
827 EfiPciIoAttributeOperationEnable
,
828 EFI_PCI_DEVICE_ENABLE
,
831 ASSERT_EFI_ERROR (Status
);
833 if (!mDetectVgaOnly
) {
835 // Here we decide whether it is LPC Bridge
837 if ((IS_PCI_LPC (Pci
)) ||
838 ((IS_PCI_ISA_PDECODE (Pci
)) &&
839 (Pci
->Hdr
.VendorId
== 0x8086) &&
840 (Pci
->Hdr
.DeviceId
== 0x7000)
844 // Add IsaKeyboard to ConIn,
845 // add IsaSerial to ConOut, ConIn, ErrOut
847 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
848 PrepareLpcBridgeDevicePath (Handle
);
852 // Here we decide which Serial device to enable in PCI bus
854 if (IS_PCI_16550SERIAL (Pci
)) {
856 // Add them to ConOut, ConIn, ErrOut.
858 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
859 PreparePciSerialDevicePath (Handle
);
865 // Here we decide which display device to enable in PCI bus
867 if (IS_PCI_DISPLAY (Pci
)) {
869 // Add them to ConOut.
871 DEBUG ((EFI_D_INFO
, "Found PCI display device\n"));
872 PreparePciDisplayDevicePath (Handle
);
881 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
883 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
885 @retval EFI_SUCCESS - PCI Device check and Console variable update
887 @retval EFI_STATUS - PCI Device check or Console variable update fail.
891 DetectAndPreparePlatformPciDevicePaths (
892 BOOLEAN DetectVgaOnly
895 mDetectVgaOnly
= DetectVgaOnly
;
896 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
901 Connect the predefined platform default console device.
903 Always try to find and enable PCI display devices.
905 @param[in] PlatformConsole Predefined platform default console device array.
908 PlatformInitializeConsole (
909 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
913 EFI_DEVICE_PATH_PROTOCOL
*VarConout
;
914 EFI_DEVICE_PATH_PROTOCOL
*VarConin
;
917 // Connect RootBridge
919 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME
, (VOID
**) &VarConout
,
921 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME
, (VOID
**) &VarConin
, NULL
);
923 if (VarConout
== NULL
|| VarConin
== NULL
) {
925 // Do platform specific PCI Device check and add them to ConOut, ConIn,
928 DetectAndPreparePlatformPciDevicePaths (FALSE
);
931 // Have chance to connect the platform default console,
932 // the platform default console is the minimum device group
933 // the platform should support
935 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
937 // Update the console variable with the connect type
939 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
940 EfiBootManagerUpdateConsoleVariable (ConIn
,
941 PlatformConsole
[Index
].DevicePath
, NULL
);
943 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
944 EfiBootManagerUpdateConsoleVariable (ConOut
,
945 PlatformConsole
[Index
].DevicePath
, NULL
);
947 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
948 EfiBootManagerUpdateConsoleVariable (ErrOut
,
949 PlatformConsole
[Index
].DevicePath
, NULL
);
954 // Only detect VGA device and add them to ConOut
956 DetectAndPreparePlatformPciDevicePaths (TRUE
);
962 Configure PCI Interrupt Line register for applicable devices
963 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
965 @param[in] Handle - Handle of PCI device instance
966 @param[in] PciIo - PCI IO protocol instance
967 @param[in] PciHdr - PCI Header register block
969 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
975 IN EFI_HANDLE Handle
,
976 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
977 IN PCI_TYPE00
*PciHdr
980 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
981 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
986 UINT32 RootBusNumber
;
988 Status
= EFI_SUCCESS
;
990 if (PciHdr
->Device
.InterruptPin
!= 0) {
992 DevPathNode
= DevicePathFromHandle (Handle
);
993 ASSERT (DevPathNode
!= NULL
);
994 DevPath
= DevPathNode
;
997 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
998 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
999 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1000 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1004 // Compute index into PciHostIrqs[] table by walking
1005 // the device path and adding up all device numbers
1007 Status
= EFI_NOT_FOUND
;
1009 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1010 while (!IsDevicePathEnd (DevPathNode
)) {
1011 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1012 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1014 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1017 // Unlike SeaBIOS, which starts climbing from the leaf device
1018 // up toward the root, we traverse the device path starting at
1019 // the root moving toward the leaf node.
1020 // The slot number of the top-level parent bridge is needed for
1021 // Q35 cases with more than 24 slots on the root bus.
1023 if (Status
!= EFI_SUCCESS
) {
1024 Status
= EFI_SUCCESS
;
1025 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1029 DevPathNode
= NextDevicePathNode (DevPathNode
);
1031 if (EFI_ERROR (Status
)) {
1034 if (RootBusNumber
== 0 && RootSlot
== 0) {
1037 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1044 // Final PciHostIrqs[] index calculation depends on the platform
1045 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1047 switch (mHostBridgeDevId
) {
1048 case INTEL_82441_DEVICE_ID
:
1051 case INTEL_Q35_MCH_DEVICE_ID
:
1053 // SeaBIOS contains the following comment:
1054 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1055 // with a different starting index - see q35-acpi-dsdt.dsl.
1057 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1059 if (RootSlot
> 24) {
1061 // in this case, subtract back out RootSlot from Idx
1062 // (SeaBIOS never adds it to begin with, but that would make our
1063 // device path traversal loop above too awkward)
1069 ASSERT (FALSE
); // should never get here
1071 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1072 IrqLine
= PciHostIrqs
[Idx
];
1074 DEBUG_CODE_BEGIN ();
1076 CHAR16
*DevPathString
;
1077 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1078 UINTN Segment
, Bus
, Device
, Function
;
1080 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1081 if (DevPathString
== NULL
) {
1082 DevPathString
= Fallback
;
1084 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1085 ASSERT_EFI_ERROR (Status
);
1087 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1088 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1091 if (DevPathString
!= Fallback
) {
1092 FreePool (DevPathString
);
1098 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1100 Status
= PciIo
->Pci
.Write (
1103 PCI_INT_LINE_OFFSET
,
1114 PciAcpiInitialization (
1120 // Query Host Bridge DID to determine platform type
1122 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1123 switch (mHostBridgeDevId
) {
1124 case INTEL_82441_DEVICE_ID
:
1125 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1127 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1129 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1130 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1131 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1132 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1134 case INTEL_Q35_MCH_DEVICE_ID
:
1135 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1137 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1139 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1140 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1141 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1142 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1143 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1144 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1145 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1146 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1149 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1150 __FUNCTION__
, mHostBridgeDevId
));
1156 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1158 VisitAllPciInstances (SetPciIntLine
);
1161 // Set ACPI SCI_EN bit in PMCNTRL
1163 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1167 This function detects if OVMF is running on Xen.
1176 EFI_HOB_GUID_TYPE
*GuidHob
;
1177 STATIC INTN FoundHob
= -1;
1179 if (FoundHob
== 0) {
1181 } else if (FoundHob
== 1) {
1186 // See if a XenInfo HOB is available
1188 GuidHob
= GetFirstGuidHob (&gEfiXenInfoGuid
);
1189 if (GuidHob
== NULL
) {
1200 ConnectRecursivelyIfPciMassStorage (
1201 IN EFI_HANDLE Handle
,
1202 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1203 IN PCI_TYPE00
*PciHeader
1207 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1211 // Recognize PCI Mass Storage, and Xen PCI devices
1213 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1214 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1216 Status
= gBS
->HandleProtocol (
1218 &gEfiDevicePathProtocolGuid
,
1221 if (EFI_ERROR (Status
)) {
1226 // Print Device Path
1228 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1229 if (DevPathStr
!= NULL
) {
1232 "Found %s device: %s\n",
1233 (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ?
1239 FreePool(DevPathStr
);
1242 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1243 if (EFI_ERROR (Status
)) {
1254 This notification function is invoked when the
1255 EMU Variable FVB has been changed.
1257 @param Event The event that occurred
1258 @param Context For EFI compatibility. Not used.
1263 EmuVariablesUpdatedCallback (
1268 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1269 UpdateNvVarsOnFileSystem ();
1275 VisitingFileSystemInstance (
1276 IN EFI_HANDLE Handle
,
1282 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1283 RETURN_STATUS PcdStatus
;
1285 if (ConnectedToFileSystem
) {
1286 return EFI_ALREADY_STARTED
;
1289 Status
= ConnectNvVarsToFileSystem (Handle
);
1290 if (EFI_ERROR (Status
)) {
1294 ConnectedToFileSystem
= TRUE
;
1296 EfiCreateProtocolNotifyEvent (
1297 &gEfiDevicePathProtocolGuid
,
1299 EmuVariablesUpdatedCallback
,
1301 &mEmuVariableEventReg
1303 PcdStatus
= PcdSet64S (PcdEmuVariableEvent
,
1304 (UINT64
)(UINTN
) mEmuVariableEvent
);
1305 ASSERT_RETURN_ERROR (PcdStatus
);
1312 PlatformBdsRestoreNvVarsFromHardDisk (
1315 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1316 VisitAllInstancesOfProtocol (
1317 &gEfiSimpleFileSystemProtocolGuid
,
1318 VisitingFileSystemInstance
,
1325 Connect with predefined platform connect sequence.
1327 The OEM/IBV can customize with their own connect sequence.
1330 PlatformBdsConnectSequence (
1335 RETURN_STATUS Status
;
1337 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1342 // Here we can get the customized platform connect sequence
1343 // Notes: we can connect with new variable which record the
1344 // last time boots connect device path sequence
1346 while (gPlatformConnectSequence
[Index
] != NULL
) {
1348 // Build the platform boot option
1350 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1354 Status
= ConnectDevicesFromQemu ();
1355 if (RETURN_ERROR (Status
)) {
1357 // Just use the simple policy to connect all devices
1359 DEBUG ((DEBUG_INFO
, "EfiBootManagerConnectAll\n"));
1360 EfiBootManagerConnectAll ();
1365 Save the S3 boot script.
1367 Note that DxeSmmReadyToLock must be signaled after this function returns;
1368 otherwise the script wouldn't be saved actually.
1377 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1378 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1380 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1381 (VOID
**) &BootScript
);
1382 ASSERT_EFI_ERROR (Status
);
1385 // Despite the opcode documentation in the PI spec, the protocol
1386 // implementation embeds a deep copy of the info in the boot script, rather
1387 // than storing just a pointer to runtime or NVS storage.
1389 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1390 (UINT32
) sizeof Info
,
1391 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1392 ASSERT_EFI_ERROR (Status
);
1397 Do the platform specific action after the console is ready
1399 Possible things that can be done in PlatformBootManagerAfterConsole:
1401 > Console post action:
1402 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1403 > Signal console ready platform customized event
1404 > Run diagnostics like memory testing
1405 > Connect certain devices
1406 > Dispatch aditional option roms
1407 > Special boot: e.g.: USB boot, enter UI
1411 PlatformBootManagerAfterConsole (
1415 EFI_BOOT_MODE BootMode
;
1417 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1419 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1420 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1421 "from disk since flash variables appear to be supported.\n"));
1424 // Try to restore variables from the hard disk early so
1425 // they can be used for the other BDS connect operations.
1427 PlatformBdsRestoreNvVarsFromHardDisk ();
1431 // Get current Boot Mode
1433 BootMode
= GetBootModeHob ();
1434 DEBUG ((DEBUG_INFO
, "Boot Mode:%x\n", BootMode
));
1437 // Go the different platform policy with different boot mode
1438 // Notes: this part code can be change with the table policy
1440 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1445 BootLogoEnableLogo ();
1448 // Set PCI Interrupt Line registers and ACPI SCI_EN
1450 PciAcpiInitialization ();
1453 // Process QEMU's -kernel command line option
1455 TryRunningQemuKernel ();
1458 // Perform some platform specific connect sequence
1460 PlatformBdsConnectSequence ();
1462 EfiBootManagerRefreshAllBootOption ();
1465 // Register UEFI Shell
1467 PlatformRegisterFvBootOption (
1468 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1471 RemoveStaleFvFileOptions ();
1472 SetBootOrderFromQemu ();
1476 This notification function is invoked when an instance of the
1477 EFI_DEVICE_PATH_PROTOCOL is produced.
1479 @param Event The event that occurred
1480 @param Context For EFI compatibility. Not used.
1493 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1494 ATAPI_DEVICE_PATH
*Atapi
;
1497 // Examine all new handles
1501 // Get the next handle
1503 BufferSize
= sizeof (Handle
);
1504 Status
= gBS
->LocateHandle (
1507 mEfiDevPathNotifyReg
,
1513 // If not found, we're done
1515 if (EFI_NOT_FOUND
== Status
) {
1519 if (EFI_ERROR (Status
)) {
1524 // Get the DevicePath protocol on that handle
1526 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
,
1527 (VOID
**)&DevPathNode
);
1528 ASSERT_EFI_ERROR (Status
);
1530 while (!IsDevicePathEnd (DevPathNode
)) {
1532 // Find the handler to dump this device path node
1535 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1536 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1538 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1544 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1551 // Next device path node
1553 DevPathNode
= NextDevicePathNode (DevPathNode
);
1562 InstallDevicePathCallback (
1566 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1567 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1568 &gEfiDevicePathProtocolGuid
,
1572 &mEfiDevPathNotifyReg
1577 This function is called each second during the boot manager waits the
1580 @param TimeoutRemain The remaining timeout.
1584 PlatformBootManagerWaitCallback (
1585 UINT16 TimeoutRemain
1588 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1589 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1592 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1594 Black
.Raw
= 0x00000000;
1595 White
.Raw
= 0x00FFFFFF;
1597 BootLogoUpdateProgress (
1600 L
"Start boot option",
1602 (Timeout
- TimeoutRemain
) * 100 / Timeout
,