2015-08-03 07:26:01 +02:00
|
|
|
/** @file
|
|
|
|
Platform BDS customizations.
|
|
|
|
|
2016-04-20 09:46:46 +02:00
|
|
|
Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
|
2015-08-03 07:26:01 +02:00
|
|
|
This program and the accompanying materials
|
|
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "BdsPlatform.h"
|
|
|
|
#include <Guid/RootBridgesConnectedEventGroup.h>
|
|
|
|
#include <Library/QemuBootOrderLib.h>
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Global data
|
|
|
|
//
|
|
|
|
|
|
|
|
VOID *mEfiDevPathNotifyReg;
|
|
|
|
EFI_EVENT mEfiDevPathEvent;
|
|
|
|
VOID *mEmuVariableEventReg;
|
|
|
|
EFI_EVENT mEmuVariableEvent;
|
|
|
|
BOOLEAN mDetectVgaOnly;
|
|
|
|
UINT16 mHostBridgeDevId;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Table of host IRQs matching PCI IRQs A-D
|
|
|
|
// (for configuring PCI Interrupt Line register)
|
|
|
|
//
|
|
|
|
CONST UINT8 PciHostIrqs[] = {
|
|
|
|
0x0a, 0x0a, 0x0b, 0x0b
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// Array Size macro
|
|
|
|
//
|
|
|
|
#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
|
|
|
|
|
|
|
|
//
|
|
|
|
// Type definitions
|
|
|
|
//
|
|
|
|
|
|
|
|
typedef
|
|
|
|
EFI_STATUS
|
|
|
|
(EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
|
|
|
|
IN EFI_HANDLE Handle,
|
|
|
|
IN VOID *Instance,
|
|
|
|
IN VOID *Context
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
@param[in] Handle - Handle of PCI device instance
|
|
|
|
@param[in] PciIo - PCI IO protocol instance
|
|
|
|
@param[in] Pci - PCI Header register block
|
|
|
|
**/
|
|
|
|
typedef
|
|
|
|
EFI_STATUS
|
|
|
|
(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
|
|
|
|
IN EFI_HANDLE Handle,
|
|
|
|
IN EFI_PCI_IO_PROTOCOL *PciIo,
|
|
|
|
IN PCI_TYPE00 *Pci
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Function prototypes
|
|
|
|
//
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
VisitAllInstancesOfProtocol (
|
|
|
|
IN EFI_GUID *Id,
|
|
|
|
IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
|
|
|
|
IN VOID *Context
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
VisitAllPciInstancesOfProtocol (
|
|
|
|
IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
InstallDevicePathCallback (
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
2016-04-20 11:49:15 +02:00
|
|
|
VOID
|
|
|
|
PlatformRegisterFvBootOption (
|
|
|
|
EFI_GUID *FileGuid,
|
|
|
|
CHAR16 *Description,
|
|
|
|
UINT32 Attributes
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
INTN OptionIndex;
|
|
|
|
EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
|
|
|
|
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
|
|
|
|
UINTN BootOptionCount;
|
|
|
|
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
|
|
|
|
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
gImageHandle,
|
|
|
|
&gEfiLoadedImageProtocolGuid,
|
|
|
|
(VOID **) &LoadedImage
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
|
|
|
|
DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
|
|
|
|
ASSERT (DevicePath != NULL);
|
|
|
|
DevicePath = AppendDevicePathNode (
|
|
|
|
DevicePath,
|
|
|
|
(EFI_DEVICE_PATH_PROTOCOL *) &FileNode
|
|
|
|
);
|
|
|
|
ASSERT (DevicePath != NULL);
|
|
|
|
|
|
|
|
Status = EfiBootManagerInitializeLoadOption (
|
|
|
|
&NewOption,
|
|
|
|
LoadOptionNumberUnassigned,
|
|
|
|
LoadOptionTypeBoot,
|
|
|
|
Attributes,
|
|
|
|
Description,
|
|
|
|
DevicePath,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
FreePool (DevicePath);
|
|
|
|
|
|
|
|
BootOptions = EfiBootManagerGetLoadOptions (
|
|
|
|
&BootOptionCount, LoadOptionTypeBoot
|
|
|
|
);
|
|
|
|
|
|
|
|
OptionIndex = EfiBootManagerFindLoadOption (
|
|
|
|
&NewOption, BootOptions, BootOptionCount
|
|
|
|
);
|
|
|
|
|
|
|
|
if (OptionIndex == -1) {
|
|
|
|
Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
}
|
|
|
|
EfiBootManagerFreeLoadOption (&NewOption);
|
|
|
|
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
PlatformRegisterOptionsAndKeys (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_INPUT_KEY Enter;
|
|
|
|
EFI_INPUT_KEY F2;
|
|
|
|
EFI_INPUT_KEY Esc;
|
|
|
|
EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Register ENTER as CONTINUE key
|
|
|
|
//
|
|
|
|
Enter.ScanCode = SCAN_NULL;
|
|
|
|
Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
|
|
|
|
Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Map F2 to Boot Manager Menu
|
|
|
|
//
|
|
|
|
F2.ScanCode = SCAN_F2;
|
|
|
|
F2.UnicodeChar = CHAR_NULL;
|
|
|
|
Esc.ScanCode = SCAN_ESC;
|
|
|
|
Esc.UnicodeChar = CHAR_NULL;
|
|
|
|
Status = EfiBootManagerGetBootManagerMenu (&BootOption);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = EfiBootManagerAddKeyOptionVariable (
|
|
|
|
NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
|
|
|
|
);
|
|
|
|
ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
|
|
|
|
Status = EfiBootManagerAddKeyOptionVariable (
|
|
|
|
NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
|
|
|
|
);
|
|
|
|
ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
|
|
|
|
//
|
|
|
|
// Register UEFI Shell
|
|
|
|
//
|
|
|
|
PlatformRegisterFvBootOption (
|
|
|
|
PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-08-03 07:26:01 +02:00
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
ConnectRootBridge (
|
|
|
|
IN EFI_HANDLE RootBridgeHandle,
|
|
|
|
IN VOID *Instance,
|
|
|
|
IN VOID *Context
|
|
|
|
);
|
|
|
|
|
|
|
|
STATIC
|
|
|
|
VOID
|
|
|
|
SaveS3BootScript (
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// BDS Platform Functions
|
|
|
|
//
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
2016-04-20 09:46:46 +02:00
|
|
|
PlatformBootManagerBeforeConsole (
|
2015-08-03 07:26:01 +02:00
|
|
|
VOID
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Platform Bds init. Incude the platform firmware vendor, revision
|
|
|
|
and so crc check.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
EFI_HANDLE Handle;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
2016-04-20 09:46:46 +02:00
|
|
|
DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n"));
|
2015-08-03 07:26:01 +02:00
|
|
|
InstallDevicePathCallback ();
|
|
|
|
|
|
|
|
VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
|
|
|
|
ConnectRootBridge, NULL);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Signal the ACPI platform driver that it can download QEMU ACPI tables.
|
|
|
|
//
|
|
|
|
EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
|
|
|
|
|
|
|
|
//
|
|
|
|
// We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
|
|
|
|
// the preparation of S3 system information. That logic has a hard dependency
|
|
|
|
// on the presence of the FACS ACPI table. Since our ACPI tables are only
|
|
|
|
// installed after PCI enumeration completes, we must not trigger the S3 save
|
|
|
|
// earlier, hence we can't signal End-of-Dxe earlier.
|
|
|
|
//
|
|
|
|
EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
|
|
|
|
|
|
|
|
if (QemuFwCfgS3Enabled ()) {
|
|
|
|
//
|
|
|
|
// Save the boot script too. Note that this will require us to emit the
|
|
|
|
// DxeSmmReadyToLock event just below, which in turn locks down SMM.
|
|
|
|
//
|
|
|
|
SaveS3BootScript ();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Prevent further changes to LockBoxes or SMRAM.
|
|
|
|
//
|
|
|
|
Handle = NULL;
|
|
|
|
Status = gBS->InstallProtocolInterface (&Handle,
|
|
|
|
&gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
|
|
|
|
NULL);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
2016-04-20 11:36:14 +02:00
|
|
|
|
|
|
|
PlatformInitializeConsole (gPlatformConsole);
|
2016-04-20 11:44:26 +02:00
|
|
|
PcdSet16 (PcdPlatformBootTimeOut, GetFrontPageTimeoutFromQemu ());
|
2016-04-20 11:49:15 +02:00
|
|
|
|
|
|
|
PlatformRegisterOptionsAndKeys ();
|
2015-08-03 07:26:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
ConnectRootBridge (
|
|
|
|
IN EFI_HANDLE RootBridgeHandle,
|
|
|
|
IN VOID *Instance,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Make the PCI bus driver connect the root bridge, non-recursively. This
|
|
|
|
// will produce a number of child handles with PciIo on them.
|
|
|
|
//
|
|
|
|
Status = gBS->ConnectController (
|
|
|
|
RootBridgeHandle, // ControllerHandle
|
|
|
|
NULL, // DriverImageHandle
|
|
|
|
NULL, // RemainingDevicePath -- produce all
|
|
|
|
// children
|
|
|
|
FALSE // Recursive
|
|
|
|
);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
PrepareLpcBridgeDevicePath (
|
|
|
|
IN EFI_HANDLE DeviceHandle
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Add IsaKeyboard to ConIn,
|
|
|
|
add IsaSerial to ConOut, ConIn, ErrOut.
|
|
|
|
LPC Bridge: 06 01 00
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
DeviceHandle - Handle of PCIIO protocol.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
|
|
|
|
EFI_STATUS - No LPC bridge is added.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
|
|
CHAR16 *DevPathStr;
|
|
|
|
|
|
|
|
DevicePath = NULL;
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
DeviceHandle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
(VOID*)&DevicePath
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
TempDevicePath = DevicePath;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Register Keyboard
|
|
|
|
//
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
|
|
|
|
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Register COM1
|
|
|
|
//
|
|
|
|
DevicePath = TempDevicePath;
|
|
|
|
gPnp16550ComPortDeviceNode.UID = 0;
|
|
|
|
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Print Device Path
|
|
|
|
//
|
2016-04-20 11:24:38 +02:00
|
|
|
DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
|
2015-08-03 07:26:01 +02:00
|
|
|
if (DevPathStr != NULL) {
|
|
|
|
DEBUG((
|
|
|
|
EFI_D_INFO,
|
|
|
|
"BdsPlatform.c+%d: COM%d DevPath: %s\n",
|
|
|
|
__LINE__,
|
|
|
|
gPnp16550ComPortDeviceNode.UID + 1,
|
|
|
|
DevPathStr
|
|
|
|
));
|
|
|
|
FreePool(DevPathStr);
|
|
|
|
}
|
|
|
|
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
|
|
|
|
EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
|
|
|
|
EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Register COM2
|
|
|
|
//
|
|
|
|
DevicePath = TempDevicePath;
|
|
|
|
gPnp16550ComPortDeviceNode.UID = 1;
|
|
|
|
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Print Device Path
|
|
|
|
//
|
2016-04-20 11:24:38 +02:00
|
|
|
DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
|
2015-08-03 07:26:01 +02:00
|
|
|
if (DevPathStr != NULL) {
|
|
|
|
DEBUG((
|
|
|
|
EFI_D_INFO,
|
|
|
|
"BdsPlatform.c+%d: COM%d DevPath: %s\n",
|
|
|
|
__LINE__,
|
|
|
|
gPnp16550ComPortDeviceNode.UID + 1,
|
|
|
|
DevPathStr
|
|
|
|
));
|
|
|
|
FreePool(DevPathStr);
|
|
|
|
}
|
|
|
|
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
|
|
|
|
EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
|
|
|
|
EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
GetGopDevicePath (
|
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
|
|
|
|
OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_HANDLE PciDeviceHandle;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
|
|
|
|
UINTN GopHandleCount;
|
|
|
|
EFI_HANDLE *GopHandleBuffer;
|
|
|
|
|
|
|
|
if (PciDevicePath == NULL || GopDevicePath == NULL) {
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize the GopDevicePath to be PciDevicePath
|
|
|
|
//
|
|
|
|
*GopDevicePath = PciDevicePath;
|
|
|
|
TempPciDevicePath = PciDevicePath;
|
|
|
|
|
|
|
|
Status = gBS->LocateDevicePath (
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
&TempPciDevicePath,
|
|
|
|
&PciDeviceHandle
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Try to connect this handle, so that GOP dirver could start on this
|
|
|
|
// device and create child handles with GraphicsOutput Protocol installed
|
|
|
|
// on them, then we get device paths of these child handles and select
|
|
|
|
// them as possible console device.
|
|
|
|
//
|
|
|
|
gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
|
|
|
|
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
|
|
ByProtocol,
|
|
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
|
|
NULL,
|
|
|
|
&GopHandleCount,
|
|
|
|
&GopHandleBuffer
|
|
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// Add all the child handles as possible Console Device
|
|
|
|
//
|
|
|
|
for (Index = 0; Index < GopHandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (CompareMem (
|
|
|
|
PciDevicePath,
|
|
|
|
TempDevicePath,
|
|
|
|
GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
|
|
|
|
) == 0) {
|
|
|
|
//
|
|
|
|
// In current implementation, we only enable one of the child handles
|
|
|
|
// as console device, i.e. sotre one of the child handle's device
|
|
|
|
// path to variable "ConOut"
|
|
|
|
// In futhure, we could select all child handles to be console device
|
|
|
|
//
|
|
|
|
|
|
|
|
*GopDevicePath = TempDevicePath;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
|
|
|
|
// Add the integrity GOP device path.
|
|
|
|
//
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
|
|
|
|
EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
gBS->FreePool (GopHandleBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
PreparePciVgaDevicePath (
|
|
|
|
IN EFI_HANDLE DeviceHandle
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Add PCI VGA to ConOut.
|
|
|
|
PCI VGA: 03 00 00
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
DeviceHandle - Handle of PCIIO protocol.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
EFI_SUCCESS - PCI VGA is added to ConOut.
|
|
|
|
EFI_STATUS - No PCI VGA device is added.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
|
|
|
|
|
|
|
|
DevicePath = NULL;
|
|
|
|
GopDevicePath = NULL;
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
DeviceHandle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
(VOID*)&DevicePath
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetGopDevicePath (DevicePath, &GopDevicePath);
|
|
|
|
DevicePath = GopDevicePath;
|
|
|
|
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
PreparePciSerialDevicePath (
|
|
|
|
IN EFI_HANDLE DeviceHandle
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Add PCI Serial to ConOut, ConIn, ErrOut.
|
|
|
|
PCI Serial: 07 00 02
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
DeviceHandle - Handle of PCIIO protocol.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
|
|
|
|
EFI_STATUS - No PCI Serial device is added.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
|
|
|
|
DevicePath = NULL;
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
DeviceHandle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
(VOID*)&DevicePath
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
|
|
|
|
DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
|
|
|
|
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
|
|
|
|
EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
|
|
|
|
EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
VisitAllInstancesOfProtocol (
|
|
|
|
IN EFI_GUID *Id,
|
|
|
|
IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN HandleCount;
|
|
|
|
EFI_HANDLE *HandleBuffer;
|
|
|
|
UINTN Index;
|
|
|
|
VOID *Instance;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Start to check all the PciIo to find all possible device
|
|
|
|
//
|
|
|
|
HandleCount = 0;
|
|
|
|
HandleBuffer = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
|
|
ByProtocol,
|
|
|
|
Id,
|
|
|
|
NULL,
|
|
|
|
&HandleCount,
|
|
|
|
&HandleBuffer
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = (*CallBackFunction) (
|
|
|
|
HandleBuffer[Index],
|
|
|
|
Instance,
|
|
|
|
Context
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
gBS->FreePool (HandleBuffer);
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
VisitingAPciInstance (
|
|
|
|
IN EFI_HANDLE Handle,
|
|
|
|
IN VOID *Instance,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
|
|
PCI_TYPE00 Pci;
|
|
|
|
|
|
|
|
PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check for all PCI device
|
|
|
|
//
|
|
|
|
Status = PciIo->Pci.Read (
|
|
|
|
PciIo,
|
|
|
|
EfiPciIoWidthUint32,
|
|
|
|
0,
|
|
|
|
sizeof (Pci) / sizeof (UINT32),
|
|
|
|
&Pci
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
|
|
|
|
Handle,
|
|
|
|
PciIo,
|
|
|
|
&Pci
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
VisitAllPciInstances (
|
|
|
|
IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return VisitAllInstancesOfProtocol (
|
|
|
|
&gEfiPciIoProtocolGuid,
|
|
|
|
VisitingAPciInstance,
|
|
|
|
(VOID*)(UINTN) CallBackFunction
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Do platform specific PCI Device check and add them to
|
|
|
|
ConOut, ConIn, ErrOut.
|
|
|
|
|
|
|
|
@param[in] Handle - Handle of PCI device instance
|
|
|
|
@param[in] PciIo - PCI IO protocol instance
|
|
|
|
@param[in] Pci - PCI Header register block
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
|
|
|
|
@retval EFI_STATUS - PCI Device check or Console variable update fail.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
DetectAndPreparePlatformPciDevicePath (
|
|
|
|
IN EFI_HANDLE Handle,
|
|
|
|
IN EFI_PCI_IO_PROTOCOL *PciIo,
|
|
|
|
IN PCI_TYPE00 *Pci
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = PciIo->Attributes (
|
|
|
|
PciIo,
|
|
|
|
EfiPciIoAttributeOperationEnable,
|
|
|
|
EFI_PCI_DEVICE_ENABLE,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
if (!mDetectVgaOnly) {
|
|
|
|
//
|
|
|
|
// Here we decide whether it is LPC Bridge
|
|
|
|
//
|
|
|
|
if ((IS_PCI_LPC (Pci)) ||
|
|
|
|
((IS_PCI_ISA_PDECODE (Pci)) &&
|
|
|
|
(Pci->Hdr.VendorId == 0x8086) &&
|
|
|
|
(Pci->Hdr.DeviceId == 0x7000)
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
//
|
|
|
|
// Add IsaKeyboard to ConIn,
|
|
|
|
// add IsaSerial to ConOut, ConIn, ErrOut
|
|
|
|
//
|
|
|
|
DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
|
|
|
|
PrepareLpcBridgeDevicePath (Handle);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Here we decide which Serial device to enable in PCI bus
|
|
|
|
//
|
|
|
|
if (IS_PCI_16550SERIAL (Pci)) {
|
|
|
|
//
|
|
|
|
// Add them to ConOut, ConIn, ErrOut.
|
|
|
|
//
|
|
|
|
DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
|
|
|
|
PreparePciSerialDevicePath (Handle);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Here we decide which VGA device to enable in PCI bus
|
|
|
|
//
|
|
|
|
if (IS_PCI_VGA (Pci)) {
|
|
|
|
//
|
|
|
|
// Add them to ConOut.
|
|
|
|
//
|
|
|
|
DEBUG ((EFI_D_INFO, "Found PCI VGA device\n"));
|
|
|
|
PreparePciVgaDevicePath (Handle);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
|
|
|
|
|
|
|
|
@param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
|
|
|
|
@retval EFI_STATUS - PCI Device check or Console variable update fail.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
DetectAndPreparePlatformPciDevicePaths (
|
|
|
|
BOOLEAN DetectVgaOnly
|
|
|
|
)
|
|
|
|
{
|
|
|
|
mDetectVgaOnly = DetectVgaOnly;
|
|
|
|
return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-20 11:36:14 +02:00
|
|
|
VOID
|
|
|
|
PlatformInitializeConsole (
|
|
|
|
IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
|
2015-08-03 07:26:01 +02:00
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Connect the predefined platform default console device. Always try to find
|
|
|
|
and enable the vga device if have.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
PlatformConsole - Predfined platform default console device array.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *VarConout;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *VarConin;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Connect RootBridge
|
|
|
|
//
|
2016-04-20 11:36:14 +02:00
|
|
|
GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout, NULL);
|
|
|
|
GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
|
|
|
|
if (VarConout == NULL || VarConin == NULL) {
|
|
|
|
//
|
|
|
|
// Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
|
|
|
|
//
|
|
|
|
DetectAndPreparePlatformPciDevicePaths (FALSE);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Have chance to connect the platform default console,
|
|
|
|
// the platform default console is the minimue device group
|
|
|
|
// the platform should support
|
|
|
|
//
|
|
|
|
for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
|
|
|
|
//
|
|
|
|
// Update the console variable with the connect type
|
|
|
|
//
|
|
|
|
if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ConIn, PlatformConsole[Index].DevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
}
|
|
|
|
if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ConOut, PlatformConsole[Index].DevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
}
|
|
|
|
if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
|
2016-04-20 11:19:14 +02:00
|
|
|
EfiBootManagerUpdateConsoleVariable (ErrOut, PlatformConsole[Index].DevicePath, NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// Only detect VGA device and add them to ConOut
|
|
|
|
//
|
|
|
|
DetectAndPreparePlatformPciDevicePaths (TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Configure PCI Interrupt Line register for applicable devices
|
|
|
|
Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
|
|
|
|
|
|
|
|
@param[in] Handle - Handle of PCI device instance
|
|
|
|
@param[in] PciIo - PCI IO protocol instance
|
|
|
|
@param[in] PciHdr - PCI Header register block
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SetPciIntLine (
|
|
|
|
IN EFI_HANDLE Handle,
|
|
|
|
IN EFI_PCI_IO_PROTOCOL *PciIo,
|
|
|
|
IN PCI_TYPE00 *PciHdr
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevPath;
|
|
|
|
UINTN RootSlot;
|
|
|
|
UINTN Idx;
|
|
|
|
UINT8 IrqLine;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 RootBusNumber;
|
|
|
|
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
|
|
|
|
if (PciHdr->Device.InterruptPin != 0) {
|
|
|
|
|
|
|
|
DevPathNode = DevicePathFromHandle (Handle);
|
|
|
|
ASSERT (DevPathNode != NULL);
|
|
|
|
DevPath = DevPathNode;
|
|
|
|
|
|
|
|
RootBusNumber = 0;
|
|
|
|
if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
|
|
|
|
DevicePathSubType (DevPathNode) == ACPI_DP &&
|
|
|
|
((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
|
|
|
|
RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Compute index into PciHostIrqs[] table by walking
|
|
|
|
// the device path and adding up all device numbers
|
|
|
|
//
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
RootSlot = 0;
|
|
|
|
Idx = PciHdr->Device.InterruptPin - 1;
|
|
|
|
while (!IsDevicePathEnd (DevPathNode)) {
|
|
|
|
if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
|
|
|
|
DevicePathSubType (DevPathNode) == HW_PCI_DP) {
|
|
|
|
|
|
|
|
Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Unlike SeaBIOS, which starts climbing from the leaf device
|
|
|
|
// up toward the root, we traverse the device path starting at
|
|
|
|
// the root moving toward the leaf node.
|
|
|
|
// The slot number of the top-level parent bridge is needed for
|
|
|
|
// Q35 cases with more than 24 slots on the root bus.
|
|
|
|
//
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DevPathNode = NextDevicePathNode (DevPathNode);
|
|
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
if (RootBusNumber == 0 && RootSlot == 0) {
|
|
|
|
DEBUG((
|
|
|
|
EFI_D_ERROR,
|
|
|
|
"%a: PCI host bridge (00:00.0) should have no interrupts!\n",
|
|
|
|
__FUNCTION__
|
|
|
|
));
|
|
|
|
ASSERT (FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Final PciHostIrqs[] index calculation depends on the platform
|
|
|
|
// and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
|
|
|
|
//
|
|
|
|
switch (mHostBridgeDevId) {
|
|
|
|
case INTEL_82441_DEVICE_ID:
|
|
|
|
Idx -= 1;
|
|
|
|
break;
|
|
|
|
case INTEL_Q35_MCH_DEVICE_ID:
|
|
|
|
//
|
|
|
|
// SeaBIOS contains the following comment:
|
|
|
|
// "Slots 0-24 rotate slot:pin mapping similar to piix above, but
|
|
|
|
// with a different starting index - see q35-acpi-dsdt.dsl.
|
|
|
|
//
|
|
|
|
// Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
|
|
|
|
//
|
|
|
|
if (RootSlot > 24) {
|
|
|
|
//
|
|
|
|
// in this case, subtract back out RootSlot from Idx
|
|
|
|
// (SeaBIOS never adds it to begin with, but that would make our
|
|
|
|
// device path traversal loop above too awkward)
|
|
|
|
//
|
|
|
|
Idx -= RootSlot;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ASSERT (FALSE); // should never get here
|
|
|
|
}
|
|
|
|
Idx %= ARRAY_SIZE (PciHostIrqs);
|
|
|
|
IrqLine = PciHostIrqs[Idx];
|
|
|
|
|
|
|
|
DEBUG_CODE_BEGIN ();
|
|
|
|
{
|
|
|
|
CHAR16 *DevPathString;
|
|
|
|
STATIC CHAR16 Fallback[] = L"<failed to convert>";
|
|
|
|
UINTN Segment, Bus, Device, Function;
|
|
|
|
|
|
|
|
DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
|
|
|
|
if (DevPathString == NULL) {
|
|
|
|
DevPathString = Fallback;
|
|
|
|
}
|
|
|
|
Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
|
|
|
|
(UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
|
|
|
|
IrqLine));
|
|
|
|
|
|
|
|
if (DevPathString != Fallback) {
|
|
|
|
FreePool (DevPathString);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DEBUG_CODE_END ();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
|
|
|
|
//
|
|
|
|
Status = PciIo->Pci.Write (
|
|
|
|
PciIo,
|
|
|
|
EfiPciIoWidthUint8,
|
|
|
|
PCI_INT_LINE_OFFSET,
|
|
|
|
1,
|
|
|
|
&IrqLine
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
PciAcpiInitialization (
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Pmba;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Query Host Bridge DID to determine platform type
|
|
|
|
//
|
|
|
|
mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
|
|
|
|
switch (mHostBridgeDevId) {
|
|
|
|
case INTEL_82441_DEVICE_ID:
|
|
|
|
Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
|
|
|
|
//
|
|
|
|
// 00:01.0 ISA Bridge (PIIX4) LNK routing targets
|
|
|
|
//
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
|
|
|
|
break;
|
|
|
|
case INTEL_Q35_MCH_DEVICE_ID:
|
|
|
|
Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
|
|
|
|
//
|
|
|
|
// 00:1f.0 LPC Bridge (Q35) LNK routing targets
|
|
|
|
//
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
|
|
|
|
__FUNCTION__, mHostBridgeDevId));
|
|
|
|
ASSERT (FALSE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
|
|
|
|
//
|
|
|
|
VisitAllPciInstances (SetPciIntLine);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set ACPI SCI_EN bit in PMCNTRL
|
|
|
|
//
|
|
|
|
IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
ConnectRecursivelyIfPciMassStorage (
|
|
|
|
IN EFI_HANDLE Handle,
|
|
|
|
IN EFI_PCI_IO_PROTOCOL *Instance,
|
|
|
|
IN PCI_TYPE00 *PciHeader
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
CHAR16 *DevPathStr;
|
|
|
|
|
|
|
|
if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
|
|
|
|
DevicePath = NULL;
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
(VOID*)&DevicePath
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Print Device Path
|
|
|
|
//
|
2016-04-20 11:24:38 +02:00
|
|
|
DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
|
2015-08-03 07:26:01 +02:00
|
|
|
if (DevPathStr != NULL) {
|
|
|
|
DEBUG((
|
|
|
|
EFI_D_INFO,
|
|
|
|
"Found Mass Storage device: %s\n",
|
|
|
|
DevPathStr
|
|
|
|
));
|
|
|
|
FreePool(DevPathStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
This notification function is invoked when the
|
|
|
|
EMU Variable FVB has been changed.
|
|
|
|
|
|
|
|
@param Event The event that occured
|
|
|
|
@param Context For EFI compatiblity. Not used.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
EmuVariablesUpdatedCallback (
|
|
|
|
IN EFI_EVENT Event,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
|
|
|
|
UpdateNvVarsOnFileSystem ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
VisitingFileSystemInstance (
|
|
|
|
IN EFI_HANDLE Handle,
|
|
|
|
IN VOID *Instance,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
STATIC BOOLEAN ConnectedToFileSystem = FALSE;
|
|
|
|
|
|
|
|
if (ConnectedToFileSystem) {
|
|
|
|
return EFI_ALREADY_STARTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = ConnectNvVarsToFileSystem (Handle);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConnectedToFileSystem = TRUE;
|
|
|
|
mEmuVariableEvent =
|
|
|
|
EfiCreateProtocolNotifyEvent (
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
TPL_CALLBACK,
|
|
|
|
EmuVariablesUpdatedCallback,
|
|
|
|
NULL,
|
|
|
|
&mEmuVariableEventReg
|
|
|
|
);
|
|
|
|
PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent);
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
PlatformBdsRestoreNvVarsFromHardDisk (
|
|
|
|
)
|
|
|
|
{
|
|
|
|
VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
|
|
|
|
VisitAllInstancesOfProtocol (
|
|
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
|
|
VisitingFileSystemInstance,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
PlatformBdsConnectSequence (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Connect with predeined platform connect sequence,
|
|
|
|
the OEM/IBV can customize with their own connect sequence.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
|
|
|
|
|
|
|
|
Index = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Here we can get the customized platform connect sequence
|
|
|
|
// Notes: we can connect with new variable which record the
|
|
|
|
// last time boots connect device path sequence
|
|
|
|
//
|
|
|
|
while (gPlatformConnectSequence[Index] != NULL) {
|
|
|
|
//
|
|
|
|
// Build the platform boot option
|
|
|
|
//
|
2016-04-20 12:05:26 +02:00
|
|
|
EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
|
2015-08-03 07:26:01 +02:00
|
|
|
Index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Just use the simple policy to connect all devices
|
|
|
|
//
|
2016-04-20 12:05:26 +02:00
|
|
|
DEBUG ((EFI_D_INFO, "EfiBootManagerConnectAll\n"));
|
|
|
|
EfiBootManagerConnectAll ();
|
2015-08-03 07:26:01 +02:00
|
|
|
|
|
|
|
PciAcpiInitialization ();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Clear the logo after all devices are connected.
|
|
|
|
//
|
|
|
|
gST->ConOut->ClearScreen (gST->ConOut);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
PlatformBdsGetDriverOption (
|
|
|
|
IN OUT LIST_ENTRY *BdsDriverLists
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Load the predefined driver option, OEM/IBV can customize this
|
|
|
|
to load their own drivers
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
BdsDriverLists - The header of the driver option link list.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DEBUG ((EFI_D_INFO, "PlatformBdsGetDriverOption\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
PlatformBdsDiagnostics (
|
|
|
|
IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,
|
|
|
|
IN BOOLEAN QuietBoot,
|
|
|
|
IN BASEM_MEMORY_TEST BaseMemoryTest
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Perform the platform diagnostic, such like test memory. OEM/IBV also
|
|
|
|
can customize this fuction to support specific platform diagnostic.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
MemoryTestLevel - The memory test intensive level
|
|
|
|
|
|
|
|
QuietBoot - Indicate if need to enable the quiet boot
|
|
|
|
|
|
|
|
BaseMemoryTest - A pointer to BaseMemoryTest()
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
None.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
DEBUG ((EFI_D_INFO, "PlatformBdsDiagnostics\n"));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Here we can decide if we need to show
|
|
|
|
// the diagnostics screen
|
|
|
|
// Notes: this quiet boot code should be remove
|
|
|
|
// from the graphic lib
|
|
|
|
//
|
|
|
|
if (QuietBoot) {
|
|
|
|
EnableQuietBoot (PcdGetPtr(PcdLogoFile));
|
|
|
|
//
|
|
|
|
// Perform system diagnostic
|
|
|
|
//
|
|
|
|
Status = BaseMemoryTest (MemoryTestLevel);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DisableQuietBoot ();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Perform system diagnostic
|
|
|
|
//
|
|
|
|
Status = BaseMemoryTest (MemoryTestLevel);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Save the S3 boot script.
|
|
|
|
|
|
|
|
Note that DxeSmmReadyToLock must be signaled after this function returns;
|
|
|
|
otherwise the script wouldn't be saved actually.
|
|
|
|
**/
|
|
|
|
STATIC
|
|
|
|
VOID
|
|
|
|
SaveS3BootScript (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
|
|
|
|
STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
|
|
|
|
|
|
|
Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
|
|
|
|
(VOID **) &BootScript);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Despite the opcode documentation in the PI spec, the protocol
|
|
|
|
// implementation embeds a deep copy of the info in the boot script, rather
|
|
|
|
// than storing just a pointer to runtime or NVS storage.
|
|
|
|
//
|
|
|
|
Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
|
|
|
|
(UINT32) sizeof Info,
|
|
|
|
(EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
2016-04-20 09:46:46 +02:00
|
|
|
PlatformBootManagerAfterConsole (
|
|
|
|
VOID
|
2015-08-03 07:26:01 +02:00
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
The function will excute with as the platform policy, current policy
|
|
|
|
is driven by boot mode. IBV/OEM can customize this code for their specific
|
|
|
|
policy action.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_BOOT_MODE BootMode;
|
|
|
|
|
2016-04-20 09:46:46 +02:00
|
|
|
DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));
|
2015-08-03 07:26:01 +02:00
|
|
|
|
|
|
|
if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
|
|
|
|
DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
|
|
|
|
"from disk since flash variables appear to be supported.\n"));
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// Try to restore variables from the hard disk early so
|
|
|
|
// they can be used for the other BDS connect operations.
|
|
|
|
//
|
|
|
|
PlatformBdsRestoreNvVarsFromHardDisk ();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Load the driver option as the driver option list
|
|
|
|
//
|
|
|
|
PlatformBdsGetDriverOption (DriverOptionList);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get current Boot Mode
|
|
|
|
//
|
|
|
|
Status = BdsLibGetBootMode (&BootMode);
|
|
|
|
DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Go the different platform policy with different boot mode
|
|
|
|
// Notes: this part code can be change with the table policy
|
|
|
|
//
|
|
|
|
ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Memory test and Logo show
|
|
|
|
//
|
|
|
|
PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Perform some platform specific connect sequence
|
|
|
|
//
|
|
|
|
PlatformBdsConnectSequence ();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Process QEMU's -kernel command line option
|
|
|
|
//
|
|
|
|
TryRunningQemuKernel ();
|
|
|
|
BdsLibEnumerateAllBootOption (BootOptionList);
|
|
|
|
|
|
|
|
SetBootOrderFromQemu (BootOptionList);
|
|
|
|
//
|
|
|
|
// The BootOrder variable may have changed, reload the in-memory list with
|
|
|
|
// it.
|
|
|
|
//
|
|
|
|
BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
This notification function is invoked when an instance of the
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL is produced.
|
|
|
|
|
|
|
|
@param Event The event that occured
|
|
|
|
@param Context For EFI compatiblity. Not used.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
NotifyDevPath (
|
|
|
|
IN EFI_EVENT Event,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_HANDLE Handle;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN BufferSize;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
|
|
|
|
ATAPI_DEVICE_PATH *Atapi;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Examine all new handles
|
|
|
|
//
|
|
|
|
for (;;) {
|
|
|
|
//
|
|
|
|
// Get the next handle
|
|
|
|
//
|
|
|
|
BufferSize = sizeof (Handle);
|
|
|
|
Status = gBS->LocateHandle (
|
|
|
|
ByRegisterNotify,
|
|
|
|
NULL,
|
|
|
|
mEfiDevPathNotifyReg,
|
|
|
|
&BufferSize,
|
|
|
|
&Handle
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// If not found, we're done
|
|
|
|
//
|
|
|
|
if (EFI_NOT_FOUND == Status) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get the DevicePath protocol on that handle
|
|
|
|
//
|
|
|
|
Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
while (!IsDevicePathEnd (DevPathNode)) {
|
|
|
|
//
|
|
|
|
// Find the handler to dump this device path node
|
|
|
|
//
|
|
|
|
if (
|
|
|
|
(DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
|
|
|
|
(DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
|
|
|
|
) {
|
|
|
|
Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
|
|
|
|
PciOr16 (
|
|
|
|
PCI_LIB_ADDRESS (
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
1,
|
|
|
|
(Atapi->PrimarySecondary == 1) ? 0x42: 0x40
|
|
|
|
),
|
|
|
|
BIT15
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Next device path node
|
|
|
|
//
|
|
|
|
DevPathNode = NextDevicePathNode (DevPathNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
InstallDevicePathCallback (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
|
|
|
|
mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
TPL_CALLBACK,
|
|
|
|
NotifyDevPath,
|
|
|
|
NULL,
|
|
|
|
&mEfiDevPathNotifyReg
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-04-20 09:46:46 +02:00
|
|
|
/**
|
|
|
|
This function is called each second during the boot manager waits the timeout.
|
|
|
|
|
|
|
|
@param TimeoutRemain The remaining timeout.
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
PlatformBootManagerWaitCallback (
|
|
|
|
UINT16 TimeoutRemain
|
|
|
|
)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|