2 Platform BDS customizations.
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this 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,
11 WITHOUT 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
43 #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
51 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
58 @param[in] Handle - Handle of PCI device instance
59 @param[in] PciIo - PCI IO protocol instance
60 @param[in] Pci - PCI Header register block
64 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
66 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
72 // Function prototypes
76 VisitAllInstancesOfProtocol (
78 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
83 VisitAllPciInstancesOfProtocol (
84 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
88 InstallDevicePathCallback (
93 PlatformRegisterFvBootOption (
101 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
102 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
103 UINTN BootOptionCount
;
104 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
105 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
106 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
108 Status
= gBS
->HandleProtocol (
110 &gEfiLoadedImageProtocolGuid
,
111 (VOID
**) &LoadedImage
113 ASSERT_EFI_ERROR (Status
);
115 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
116 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
117 ASSERT (DevicePath
!= NULL
);
118 DevicePath
= AppendDevicePathNode (
120 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
122 ASSERT (DevicePath
!= NULL
);
124 Status
= EfiBootManagerInitializeLoadOption (
126 LoadOptionNumberUnassigned
,
134 ASSERT_EFI_ERROR (Status
);
135 FreePool (DevicePath
);
137 BootOptions
= EfiBootManagerGetLoadOptions (
138 &BootOptionCount
, LoadOptionTypeBoot
141 OptionIndex
= EfiBootManagerFindLoadOption (
142 &NewOption
, BootOptions
, BootOptionCount
145 if (OptionIndex
== -1) {
146 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
147 ASSERT_EFI_ERROR (Status
);
149 EfiBootManagerFreeLoadOption (&NewOption
);
150 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
154 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
155 whose device paths do not resolve exactly to an FvFile in the system.
157 This removes any boot options that point to binaries built into the firmware
158 and have become stale due to any of the following:
159 - DXEFV's base address or size changed (historical),
160 - DXEFV's FvNameGuid changed,
161 - the FILE_GUID of the pointed-to binary changed,
162 - the referenced binary is no longer built into the firmware.
164 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
165 avoids exact duplicates.
168 RemoveStaleFvFileOptions (
172 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
173 UINTN BootOptionCount
;
176 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
,
179 for (Index
= 0; Index
< BootOptionCount
; ++Index
) {
180 EFI_DEVICE_PATH_PROTOCOL
*Node1
, *Node2
, *SearchNode
;
185 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
186 // then keep the boot option.
188 Node1
= BootOptions
[Index
].FilePath
;
189 if (!(DevicePathType (Node1
) == HARDWARE_DEVICE_PATH
&&
190 DevicePathSubType (Node1
) == HW_MEMMAP_DP
) &&
191 !(DevicePathType (Node1
) == MEDIA_DEVICE_PATH
&&
192 DevicePathSubType (Node1
) == MEDIA_PIWG_FW_VOL_DP
)) {
197 // If the second device path node is not FvFile(...), then keep the boot
200 Node2
= NextDevicePathNode (Node1
);
201 if (DevicePathType (Node2
) != MEDIA_DEVICE_PATH
||
202 DevicePathSubType (Node2
) != MEDIA_PIWG_FW_FILE_DP
) {
207 // Locate the Firmware Volume2 protocol instance that is denoted by the
208 // boot option. If this lookup fails (i.e., the boot option references a
209 // firmware volume that doesn't exist), then we'll proceed to delete the
213 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
,
214 &SearchNode
, &FvHandle
);
216 if (!EFI_ERROR (Status
)) {
218 // The firmware volume was found; now let's see if it contains the FvFile
219 // identified by GUID.
221 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
222 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFileNode
;
224 EFI_FV_FILETYPE FoundType
;
225 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
226 UINT32 AuthenticationStatus
;
228 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
,
229 (VOID
**)&FvProtocol
);
230 ASSERT_EFI_ERROR (Status
);
232 FvFileNode
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)Node2
;
234 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
237 Status
= FvProtocol
->ReadFile (
239 &FvFileNode
->FvFileName
, // NameGuid
244 &AuthenticationStatus
246 if (!EFI_ERROR (Status
)) {
248 // The FvFile was found. Keep the boot option.
255 // Delete the boot option.
257 Status
= EfiBootManagerDeleteLoadOptionVariable (
258 BootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
260 CHAR16
*DevicePathString
;
262 DevicePathString
= ConvertDevicePathToText(BootOptions
[Index
].FilePath
,
265 EFI_ERROR (Status
) ? EFI_D_WARN
: EFI_D_VERBOSE
,
266 "%a: removing stale Boot#%04x %s: %r\n",
268 (UINT32
)BootOptions
[Index
].OptionNumber
,
269 DevicePathString
== NULL
? L
"<unavailable>" : DevicePathString
,
272 if (DevicePathString
!= NULL
) {
273 FreePool (DevicePathString
);
278 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
282 PlatformRegisterOptionsAndKeys (
290 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
293 // Register ENTER as CONTINUE key
295 Enter
.ScanCode
= SCAN_NULL
;
296 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
297 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
298 ASSERT_EFI_ERROR (Status
);
301 // Map F2 to Boot Manager Menu
303 F2
.ScanCode
= SCAN_F2
;
304 F2
.UnicodeChar
= CHAR_NULL
;
305 Esc
.ScanCode
= SCAN_ESC
;
306 Esc
.UnicodeChar
= CHAR_NULL
;
307 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
308 ASSERT_EFI_ERROR (Status
);
309 Status
= EfiBootManagerAddKeyOptionVariable (
310 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
312 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
313 Status
= EfiBootManagerAddKeyOptionVariable (
314 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
316 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
322 IN EFI_HANDLE RootBridgeHandle
,
334 // BDS Platform Functions
338 PlatformBootManagerBeforeConsole (
345 Platform Bds init. Incude the platform firmware vendor, revision
359 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
360 InstallDevicePathCallback ();
362 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
363 ConnectRootBridge
, NULL
);
366 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
368 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
371 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
372 // the preparation of S3 system information. That logic has a hard dependency
373 // on the presence of the FACS ACPI table. Since our ACPI tables are only
374 // installed after PCI enumeration completes, we must not trigger the S3 save
375 // earlier, hence we can't signal End-of-Dxe earlier.
377 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
379 if (QemuFwCfgS3Enabled ()) {
381 // Save the boot script too. Note that this will require us to emit the
382 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
388 // Prevent further changes to LockBoxes or SMRAM.
391 Status
= gBS
->InstallProtocolInterface (&Handle
,
392 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
394 ASSERT_EFI_ERROR (Status
);
396 PlatformInitializeConsole (gPlatformConsole
);
397 PcdSet16 (PcdPlatformBootTimeOut
, GetFrontPageTimeoutFromQemu ());
399 PlatformRegisterOptionsAndKeys ();
406 IN EFI_HANDLE RootBridgeHandle
,
414 // Make the PCI bus driver connect the root bridge, non-recursively. This
415 // will produce a number of child handles with PciIo on them.
417 Status
= gBS
->ConnectController (
418 RootBridgeHandle
, // ControllerHandle
419 NULL
, // DriverImageHandle
420 NULL
, // RemainingDevicePath -- produce all
429 PrepareLpcBridgeDevicePath (
430 IN EFI_HANDLE DeviceHandle
436 Add IsaKeyboard to ConIn,
437 add IsaSerial to ConOut, ConIn, ErrOut.
442 DeviceHandle - Handle of PCIIO protocol.
446 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
447 EFI_STATUS - No LPC bridge is added.
452 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
453 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
457 Status
= gBS
->HandleProtocol (
459 &gEfiDevicePathProtocolGuid
,
462 if (EFI_ERROR (Status
)) {
465 TempDevicePath
= DevicePath
;
470 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
472 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
477 DevicePath
= TempDevicePath
;
478 gPnp16550ComPortDeviceNode
.UID
= 0;
480 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
481 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
482 DevicePath
= AppendDevicePathNode (DevicePath
, (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
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
510 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
511 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
516 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
517 if (DevPathStr
!= NULL
) {
520 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
522 gPnp16550ComPortDeviceNode
.UID
+ 1,
525 FreePool(DevPathStr
);
528 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
529 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
530 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
537 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
538 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
543 EFI_HANDLE PciDeviceHandle
;
544 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
545 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
546 UINTN GopHandleCount
;
547 EFI_HANDLE
*GopHandleBuffer
;
549 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
550 return EFI_INVALID_PARAMETER
;
554 // Initialize the GopDevicePath to be PciDevicePath
556 *GopDevicePath
= PciDevicePath
;
557 TempPciDevicePath
= PciDevicePath
;
559 Status
= gBS
->LocateDevicePath (
560 &gEfiDevicePathProtocolGuid
,
564 if (EFI_ERROR (Status
)) {
569 // Try to connect this handle, so that GOP dirver could start on this
570 // device and create child handles with GraphicsOutput Protocol installed
571 // on them, then we get device paths of these child handles and select
572 // them as possible console device.
574 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
576 Status
= gBS
->LocateHandleBuffer (
578 &gEfiGraphicsOutputProtocolGuid
,
583 if (!EFI_ERROR (Status
)) {
585 // Add all the child handles as possible Console Device
587 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
588 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
589 if (EFI_ERROR (Status
)) {
595 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
598 // In current implementation, we only enable one of the child handles
599 // as console device, i.e. sotre one of the child handle's device
600 // path to variable "ConOut"
601 // In futhure, we could select all child handles to be console device
604 *GopDevicePath
= TempDevicePath
;
607 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
608 // Add the integrity GOP device path.
610 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
611 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
614 gBS
->FreePool (GopHandleBuffer
);
621 PreparePciDisplayDevicePath (
622 IN EFI_HANDLE DeviceHandle
628 Add PCI VGA to ConOut.
633 DeviceHandle - Handle of PCIIO protocol.
637 EFI_SUCCESS - PCI VGA is added to ConOut.
638 EFI_STATUS - No PCI VGA device is added.
643 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
644 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
647 GopDevicePath
= NULL
;
648 Status
= gBS
->HandleProtocol (
650 &gEfiDevicePathProtocolGuid
,
653 if (EFI_ERROR (Status
)) {
657 GetGopDevicePath (DevicePath
, &GopDevicePath
);
658 DevicePath
= GopDevicePath
;
660 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
666 PreparePciSerialDevicePath (
667 IN EFI_HANDLE DeviceHandle
673 Add PCI Serial to ConOut, ConIn, ErrOut.
678 DeviceHandle - Handle of PCIIO protocol.
682 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
683 EFI_STATUS - No PCI Serial device is added.
688 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
691 Status
= gBS
->HandleProtocol (
693 &gEfiDevicePathProtocolGuid
,
696 if (EFI_ERROR (Status
)) {
700 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
701 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
703 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
704 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
705 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
711 VisitAllInstancesOfProtocol (
713 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
719 EFI_HANDLE
*HandleBuffer
;
724 // Start to check all the PciIo to find all possible device
728 Status
= gBS
->LocateHandleBuffer (
735 if (EFI_ERROR (Status
)) {
739 for (Index
= 0; Index
< HandleCount
; Index
++) {
740 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
741 if (EFI_ERROR (Status
)) {
745 Status
= (*CallBackFunction
) (
752 gBS
->FreePool (HandleBuffer
);
760 VisitingAPciInstance (
761 IN EFI_HANDLE Handle
,
767 EFI_PCI_IO_PROTOCOL
*PciIo
;
770 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
773 // Check for all PCI device
775 Status
= PciIo
->Pci
.Read (
779 sizeof (Pci
) / sizeof (UINT32
),
782 if (EFI_ERROR (Status
)) {
786 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
797 VisitAllPciInstances (
798 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
801 return VisitAllInstancesOfProtocol (
802 &gEfiPciIoProtocolGuid
,
803 VisitingAPciInstance
,
804 (VOID
*)(UINTN
) CallBackFunction
810 Do platform specific PCI Device check and add them to
811 ConOut, ConIn, ErrOut.
813 @param[in] Handle - Handle of PCI device instance
814 @param[in] PciIo - PCI IO protocol instance
815 @param[in] Pci - PCI Header register block
817 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
818 @retval EFI_STATUS - PCI Device check or Console variable update fail.
823 DetectAndPreparePlatformPciDevicePath (
824 IN EFI_HANDLE Handle
,
825 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
831 Status
= PciIo
->Attributes (
833 EfiPciIoAttributeOperationEnable
,
834 EFI_PCI_DEVICE_ENABLE
,
837 ASSERT_EFI_ERROR (Status
);
839 if (!mDetectVgaOnly
) {
841 // Here we decide whether it is LPC Bridge
843 if ((IS_PCI_LPC (Pci
)) ||
844 ((IS_PCI_ISA_PDECODE (Pci
)) &&
845 (Pci
->Hdr
.VendorId
== 0x8086) &&
846 (Pci
->Hdr
.DeviceId
== 0x7000)
850 // Add IsaKeyboard to ConIn,
851 // add IsaSerial to ConOut, ConIn, ErrOut
853 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
854 PrepareLpcBridgeDevicePath (Handle
);
858 // Here we decide which Serial device to enable in PCI bus
860 if (IS_PCI_16550SERIAL (Pci
)) {
862 // Add them to ConOut, ConIn, ErrOut.
864 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
865 PreparePciSerialDevicePath (Handle
);
871 // Here we decide which display device to enable in PCI bus
873 if (IS_PCI_DISPLAY (Pci
)) {
875 // Add them to ConOut.
877 DEBUG ((EFI_D_INFO
, "Found PCI display device\n"));
878 PreparePciDisplayDevicePath (Handle
);
887 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
889 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
891 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
892 @retval EFI_STATUS - PCI Device check or Console variable update fail.
896 DetectAndPreparePlatformPciDevicePaths (
897 BOOLEAN DetectVgaOnly
900 mDetectVgaOnly
= DetectVgaOnly
;
901 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
906 PlatformInitializeConsole (
907 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
913 Connect the predefined platform default console device. Always try to find
914 and enable the vga device if have.
918 PlatformConsole - Predfined platform default console device array.
922 EFI_DEVICE_PATH_PROTOCOL
*VarConout
;
923 EFI_DEVICE_PATH_PROTOCOL
*VarConin
;
926 // Connect RootBridge
928 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME
, (VOID
**) &VarConout
, NULL
);
929 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME
, (VOID
**) &VarConin
, NULL
);
931 if (VarConout
== NULL
|| VarConin
== NULL
) {
933 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
935 DetectAndPreparePlatformPciDevicePaths (FALSE
);
938 // Have chance to connect the platform default console,
939 // the platform default console is the minimue device group
940 // the platform should support
942 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
944 // Update the console variable with the connect type
946 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
947 EfiBootManagerUpdateConsoleVariable (ConIn
, PlatformConsole
[Index
].DevicePath
, NULL
);
949 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
950 EfiBootManagerUpdateConsoleVariable (ConOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
952 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
953 EfiBootManagerUpdateConsoleVariable (ErrOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
958 // Only detect VGA device and add them to ConOut
960 DetectAndPreparePlatformPciDevicePaths (TRUE
);
966 Configure PCI Interrupt Line register for applicable devices
967 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
969 @param[in] Handle - Handle of PCI device instance
970 @param[in] PciIo - PCI IO protocol instance
971 @param[in] PciHdr - PCI Header register block
973 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
979 IN EFI_HANDLE Handle
,
980 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
981 IN PCI_TYPE00
*PciHdr
984 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
985 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
990 UINT32 RootBusNumber
;
992 Status
= EFI_SUCCESS
;
994 if (PciHdr
->Device
.InterruptPin
!= 0) {
996 DevPathNode
= DevicePathFromHandle (Handle
);
997 ASSERT (DevPathNode
!= NULL
);
998 DevPath
= DevPathNode
;
1001 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
1002 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
1003 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
1004 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
1008 // Compute index into PciHostIrqs[] table by walking
1009 // the device path and adding up all device numbers
1011 Status
= EFI_NOT_FOUND
;
1013 Idx
= PciHdr
->Device
.InterruptPin
- 1;
1014 while (!IsDevicePathEnd (DevPathNode
)) {
1015 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
1016 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
1018 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1021 // Unlike SeaBIOS, which starts climbing from the leaf device
1022 // up toward the root, we traverse the device path starting at
1023 // the root moving toward the leaf node.
1024 // The slot number of the top-level parent bridge is needed for
1025 // Q35 cases with more than 24 slots on the root bus.
1027 if (Status
!= EFI_SUCCESS
) {
1028 Status
= EFI_SUCCESS
;
1029 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
1033 DevPathNode
= NextDevicePathNode (DevPathNode
);
1035 if (EFI_ERROR (Status
)) {
1038 if (RootBusNumber
== 0 && RootSlot
== 0) {
1041 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1048 // Final PciHostIrqs[] index calculation depends on the platform
1049 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1051 switch (mHostBridgeDevId
) {
1052 case INTEL_82441_DEVICE_ID
:
1055 case INTEL_Q35_MCH_DEVICE_ID
:
1057 // SeaBIOS contains the following comment:
1058 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1059 // with a different starting index - see q35-acpi-dsdt.dsl.
1061 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1063 if (RootSlot
> 24) {
1065 // in this case, subtract back out RootSlot from Idx
1066 // (SeaBIOS never adds it to begin with, but that would make our
1067 // device path traversal loop above too awkward)
1073 ASSERT (FALSE
); // should never get here
1075 Idx
%= ARRAY_SIZE (PciHostIrqs
);
1076 IrqLine
= PciHostIrqs
[Idx
];
1078 DEBUG_CODE_BEGIN ();
1080 CHAR16
*DevPathString
;
1081 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
1082 UINTN Segment
, Bus
, Device
, Function
;
1084 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
1085 if (DevPathString
== NULL
) {
1086 DevPathString
= Fallback
;
1088 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
1089 ASSERT_EFI_ERROR (Status
);
1091 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
1092 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
1095 if (DevPathString
!= Fallback
) {
1096 FreePool (DevPathString
);
1102 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1104 Status
= PciIo
->Pci
.Write (
1107 PCI_INT_LINE_OFFSET
,
1118 PciAcpiInitialization (
1124 // Query Host Bridge DID to determine platform type
1126 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1127 switch (mHostBridgeDevId
) {
1128 case INTEL_82441_DEVICE_ID
:
1129 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1131 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1133 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1134 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1135 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1136 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1138 case INTEL_Q35_MCH_DEVICE_ID
:
1139 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1141 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1143 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1144 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1145 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1146 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1147 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1148 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1149 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1150 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1153 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1154 __FUNCTION__
, mHostBridgeDevId
));
1160 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1162 VisitAllPciInstances (SetPciIntLine
);
1165 // Set ACPI SCI_EN bit in PMCNTRL
1167 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1171 This function detects if OVMF is running on Xen.
1180 EFI_HOB_GUID_TYPE
*GuidHob
;
1181 STATIC INTN FoundHob
= -1;
1183 if (FoundHob
== 0) {
1185 } else if (FoundHob
== 1) {
1190 // See if a XenInfo HOB is available
1192 GuidHob
= GetFirstGuidHob (&gEfiXenInfoGuid
);
1193 if (GuidHob
== NULL
) {
1204 ConnectRecursivelyIfPciMassStorage (
1205 IN EFI_HANDLE Handle
,
1206 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1207 IN PCI_TYPE00
*PciHeader
1211 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1215 // Recognize PCI Mass Storage, and Xen PCI devices
1217 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ||
1218 (XenDetected() && IS_CLASS2 (PciHeader
, 0xFF, 0x80))) {
1220 Status
= gBS
->HandleProtocol (
1222 &gEfiDevicePathProtocolGuid
,
1225 if (EFI_ERROR (Status
)) {
1230 // Print Device Path
1232 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1233 if (DevPathStr
!= NULL
) {
1236 "Found %s device: %s\n",
1237 IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
) ? L
"Mass Storage" : L
"Xen",
1240 FreePool(DevPathStr
);
1243 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1244 if (EFI_ERROR (Status
)) {
1255 This notification function is invoked when the
1256 EMU Variable FVB has been changed.
1258 @param Event The event that occurred
1259 @param Context For EFI compatibility. Not used.
1264 EmuVariablesUpdatedCallback (
1269 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1270 UpdateNvVarsOnFileSystem ();
1276 VisitingFileSystemInstance (
1277 IN EFI_HANDLE Handle
,
1283 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
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 PcdSet64 (PcdEmuVariableEvent
, (UINT64
)(UINTN
) mEmuVariableEvent
);
1310 PlatformBdsRestoreNvVarsFromHardDisk (
1313 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1314 VisitAllInstancesOfProtocol (
1315 &gEfiSimpleFileSystemProtocolGuid
,
1316 VisitingFileSystemInstance
,
1323 PlatformBdsConnectSequence (
1328 Routine Description:
1330 Connect with predeined platform connect sequence,
1331 the OEM/IBV can customize with their own connect sequence.
1345 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1350 // Here we can get the customized platform connect sequence
1351 // Notes: we can connect with new variable which record the
1352 // last time boots connect device path sequence
1354 while (gPlatformConnectSequence
[Index
] != NULL
) {
1356 // Build the platform boot option
1358 EfiBootManagerConnectDevicePath (gPlatformConnectSequence
[Index
], NULL
);
1363 // Just use the simple policy to connect all devices
1365 DEBUG ((EFI_D_INFO
, "EfiBootManagerConnectAll\n"));
1366 EfiBootManagerConnectAll ();
1368 PciAcpiInitialization ();
1372 Save the S3 boot script.
1374 Note that DxeSmmReadyToLock must be signaled after this function returns;
1375 otherwise the script wouldn't be saved actually.
1384 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1385 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1387 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1388 (VOID
**) &BootScript
);
1389 ASSERT_EFI_ERROR (Status
);
1392 // Despite the opcode documentation in the PI spec, the protocol
1393 // implementation embeds a deep copy of the info in the boot script, rather
1394 // than storing just a pointer to runtime or NVS storage.
1396 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1397 (UINT32
) sizeof Info
,
1398 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1399 ASSERT_EFI_ERROR (Status
);
1405 PlatformBootManagerAfterConsole (
1410 Routine Description:
1412 The function will excute with as the platform policy, current policy
1413 is driven by boot mode. IBV/OEM can customize this code for their specific
1418 EFI_BOOT_MODE BootMode
;
1420 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1422 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1423 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1424 "from disk since flash variables appear to be supported.\n"));
1427 // Try to restore variables from the hard disk early so
1428 // they can be used for the other BDS connect operations.
1430 PlatformBdsRestoreNvVarsFromHardDisk ();
1434 // Get current Boot Mode
1436 BootMode
= GetBootModeHob ();
1437 DEBUG ((EFI_D_ERROR
, "Boot Mode:%x\n", BootMode
));
1440 // Go the different platform policy with different boot mode
1441 // Notes: this part code can be change with the table policy
1443 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1448 //BootLogoEnableLogo (
1449 // ImageFormatBmp, // ImageFormat
1450 // PcdGetPtr (PcdLogoFile), // Logo
1451 // EdkiiPlatformLogoDisplayAttributeCenter, // Attribute
1457 // Perform some platform specific connect sequence
1459 PlatformBdsConnectSequence ();
1462 // Process QEMU's -kernel command line option
1464 TryRunningQemuKernel ();
1466 EfiBootManagerRefreshAllBootOption ();
1469 // Register UEFI Shell
1471 PlatformRegisterFvBootOption (
1472 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
1475 RemoveStaleFvFileOptions ();
1476 SetBootOrderFromQemu ();
1480 This notification function is invoked when an instance of the
1481 EFI_DEVICE_PATH_PROTOCOL is produced.
1483 @param Event The event that occurred
1484 @param Context For EFI compatibility. Not used.
1497 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1498 ATAPI_DEVICE_PATH
*Atapi
;
1501 // Examine all new handles
1505 // Get the next handle
1507 BufferSize
= sizeof (Handle
);
1508 Status
= gBS
->LocateHandle (
1511 mEfiDevPathNotifyReg
,
1517 // If not found, we're done
1519 if (EFI_NOT_FOUND
== Status
) {
1523 if (EFI_ERROR (Status
)) {
1528 // Get the DevicePath protocol on that handle
1530 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevPathNode
);
1531 ASSERT_EFI_ERROR (Status
);
1533 while (!IsDevicePathEnd (DevPathNode
)) {
1535 // Find the handler to dump this device path node
1538 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1539 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1541 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1547 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1554 // Next device path node
1556 DevPathNode
= NextDevicePathNode (DevPathNode
);
1565 InstallDevicePathCallback (
1569 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1570 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1571 &gEfiDevicePathProtocolGuid
,
1575 &mEfiDevPathNotifyReg
1580 This function is called each second during the boot manager waits the timeout.
1582 @param TimeoutRemain The remaining timeout.
1586 PlatformBootManagerWaitCallback (
1587 UINT16 TimeoutRemain
1590 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
1591 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
1594 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
1596 Black
.Raw
= 0x00000000;
1597 White
.Raw
= 0x00FFFFFF;
1599 BootLogoUpdateProgress (
1602 L
"Start boot option",
1604 (Timeout
- TimeoutRemain
) * 100 / Timeout
,