Currently, the ArmVirtPkg platforms built with the Intel BDS fail to signal the end-of-DXE event 'gEfiEndOfDxeEventGroupGuid' when entering the BDS phase, which results in some loss of functionality, i.e., variable reclaim in the VariableDxe drivers, and the splitting of the memory regions that is part of the recently added UEFI 2.5 properties table feature. As discussed on the edk2-devel mailing list here: http://thread.gmane.org/gmane.comp.bios.tianocore.devel/16088/focus=16109 it is up to the platform BDS to signal that event, since there may be platform specific ordering constraints with respect to the signalling of the event that are difficult to honor at the generic level. So add the SignalEvent () call to PlatformBdsInit () of ArmVirtPkg's PlatformBdsLib implementation for the Intel BDS. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Laszlo Ersek <lersek@redhat.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17713 6f19259b-4bc3-4df7-8a09-765794883524
514 lines
14 KiB
C
514 lines
14 KiB
C
/** @file
|
|
Implementation for PlatformBdsLib library class interfaces.
|
|
|
|
Copyright (C) 2015, Red Hat, Inc.
|
|
Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
|
|
Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
|
|
|
|
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 <IndustryStandard/Pci22.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/PlatformBdsLib.h>
|
|
#include <Library/QemuBootOrderLib.h>
|
|
#include <Protocol/DevicePath.h>
|
|
#include <Protocol/GraphicsOutput.h>
|
|
#include <Protocol/PciIo.h>
|
|
#include <Protocol/PciRootBridgeIo.h>
|
|
#include <Guid/EventGroup.h>
|
|
|
|
#include "IntelBdsPlatform.h"
|
|
|
|
#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
|
|
|
|
|
|
#pragma pack (1)
|
|
typedef struct {
|
|
VENDOR_DEVICE_PATH SerialDxe;
|
|
UART_DEVICE_PATH Uart;
|
|
VENDOR_DEFINED_DEVICE_PATH Vt100;
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
} PLATFORM_SERIAL_CONSOLE;
|
|
#pragma pack ()
|
|
|
|
#define SERIAL_DXE_FILE_GUID { \
|
|
0xD3987D4B, 0x971A, 0x435F, \
|
|
{ 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
|
|
}
|
|
|
|
STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
|
|
//
|
|
// VENDOR_DEVICE_PATH SerialDxe
|
|
//
|
|
{
|
|
{ HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
|
|
SERIAL_DXE_FILE_GUID
|
|
},
|
|
|
|
//
|
|
// UART_DEVICE_PATH Uart
|
|
//
|
|
{
|
|
{ MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
|
|
0, // Reserved
|
|
FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
|
|
FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
|
|
FixedPcdGet8 (PcdUartDefaultParity), // Parity
|
|
FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
|
|
},
|
|
|
|
//
|
|
// VENDOR_DEFINED_DEVICE_PATH Vt100
|
|
//
|
|
{
|
|
{
|
|
MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
|
|
DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
|
|
},
|
|
EFI_VT_100_GUID
|
|
},
|
|
|
|
//
|
|
// EFI_DEVICE_PATH_PROTOCOL End
|
|
//
|
|
{
|
|
END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
|
|
}
|
|
};
|
|
|
|
|
|
#pragma pack (1)
|
|
typedef struct {
|
|
USB_CLASS_DEVICE_PATH Keyboard;
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
} PLATFORM_USB_KEYBOARD;
|
|
#pragma pack ()
|
|
|
|
STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
|
|
//
|
|
// USB_CLASS_DEVICE_PATH Keyboard
|
|
//
|
|
{
|
|
{
|
|
MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
|
|
DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
|
|
},
|
|
0xFFFF, // VendorId: any
|
|
0xFFFF, // ProductId: any
|
|
3, // DeviceClass: HID
|
|
1, // DeviceSubClass: boot
|
|
1 // DeviceProtocol: keyboard
|
|
},
|
|
|
|
//
|
|
// EFI_DEVICE_PATH_PROTOCOL End
|
|
//
|
|
{
|
|
END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
|
|
}
|
|
};
|
|
|
|
/**
|
|
An empty function to pass error checking of CreateEventEx ().
|
|
|
|
@param Event Event whose notification function is being invoked.
|
|
@param Context Pointer to the notification function's context,
|
|
which is implementation-dependent.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
EmptyCallbackFunction (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
}
|
|
|
|
//
|
|
// BDS Platform Functions
|
|
//
|
|
/**
|
|
Platform Bds init. Include the platform firmware vendor, revision
|
|
and so crc check.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PlatformBdsInit (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_EVENT EndOfDxeEvent;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Signal EndOfDxe PI Event
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
EmptyCallbackFunction,
|
|
NULL,
|
|
&gEfiEndOfDxeEventGroupGuid,
|
|
&EndOfDxeEvent
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
gBS->SignalEvent (EndOfDxeEvent);
|
|
gBS->CloseEvent (EndOfDxeEvent);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Check if the handle satisfies a particular condition.
|
|
|
|
@param[in] Handle The handle to check.
|
|
@param[in] ReportText A caller-allocated string passed in for reporting
|
|
purposes. It must never be NULL.
|
|
|
|
@retval TRUE The condition is satisfied.
|
|
@retval FALSE Otherwise. This includes the case when the condition could not
|
|
be fully evaluated due to an error.
|
|
**/
|
|
typedef
|
|
BOOLEAN
|
|
(EFIAPI *FILTER_FUNCTION) (
|
|
IN EFI_HANDLE Handle,
|
|
IN CONST CHAR16 *ReportText
|
|
);
|
|
|
|
|
|
/**
|
|
Process a handle.
|
|
|
|
@param[in] Handle The handle to process.
|
|
@param[in] ReportText A caller-allocated string passed in for reporting
|
|
purposes. It must never be NULL.
|
|
**/
|
|
typedef
|
|
VOID
|
|
(EFIAPI *CALLBACK_FUNCTION) (
|
|
IN EFI_HANDLE Handle,
|
|
IN CONST CHAR16 *ReportText
|
|
);
|
|
|
|
/**
|
|
Locate all handles that carry the specified protocol, filter them with a
|
|
callback function, and pass each handle that passes the filter to another
|
|
callback.
|
|
|
|
@param[in] ProtocolGuid The protocol to look for.
|
|
|
|
@param[in] Filter The filter function to pass each handle to. If this
|
|
parameter is NULL, then all handles are processed.
|
|
|
|
@param[in] Process The callback function to pass each handle to that
|
|
clears the filter.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
FilterAndProcess (
|
|
IN EFI_GUID *ProtocolGuid,
|
|
IN FILTER_FUNCTION Filter OPTIONAL,
|
|
IN CALLBACK_FUNCTION Process
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *Handles;
|
|
UINTN NoHandles;
|
|
UINTN Idx;
|
|
|
|
Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,
|
|
NULL /* SearchKey */, &NoHandles, &Handles);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// This is not an error, just an informative condition.
|
|
//
|
|
DEBUG ((EFI_D_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,
|
|
Status));
|
|
return;
|
|
}
|
|
|
|
ASSERT (NoHandles > 0);
|
|
for (Idx = 0; Idx < NoHandles; ++Idx) {
|
|
CHAR16 *DevicePathText;
|
|
STATIC CHAR16 Fallback[] = L"<device path unavailable>";
|
|
|
|
//
|
|
// The ConvertDevicePathToText() function handles NULL input transparently.
|
|
//
|
|
DevicePathText = ConvertDevicePathToText (
|
|
DevicePathFromHandle (Handles[Idx]),
|
|
FALSE, // DisplayOnly
|
|
FALSE // AllowShortcuts
|
|
);
|
|
if (DevicePathText == NULL) {
|
|
DevicePathText = Fallback;
|
|
}
|
|
|
|
if (Filter == NULL || Filter (Handles[Idx], DevicePathText)) {
|
|
Process (Handles[Idx], DevicePathText);
|
|
}
|
|
|
|
if (DevicePathText != Fallback) {
|
|
FreePool (DevicePathText);
|
|
}
|
|
}
|
|
gBS->FreePool (Handles);
|
|
}
|
|
|
|
|
|
/**
|
|
This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
EFIAPI
|
|
IsPciDisplay (
|
|
IN EFI_HANDLE Handle,
|
|
IN CONST CHAR16 *ReportText
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
PCI_TYPE00 Pci;
|
|
|
|
Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
|
|
(VOID**)&PciIo);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// This is not an error worth reporting.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,
|
|
sizeof Pci / sizeof (UINT32), &Pci);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
|
|
return FALSE;
|
|
}
|
|
|
|
return IS_PCI_DISPLAY (&Pci);
|
|
}
|
|
|
|
|
|
/**
|
|
This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
|
|
the matching driver to produce all first-level child handles.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
Connect (
|
|
IN EFI_HANDLE Handle,
|
|
IN CONST CHAR16 *ReportText
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->ConnectController (
|
|
Handle, // ControllerHandle
|
|
NULL, // DriverImageHandle
|
|
NULL, // RemainingDevicePath -- produce all children
|
|
FALSE // Recursive
|
|
);
|
|
DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, "%a: %s: %r\n",
|
|
__FUNCTION__, ReportText, Status));
|
|
}
|
|
|
|
|
|
/**
|
|
This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
|
|
handle, and adds it to ConOut and ErrOut.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
AddOutput (
|
|
IN EFI_HANDLE Handle,
|
|
IN CONST CHAR16 *ReportText
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
DevicePath = DevicePathFromHandle (Handle);
|
|
if (DevicePath == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "%a: %s: handle %p: device path not found\n",
|
|
__FUNCTION__, ReportText, Handle));
|
|
return;
|
|
}
|
|
|
|
Status = BdsLibUpdateConsoleVariable (L"ConOut", DevicePath, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
|
|
ReportText, Status));
|
|
return;
|
|
}
|
|
|
|
Status = BdsLibUpdateConsoleVariable (L"ErrOut", DevicePath, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
|
|
ReportText, Status));
|
|
return;
|
|
}
|
|
|
|
DEBUG ((EFI_D_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
|
|
ReportText));
|
|
}
|
|
|
|
|
|
/**
|
|
The function will execute with as the platform policy, current policy
|
|
is driven by boot mode. IBV/OEM can customize this code for their specific
|
|
policy action.
|
|
|
|
@param DriverOptionList The header of the driver option link list
|
|
@param BootOptionList The header of the boot option link list
|
|
@param ProcessCapsules A pointer to ProcessCapsules()
|
|
@param BaseMemoryTest A pointer to BaseMemoryTest()
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PlatformBdsPolicyBehavior (
|
|
IN LIST_ENTRY *DriverOptionList,
|
|
IN LIST_ENTRY *BootOptionList,
|
|
IN PROCESS_CAPSULES ProcessCapsules,
|
|
IN BASEM_MEMORY_TEST BaseMemoryTest
|
|
)
|
|
{
|
|
//
|
|
// Locate the PCI root bridges and make the PCI bus driver connect each,
|
|
// non-recursively. This will produce a number of child handles with PciIo on
|
|
// them.
|
|
//
|
|
FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
|
|
|
|
//
|
|
// Find all display class PCI devices (using the handles from the previous
|
|
// step), and connect them non-recursively. This should produce a number of
|
|
// child handles with GOPs on them.
|
|
//
|
|
FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
|
|
|
|
//
|
|
// Now add the device path of all handles with GOP on them to ConOut and
|
|
// ErrOut.
|
|
//
|
|
FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
|
|
|
|
//
|
|
// Add the hardcoded short-form USB keyboard device path to ConIn.
|
|
//
|
|
BdsLibUpdateConsoleVariable (L"ConIn",
|
|
(EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
|
|
|
|
//
|
|
// Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
|
|
//
|
|
BdsLibUpdateConsoleVariable (L"ConIn",
|
|
(EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
|
|
BdsLibUpdateConsoleVariable (L"ConOut",
|
|
(EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
|
|
BdsLibUpdateConsoleVariable (L"ErrOut",
|
|
(EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
|
|
|
|
//
|
|
// Connect the consoles based on the above variables.
|
|
//
|
|
BdsLibConnectAllDefaultConsoles ();
|
|
|
|
//
|
|
// Show the splash screen.
|
|
//
|
|
EnableQuietBoot (PcdGetPtr (PcdLogoFile));
|
|
|
|
//
|
|
// Connect the rest of the devices.
|
|
//
|
|
BdsLibConnectAll ();
|
|
|
|
//
|
|
// Process QEMU's -kernel command line option. Note that the kernel booted
|
|
// this way should receive ACPI tables, which is why we connect all devices
|
|
// first (see above) -- PCI enumeration blocks ACPI table installation, if
|
|
// there is a PCI host.
|
|
//
|
|
TryRunningQemuKernel ();
|
|
|
|
BdsLibEnumerateAllBootOption (BootOptionList);
|
|
SetBootOrderFromQemu (BootOptionList);
|
|
//
|
|
// The BootOrder variable may have changed, reload the in-memory list with
|
|
// it.
|
|
//
|
|
BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");
|
|
|
|
PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE);
|
|
}
|
|
|
|
/**
|
|
Hook point after a boot attempt succeeds. We don't expect a boot option to
|
|
return, so the UEFI 2.0 specification defines that you will default to an
|
|
interactive mode and stop processing the BootOrder list in this case. This
|
|
is also a platform implementation and can be customized by IBV/OEM.
|
|
|
|
@param Option Pointer to Boot Option that succeeded to boot.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PlatformBdsBootSuccess (
|
|
IN BDS_COMMON_OPTION *Option
|
|
)
|
|
{
|
|
}
|
|
|
|
/**
|
|
Hook point after a boot attempt fails.
|
|
|
|
@param Option Pointer to Boot Option that failed to boot.
|
|
@param Status Status returned from failed boot.
|
|
@param ExitData Exit data returned from failed boot.
|
|
@param ExitDataSize Exit data size returned from failed boot.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PlatformBdsBootFail (
|
|
IN BDS_COMMON_OPTION *Option,
|
|
IN EFI_STATUS Status,
|
|
IN CHAR16 *ExitData,
|
|
IN UINTN ExitDataSize
|
|
)
|
|
{
|
|
}
|
|
|
|
/**
|
|
This function locks platform flash that is not allowed to be updated during normal boot path.
|
|
The flash layout is platform specific.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PlatformBdsLockNonUpdatableFlash (
|
|
VOID
|
|
)
|
|
{
|
|
return;
|
|
}
|