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/RootBridgesConnectedEventGroup.h>
17 #include <Library/QemuBootOrderLib.h>
24 VOID
*mEfiDevPathNotifyReg
;
25 EFI_EVENT mEfiDevPathEvent
;
26 VOID
*mEmuVariableEventReg
;
27 EFI_EVENT mEmuVariableEvent
;
28 BOOLEAN mDetectVgaOnly
;
29 UINT16 mHostBridgeDevId
;
32 // Table of host IRQs matching PCI IRQs A-D
33 // (for configuring PCI Interrupt Line register)
35 CONST UINT8 PciHostIrqs
[] = {
36 0x0a, 0x0a, 0x0b, 0x0b
42 #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
50 (EFIAPI
*PROTOCOL_INSTANCE_CALLBACK
)(
57 @param[in] Handle - Handle of PCI device instance
58 @param[in] PciIo - PCI IO protocol instance
59 @param[in] Pci - PCI Header register block
63 (EFIAPI
*VISIT_PCI_INSTANCE_CALLBACK
)(
65 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
71 // Function prototypes
75 VisitAllInstancesOfProtocol (
77 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
82 VisitAllPciInstancesOfProtocol (
83 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
87 InstallDevicePathCallback (
92 PlatformRegisterFvBootOption (
100 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
101 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
102 UINTN BootOptionCount
;
103 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
104 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
105 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
107 Status
= gBS
->HandleProtocol (
109 &gEfiLoadedImageProtocolGuid
,
110 (VOID
**) &LoadedImage
112 ASSERT_EFI_ERROR (Status
);
114 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
115 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
116 ASSERT (DevicePath
!= NULL
);
117 DevicePath
= AppendDevicePathNode (
119 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
121 ASSERT (DevicePath
!= NULL
);
123 Status
= EfiBootManagerInitializeLoadOption (
125 LoadOptionNumberUnassigned
,
133 ASSERT_EFI_ERROR (Status
);
134 FreePool (DevicePath
);
136 BootOptions
= EfiBootManagerGetLoadOptions (
137 &BootOptionCount
, LoadOptionTypeBoot
140 OptionIndex
= EfiBootManagerFindLoadOption (
141 &NewOption
, BootOptions
, BootOptionCount
144 if (OptionIndex
== -1) {
145 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
146 ASSERT_EFI_ERROR (Status
);
148 EfiBootManagerFreeLoadOption (&NewOption
);
149 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
153 PlatformRegisterOptionsAndKeys (
161 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
164 // Register ENTER as CONTINUE key
166 Enter
.ScanCode
= SCAN_NULL
;
167 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
168 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
169 ASSERT_EFI_ERROR (Status
);
172 // Map F2 to Boot Manager Menu
174 F2
.ScanCode
= SCAN_F2
;
175 F2
.UnicodeChar
= CHAR_NULL
;
176 Esc
.ScanCode
= SCAN_ESC
;
177 Esc
.UnicodeChar
= CHAR_NULL
;
178 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
179 ASSERT_EFI_ERROR (Status
);
180 Status
= EfiBootManagerAddKeyOptionVariable (
181 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
183 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
184 Status
= EfiBootManagerAddKeyOptionVariable (
185 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
187 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
189 // Register UEFI Shell
191 PlatformRegisterFvBootOption (
192 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
199 IN EFI_HANDLE RootBridgeHandle
,
211 // BDS Platform Functions
215 PlatformBootManagerBeforeConsole (
222 Platform Bds init. Incude the platform firmware vendor, revision
236 DEBUG ((EFI_D_INFO
, "PlatformBootManagerBeforeConsole\n"));
237 InstallDevicePathCallback ();
239 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid
,
240 ConnectRootBridge
, NULL
);
243 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
245 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
248 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
249 // the preparation of S3 system information. That logic has a hard dependency
250 // on the presence of the FACS ACPI table. Since our ACPI tables are only
251 // installed after PCI enumeration completes, we must not trigger the S3 save
252 // earlier, hence we can't signal End-of-Dxe earlier.
254 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
256 if (QemuFwCfgS3Enabled ()) {
258 // Save the boot script too. Note that this will require us to emit the
259 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
265 // Prevent further changes to LockBoxes or SMRAM.
268 Status
= gBS
->InstallProtocolInterface (&Handle
,
269 &gEfiDxeSmmReadyToLockProtocolGuid
, EFI_NATIVE_INTERFACE
,
271 ASSERT_EFI_ERROR (Status
);
273 PlatformInitializeConsole (gPlatformConsole
);
274 PcdSet16 (PcdPlatformBootTimeOut
, GetFrontPageTimeoutFromQemu ());
276 PlatformRegisterOptionsAndKeys ();
283 IN EFI_HANDLE RootBridgeHandle
,
291 // Make the PCI bus driver connect the root bridge, non-recursively. This
292 // will produce a number of child handles with PciIo on them.
294 Status
= gBS
->ConnectController (
295 RootBridgeHandle
, // ControllerHandle
296 NULL
, // DriverImageHandle
297 NULL
, // RemainingDevicePath -- produce all
306 PrepareLpcBridgeDevicePath (
307 IN EFI_HANDLE DeviceHandle
313 Add IsaKeyboard to ConIn,
314 add IsaSerial to ConOut, ConIn, ErrOut.
319 DeviceHandle - Handle of PCIIO protocol.
323 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
324 EFI_STATUS - No LPC bridge is added.
329 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
330 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
334 Status
= gBS
->HandleProtocol (
336 &gEfiDevicePathProtocolGuid
,
339 if (EFI_ERROR (Status
)) {
342 TempDevicePath
= DevicePath
;
347 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnpPs2KeyboardDeviceNode
);
349 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
354 DevicePath
= TempDevicePath
;
355 gPnp16550ComPortDeviceNode
.UID
= 0;
357 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
358 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
359 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
364 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
365 if (DevPathStr
!= NULL
) {
368 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
370 gPnp16550ComPortDeviceNode
.UID
+ 1,
373 FreePool(DevPathStr
);
376 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
377 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
378 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
383 DevicePath
= TempDevicePath
;
384 gPnp16550ComPortDeviceNode
.UID
= 1;
386 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gPnp16550ComPortDeviceNode
);
387 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
388 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
393 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
394 if (DevPathStr
!= NULL
) {
397 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
399 gPnp16550ComPortDeviceNode
.UID
+ 1,
402 FreePool(DevPathStr
);
405 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
406 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
407 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
414 IN EFI_DEVICE_PATH_PROTOCOL
*PciDevicePath
,
415 OUT EFI_DEVICE_PATH_PROTOCOL
**GopDevicePath
420 EFI_HANDLE PciDeviceHandle
;
421 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
422 EFI_DEVICE_PATH_PROTOCOL
*TempPciDevicePath
;
423 UINTN GopHandleCount
;
424 EFI_HANDLE
*GopHandleBuffer
;
426 if (PciDevicePath
== NULL
|| GopDevicePath
== NULL
) {
427 return EFI_INVALID_PARAMETER
;
431 // Initialize the GopDevicePath to be PciDevicePath
433 *GopDevicePath
= PciDevicePath
;
434 TempPciDevicePath
= PciDevicePath
;
436 Status
= gBS
->LocateDevicePath (
437 &gEfiDevicePathProtocolGuid
,
441 if (EFI_ERROR (Status
)) {
446 // Try to connect this handle, so that GOP dirver could start on this
447 // device and create child handles with GraphicsOutput Protocol installed
448 // on them, then we get device paths of these child handles and select
449 // them as possible console device.
451 gBS
->ConnectController (PciDeviceHandle
, NULL
, NULL
, FALSE
);
453 Status
= gBS
->LocateHandleBuffer (
455 &gEfiGraphicsOutputProtocolGuid
,
460 if (!EFI_ERROR (Status
)) {
462 // Add all the child handles as possible Console Device
464 for (Index
= 0; Index
< GopHandleCount
; Index
++) {
465 Status
= gBS
->HandleProtocol (GopHandleBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*)&TempDevicePath
);
466 if (EFI_ERROR (Status
)) {
472 GetDevicePathSize (PciDevicePath
) - END_DEVICE_PATH_LENGTH
475 // In current implementation, we only enable one of the child handles
476 // as console device, i.e. sotre one of the child handle's device
477 // path to variable "ConOut"
478 // In futhure, we could select all child handles to be console device
481 *GopDevicePath
= TempDevicePath
;
484 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
485 // Add the integrity GOP device path.
487 EfiBootManagerUpdateConsoleVariable (ConOutDev
, NULL
, PciDevicePath
);
488 EfiBootManagerUpdateConsoleVariable (ConOutDev
, TempDevicePath
, NULL
);
491 gBS
->FreePool (GopHandleBuffer
);
498 PreparePciVgaDevicePath (
499 IN EFI_HANDLE DeviceHandle
505 Add PCI VGA to ConOut.
510 DeviceHandle - Handle of PCIIO protocol.
514 EFI_SUCCESS - PCI VGA is added to ConOut.
515 EFI_STATUS - No PCI VGA device is added.
520 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
521 EFI_DEVICE_PATH_PROTOCOL
*GopDevicePath
;
524 GopDevicePath
= NULL
;
525 Status
= gBS
->HandleProtocol (
527 &gEfiDevicePathProtocolGuid
,
530 if (EFI_ERROR (Status
)) {
534 GetGopDevicePath (DevicePath
, &GopDevicePath
);
535 DevicePath
= GopDevicePath
;
537 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
543 PreparePciSerialDevicePath (
544 IN EFI_HANDLE DeviceHandle
550 Add PCI Serial to ConOut, ConIn, ErrOut.
555 DeviceHandle - Handle of PCIIO protocol.
559 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
560 EFI_STATUS - No PCI Serial device is added.
565 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
568 Status
= gBS
->HandleProtocol (
570 &gEfiDevicePathProtocolGuid
,
573 if (EFI_ERROR (Status
)) {
577 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gUartDeviceNode
);
578 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&gTerminalTypeDeviceNode
);
580 EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
581 EfiBootManagerUpdateConsoleVariable (ConIn
, DevicePath
, NULL
);
582 EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
588 VisitAllInstancesOfProtocol (
590 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction
,
596 EFI_HANDLE
*HandleBuffer
;
601 // Start to check all the PciIo to find all possible device
605 Status
= gBS
->LocateHandleBuffer (
612 if (EFI_ERROR (Status
)) {
616 for (Index
= 0; Index
< HandleCount
; Index
++) {
617 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], Id
, &Instance
);
618 if (EFI_ERROR (Status
)) {
622 Status
= (*CallBackFunction
) (
629 gBS
->FreePool (HandleBuffer
);
637 VisitingAPciInstance (
638 IN EFI_HANDLE Handle
,
644 EFI_PCI_IO_PROTOCOL
*PciIo
;
647 PciIo
= (EFI_PCI_IO_PROTOCOL
*) Instance
;
650 // Check for all PCI device
652 Status
= PciIo
->Pci
.Read (
656 sizeof (Pci
) / sizeof (UINT32
),
659 if (EFI_ERROR (Status
)) {
663 return (*(VISIT_PCI_INSTANCE_CALLBACK
)(UINTN
) Context
) (
674 VisitAllPciInstances (
675 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
678 return VisitAllInstancesOfProtocol (
679 &gEfiPciIoProtocolGuid
,
680 VisitingAPciInstance
,
681 (VOID
*)(UINTN
) CallBackFunction
687 Do platform specific PCI Device check and add them to
688 ConOut, ConIn, ErrOut.
690 @param[in] Handle - Handle of PCI device instance
691 @param[in] PciIo - PCI IO protocol instance
692 @param[in] Pci - PCI Header register block
694 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
695 @retval EFI_STATUS - PCI Device check or Console variable update fail.
700 DetectAndPreparePlatformPciDevicePath (
701 IN EFI_HANDLE Handle
,
702 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
708 Status
= PciIo
->Attributes (
710 EfiPciIoAttributeOperationEnable
,
711 EFI_PCI_DEVICE_ENABLE
,
714 ASSERT_EFI_ERROR (Status
);
716 if (!mDetectVgaOnly
) {
718 // Here we decide whether it is LPC Bridge
720 if ((IS_PCI_LPC (Pci
)) ||
721 ((IS_PCI_ISA_PDECODE (Pci
)) &&
722 (Pci
->Hdr
.VendorId
== 0x8086) &&
723 (Pci
->Hdr
.DeviceId
== 0x7000)
727 // Add IsaKeyboard to ConIn,
728 // add IsaSerial to ConOut, ConIn, ErrOut
730 DEBUG ((EFI_D_INFO
, "Found LPC Bridge device\n"));
731 PrepareLpcBridgeDevicePath (Handle
);
735 // Here we decide which Serial device to enable in PCI bus
737 if (IS_PCI_16550SERIAL (Pci
)) {
739 // Add them to ConOut, ConIn, ErrOut.
741 DEBUG ((EFI_D_INFO
, "Found PCI 16550 SERIAL device\n"));
742 PreparePciSerialDevicePath (Handle
);
748 // Here we decide which VGA device to enable in PCI bus
750 if (IS_PCI_VGA (Pci
)) {
752 // Add them to ConOut.
754 DEBUG ((EFI_D_INFO
, "Found PCI VGA device\n"));
755 PreparePciVgaDevicePath (Handle
);
764 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
766 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
768 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
769 @retval EFI_STATUS - PCI Device check or Console variable update fail.
773 DetectAndPreparePlatformPciDevicePaths (
774 BOOLEAN DetectVgaOnly
777 mDetectVgaOnly
= DetectVgaOnly
;
778 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath
);
783 PlatformInitializeConsole (
784 IN PLATFORM_CONSOLE_CONNECT_ENTRY
*PlatformConsole
790 Connect the predefined platform default console device. Always try to find
791 and enable the vga device if have.
795 PlatformConsole - Predfined platform default console device array.
799 EFI_DEVICE_PATH_PROTOCOL
*VarConout
;
800 EFI_DEVICE_PATH_PROTOCOL
*VarConin
;
803 // Connect RootBridge
805 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME
, (VOID
**) &VarConout
, NULL
);
806 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME
, (VOID
**) &VarConin
, NULL
);
808 if (VarConout
== NULL
|| VarConin
== NULL
) {
810 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
812 DetectAndPreparePlatformPciDevicePaths (FALSE
);
815 // Have chance to connect the platform default console,
816 // the platform default console is the minimue device group
817 // the platform should support
819 for (Index
= 0; PlatformConsole
[Index
].DevicePath
!= NULL
; ++Index
) {
821 // Update the console variable with the connect type
823 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_IN
) == CONSOLE_IN
) {
824 EfiBootManagerUpdateConsoleVariable (ConIn
, PlatformConsole
[Index
].DevicePath
, NULL
);
826 if ((PlatformConsole
[Index
].ConnectType
& CONSOLE_OUT
) == CONSOLE_OUT
) {
827 EfiBootManagerUpdateConsoleVariable (ConOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
829 if ((PlatformConsole
[Index
].ConnectType
& STD_ERROR
) == STD_ERROR
) {
830 EfiBootManagerUpdateConsoleVariable (ErrOut
, PlatformConsole
[Index
].DevicePath
, NULL
);
835 // Only detect VGA device and add them to ConOut
837 DetectAndPreparePlatformPciDevicePaths (TRUE
);
843 Configure PCI Interrupt Line register for applicable devices
844 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
846 @param[in] Handle - Handle of PCI device instance
847 @param[in] PciIo - PCI IO protocol instance
848 @param[in] PciHdr - PCI Header register block
850 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
856 IN EFI_HANDLE Handle
,
857 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
858 IN PCI_TYPE00
*PciHdr
861 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
862 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
867 UINT32 RootBusNumber
;
869 Status
= EFI_SUCCESS
;
871 if (PciHdr
->Device
.InterruptPin
!= 0) {
873 DevPathNode
= DevicePathFromHandle (Handle
);
874 ASSERT (DevPathNode
!= NULL
);
875 DevPath
= DevPathNode
;
878 if (DevicePathType (DevPathNode
) == ACPI_DEVICE_PATH
&&
879 DevicePathSubType (DevPathNode
) == ACPI_DP
&&
880 ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->HID
== EISA_PNP_ID(0x0A03)) {
881 RootBusNumber
= ((ACPI_HID_DEVICE_PATH
*)DevPathNode
)->UID
;
885 // Compute index into PciHostIrqs[] table by walking
886 // the device path and adding up all device numbers
888 Status
= EFI_NOT_FOUND
;
890 Idx
= PciHdr
->Device
.InterruptPin
- 1;
891 while (!IsDevicePathEnd (DevPathNode
)) {
892 if (DevicePathType (DevPathNode
) == HARDWARE_DEVICE_PATH
&&
893 DevicePathSubType (DevPathNode
) == HW_PCI_DP
) {
895 Idx
+= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
898 // Unlike SeaBIOS, which starts climbing from the leaf device
899 // up toward the root, we traverse the device path starting at
900 // the root moving toward the leaf node.
901 // The slot number of the top-level parent bridge is needed for
902 // Q35 cases with more than 24 slots on the root bus.
904 if (Status
!= EFI_SUCCESS
) {
905 Status
= EFI_SUCCESS
;
906 RootSlot
= ((PCI_DEVICE_PATH
*)DevPathNode
)->Device
;
910 DevPathNode
= NextDevicePathNode (DevPathNode
);
912 if (EFI_ERROR (Status
)) {
915 if (RootBusNumber
== 0 && RootSlot
== 0) {
918 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
925 // Final PciHostIrqs[] index calculation depends on the platform
926 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
928 switch (mHostBridgeDevId
) {
929 case INTEL_82441_DEVICE_ID
:
932 case INTEL_Q35_MCH_DEVICE_ID
:
934 // SeaBIOS contains the following comment:
935 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
936 // with a different starting index - see q35-acpi-dsdt.dsl.
938 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
942 // in this case, subtract back out RootSlot from Idx
943 // (SeaBIOS never adds it to begin with, but that would make our
944 // device path traversal loop above too awkward)
950 ASSERT (FALSE
); // should never get here
952 Idx
%= ARRAY_SIZE (PciHostIrqs
);
953 IrqLine
= PciHostIrqs
[Idx
];
957 CHAR16
*DevPathString
;
958 STATIC CHAR16 Fallback
[] = L
"<failed to convert>";
959 UINTN Segment
, Bus
, Device
, Function
;
961 DevPathString
= ConvertDevicePathToText (DevPath
, FALSE
, FALSE
);
962 if (DevPathString
== NULL
) {
963 DevPathString
= Fallback
;
965 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
966 ASSERT_EFI_ERROR (Status
);
968 DEBUG ((EFI_D_VERBOSE
, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__
,
969 (UINT32
)Bus
, (UINT32
)Device
, (UINT32
)Function
, DevPathString
,
972 if (DevPathString
!= Fallback
) {
973 FreePool (DevPathString
);
979 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
981 Status
= PciIo
->Pci
.Write (
995 PciAcpiInitialization (
1001 // Query Host Bridge DID to determine platform type
1003 mHostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
1004 switch (mHostBridgeDevId
) {
1005 case INTEL_82441_DEVICE_ID
:
1006 Pmba
= POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA
);
1008 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1010 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1011 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1012 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1013 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1015 case INTEL_Q35_MCH_DEVICE_ID
:
1016 Pmba
= POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
);
1018 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1020 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1021 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1022 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1023 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1024 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1025 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1026 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1027 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1030 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1031 __FUNCTION__
, mHostBridgeDevId
));
1037 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1039 VisitAllPciInstances (SetPciIntLine
);
1042 // Set ACPI SCI_EN bit in PMCNTRL
1044 IoOr16 ((PciRead32 (Pmba
) & ~BIT0
) + 4, BIT0
);
1050 ConnectRecursivelyIfPciMassStorage (
1051 IN EFI_HANDLE Handle
,
1052 IN EFI_PCI_IO_PROTOCOL
*Instance
,
1053 IN PCI_TYPE00
*PciHeader
1057 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1060 if (IS_CLASS1 (PciHeader
, PCI_CLASS_MASS_STORAGE
)) {
1062 Status
= gBS
->HandleProtocol (
1064 &gEfiDevicePathProtocolGuid
,
1067 if (EFI_ERROR (Status
)) {
1072 // Print Device Path
1074 DevPathStr
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
1075 if (DevPathStr
!= NULL
) {
1078 "Found Mass Storage device: %s\n",
1081 FreePool(DevPathStr
);
1084 Status
= gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1085 if (EFI_ERROR (Status
)) {
1096 This notification function is invoked when the
1097 EMU Variable FVB has been changed.
1099 @param Event The event that occured
1100 @param Context For EFI compatiblity. Not used.
1105 EmuVariablesUpdatedCallback (
1110 DEBUG ((EFI_D_INFO
, "EmuVariablesUpdatedCallback\n"));
1111 UpdateNvVarsOnFileSystem ();
1117 VisitingFileSystemInstance (
1118 IN EFI_HANDLE Handle
,
1124 STATIC BOOLEAN ConnectedToFileSystem
= FALSE
;
1126 if (ConnectedToFileSystem
) {
1127 return EFI_ALREADY_STARTED
;
1130 Status
= ConnectNvVarsToFileSystem (Handle
);
1131 if (EFI_ERROR (Status
)) {
1135 ConnectedToFileSystem
= TRUE
;
1137 EfiCreateProtocolNotifyEvent (
1138 &gEfiDevicePathProtocolGuid
,
1140 EmuVariablesUpdatedCallback
,
1142 &mEmuVariableEventReg
1144 PcdSet64 (PcdEmuVariableEvent
, (UINT64
)(UINTN
) mEmuVariableEvent
);
1151 PlatformBdsRestoreNvVarsFromHardDisk (
1154 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage
);
1155 VisitAllInstancesOfProtocol (
1156 &gEfiSimpleFileSystemProtocolGuid
,
1157 VisitingFileSystemInstance
,
1165 PlatformBdsConnectSequence (
1170 Routine Description:
1172 Connect with predeined platform connect sequence,
1173 the OEM/IBV can customize with their own connect sequence.
1187 DEBUG ((EFI_D_INFO
, "PlatformBdsConnectSequence\n"));
1192 // Here we can get the customized platform connect sequence
1193 // Notes: we can connect with new variable which record the
1194 // last time boots connect device path sequence
1196 while (gPlatformConnectSequence
[Index
] != NULL
) {
1198 // Build the platform boot option
1200 BdsLibConnectDevicePath (gPlatformConnectSequence
[Index
]);
1205 // Just use the simple policy to connect all devices
1207 BdsLibConnectAll ();
1209 PciAcpiInitialization ();
1212 // Clear the logo after all devices are connected.
1214 gST
->ConOut
->ClearScreen (gST
->ConOut
);
1218 PlatformBdsGetDriverOption (
1219 IN OUT LIST_ENTRY
*BdsDriverLists
1223 Routine Description:
1225 Load the predefined driver option, OEM/IBV can customize this
1226 to load their own drivers
1230 BdsDriverLists - The header of the driver option link list.
1238 DEBUG ((EFI_D_INFO
, "PlatformBdsGetDriverOption\n"));
1243 PlatformBdsDiagnostics (
1244 IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel
,
1245 IN BOOLEAN QuietBoot
,
1246 IN BASEM_MEMORY_TEST BaseMemoryTest
1250 Routine Description:
1252 Perform the platform diagnostic, such like test memory. OEM/IBV also
1253 can customize this fuction to support specific platform diagnostic.
1257 MemoryTestLevel - The memory test intensive level
1259 QuietBoot - Indicate if need to enable the quiet boot
1261 BaseMemoryTest - A pointer to BaseMemoryTest()
1271 DEBUG ((EFI_D_INFO
, "PlatformBdsDiagnostics\n"));
1274 // Here we can decide if we need to show
1275 // the diagnostics screen
1276 // Notes: this quiet boot code should be remove
1277 // from the graphic lib
1280 EnableQuietBoot (PcdGetPtr(PcdLogoFile
));
1282 // Perform system diagnostic
1284 Status
= BaseMemoryTest (MemoryTestLevel
);
1285 if (EFI_ERROR (Status
)) {
1286 DisableQuietBoot ();
1292 // Perform system diagnostic
1294 Status
= BaseMemoryTest (MemoryTestLevel
);
1299 Save the S3 boot script.
1301 Note that DxeSmmReadyToLock must be signaled after this function returns;
1302 otherwise the script wouldn't be saved actually.
1311 EFI_S3_SAVE_STATE_PROTOCOL
*BootScript
;
1312 STATIC CONST UINT8 Info
[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1314 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
, NULL
,
1315 (VOID
**) &BootScript
);
1316 ASSERT_EFI_ERROR (Status
);
1319 // Despite the opcode documentation in the PI spec, the protocol
1320 // implementation embeds a deep copy of the info in the boot script, rather
1321 // than storing just a pointer to runtime or NVS storage.
1323 Status
= BootScript
->Write(BootScript
, EFI_BOOT_SCRIPT_INFORMATION_OPCODE
,
1324 (UINT32
) sizeof Info
,
1325 (EFI_PHYSICAL_ADDRESS
)(UINTN
) &Info
);
1326 ASSERT_EFI_ERROR (Status
);
1332 PlatformBootManagerAfterConsole (
1337 Routine Description:
1339 The function will excute with as the platform policy, current policy
1340 is driven by boot mode. IBV/OEM can customize this code for their specific
1346 EFI_BOOT_MODE BootMode
;
1348 DEBUG ((EFI_D_INFO
, "PlatformBootManagerAfterConsole\n"));
1350 if (PcdGetBool (PcdOvmfFlashVariablesEnable
)) {
1351 DEBUG ((EFI_D_INFO
, "PlatformBdsPolicyBehavior: not restoring NvVars "
1352 "from disk since flash variables appear to be supported.\n"));
1355 // Try to restore variables from the hard disk early so
1356 // they can be used for the other BDS connect operations.
1358 PlatformBdsRestoreNvVarsFromHardDisk ();
1362 // Load the driver option as the driver option list
1364 PlatformBdsGetDriverOption (DriverOptionList
);
1367 // Get current Boot Mode
1369 Status
= BdsLibGetBootMode (&BootMode
);
1370 DEBUG ((EFI_D_ERROR
, "Boot Mode:%x\n", BootMode
));
1373 // Go the different platform policy with different boot mode
1374 // Notes: this part code can be change with the table policy
1376 ASSERT (BootMode
== BOOT_WITH_FULL_CONFIGURATION
);
1379 // Memory test and Logo show
1381 PlatformBdsDiagnostics (IGNORE
, TRUE
, BaseMemoryTest
);
1384 // Perform some platform specific connect sequence
1386 PlatformBdsConnectSequence ();
1389 // Process QEMU's -kernel command line option
1391 TryRunningQemuKernel ();
1393 DEBUG ((EFI_D_INFO
, "BdsLibConnectAll\n"));
1394 BdsLibConnectAll ();
1395 BdsLibEnumerateAllBootOption (BootOptionList
);
1397 SetBootOrderFromQemu (BootOptionList
);
1399 // The BootOrder variable may have changed, reload the in-memory list with
1402 BdsLibBuildOptionFromVar (BootOptionList
, L
"BootOrder");
1407 PlatformBdsBootSuccess (
1408 IN BDS_COMMON_OPTION
*Option
1412 Routine Description:
1414 Hook point after a boot attempt succeeds. We don't expect a boot option to
1415 return, so the EFI 1.0 specification defines that you will default to an
1416 interactive mode and stop processing the BootOrder list in this case. This
1417 is alos a platform implementation and can be customized by IBV/OEM.
1421 Option - Pointer to Boot Option that succeeded to boot.
1431 DEBUG ((EFI_D_INFO
, "PlatformBdsBootSuccess\n"));
1433 // If Boot returned with EFI_SUCCESS and there is not in the boot device
1434 // select loop then we need to pop up a UI and wait for user input.
1436 TmpStr
= Option
->StatusString
;
1437 if (TmpStr
!= NULL
) {
1438 BdsLibOutputStrings (gST
->ConOut
, TmpStr
, Option
->Description
, L
"\n\r", NULL
);
1445 PlatformBdsBootFail (
1446 IN BDS_COMMON_OPTION
*Option
,
1447 IN EFI_STATUS Status
,
1448 IN CHAR16
*ExitData
,
1449 IN UINTN ExitDataSize
1453 Routine Description:
1455 Hook point after a boot attempt fails.
1459 Option - Pointer to Boot Option that failed to boot.
1461 Status - Status returned from failed boot.
1463 ExitData - Exit data returned from failed boot.
1465 ExitDataSize - Exit data size returned from failed boot.
1475 DEBUG ((EFI_D_INFO
, "PlatformBdsBootFail\n"));
1478 // If Boot returned with failed status then we need to pop up a UI and wait
1481 TmpStr
= Option
->StatusString
;
1482 if (TmpStr
!= NULL
) {
1483 BdsLibOutputStrings (gST
->ConOut
, TmpStr
, Option
->Description
, L
"\n\r", NULL
);
1490 PlatformBdsLockNonUpdatableFlash (
1494 DEBUG ((EFI_D_INFO
, "PlatformBdsLockNonUpdatableFlash\n"));
1500 This notification function is invoked when an instance of the
1501 EFI_DEVICE_PATH_PROTOCOL is produced.
1503 @param Event The event that occured
1504 @param Context For EFI compatiblity. Not used.
1517 EFI_DEVICE_PATH_PROTOCOL
*DevPathNode
;
1518 ATAPI_DEVICE_PATH
*Atapi
;
1521 // Examine all new handles
1525 // Get the next handle
1527 BufferSize
= sizeof (Handle
);
1528 Status
= gBS
->LocateHandle (
1531 mEfiDevPathNotifyReg
,
1537 // If not found, we're done
1539 if (EFI_NOT_FOUND
== Status
) {
1543 if (EFI_ERROR (Status
)) {
1548 // Get the DevicePath protocol on that handle
1550 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevPathNode
);
1551 ASSERT_EFI_ERROR (Status
);
1553 while (!IsDevicePathEnd (DevPathNode
)) {
1555 // Find the handler to dump this device path node
1558 (DevicePathType(DevPathNode
) == MESSAGING_DEVICE_PATH
) &&
1559 (DevicePathSubType(DevPathNode
) == MSG_ATAPI_DP
)
1561 Atapi
= (ATAPI_DEVICE_PATH
*) DevPathNode
;
1567 (Atapi
->PrimarySecondary
== 1) ? 0x42: 0x40
1574 // Next device path node
1576 DevPathNode
= NextDevicePathNode (DevPathNode
);
1585 InstallDevicePathCallback (
1589 DEBUG ((EFI_D_INFO
, "Registered NotifyDevPath Event\n"));
1590 mEfiDevPathEvent
= EfiCreateProtocolNotifyEvent (
1591 &gEfiDevicePathProtocolGuid
,
1595 &mEfiDevPathNotifyReg
1600 This function is called each second during the boot manager waits the timeout.
1602 @param TimeoutRemain The remaining timeout.
1606 PlatformBootManagerWaitCallback (
1607 UINT16 TimeoutRemain