mirror of https://github.com/acidanthera/audk.git
354 lines
8.5 KiB
C
354 lines
8.5 KiB
C
/** @file
|
|
*
|
|
* Copyright (c) 2017, Linaro, Ltd. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
*
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
#include <IndustryStandard/Acpi.h>
|
|
#include <libfdt.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/HiiLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiDriverEntryPoint.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
|
|
#include <Protocol/AcpiTable.h>
|
|
#include <Protocol/AcpiSystemDescriptionTable.h>
|
|
|
|
#include "ConsolePrefDxe.h"
|
|
|
|
#define SPCR_SIG EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE
|
|
|
|
extern UINT8 ConsolePrefHiiBin[];
|
|
extern UINT8 ConsolePrefDxeStrings[];
|
|
|
|
typedef struct {
|
|
VENDOR_DEVICE_PATH VendorDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
} HII_VENDOR_DEVICE_PATH;
|
|
|
|
STATIC HII_VENDOR_DEVICE_PATH mConsolePrefDxeVendorDevicePath = {
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
{
|
|
(UINT8)(sizeof (VENDOR_DEVICE_PATH)),
|
|
(UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
|
|
}
|
|
},
|
|
CONSOLE_PREF_FORMSET_GUID
|
|
},
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
{
|
|
(UINT8)(END_DEVICE_PATH_LENGTH),
|
|
(UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
|
|
}
|
|
}
|
|
};
|
|
|
|
STATIC EFI_EVENT mReadyToBootEvent;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InstallHiiPages (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HII_HANDLE HiiHandle;
|
|
EFI_HANDLE DriverHandle;
|
|
|
|
DriverHandle = NULL;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mConsolePrefDxeVendorDevicePath,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
HiiHandle = HiiAddPackages (
|
|
&gConsolePrefFormSetGuid,
|
|
DriverHandle,
|
|
ConsolePrefDxeStrings,
|
|
ConsolePrefHiiBin,
|
|
NULL
|
|
);
|
|
|
|
if (HiiHandle == NULL) {
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mConsolePrefDxeVendorDevicePath,
|
|
NULL
|
|
);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
RemoveDtStdoutPath (
|
|
VOID
|
|
)
|
|
{
|
|
VOID *Dtb;
|
|
INT32 Node;
|
|
INT32 Error;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: could not retrieve DT blob - %r\n",
|
|
__FUNCTION__,
|
|
Status
|
|
));
|
|
return;
|
|
}
|
|
|
|
Node = fdt_path_offset (Dtb, "/chosen");
|
|
if (Node < 0) {
|
|
return;
|
|
}
|
|
|
|
Error = fdt_delprop (Dtb, Node, "stdout-path");
|
|
if (Error) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: Failed to delete 'stdout-path' property: %a\n",
|
|
__FUNCTION__,
|
|
fdt_strerror (Error)
|
|
));
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
RemoveSpcrTable (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_ACPI_SDT_PROTOCOL *Sdt;
|
|
EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
|
|
EFI_STATUS Status;
|
|
UINTN TableIndex;
|
|
EFI_ACPI_SDT_HEADER *TableHeader;
|
|
EFI_ACPI_TABLE_VERSION TableVersion;
|
|
UINTN TableKey;
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiAcpiTableProtocolGuid,
|
|
NULL,
|
|
(VOID **)&AcpiTable
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&Sdt);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
TableIndex = 0;
|
|
TableKey = 0;
|
|
TableHeader = NULL;
|
|
|
|
do {
|
|
Status = Sdt->GetAcpiTable (
|
|
TableIndex++,
|
|
&TableHeader,
|
|
&TableVersion,
|
|
&TableKey
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
if (TableHeader->Signature != SPCR_SIG) {
|
|
continue;
|
|
}
|
|
|
|
Status = AcpiTable->UninstallAcpiTable (AcpiTable, TableKey);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_WARN,
|
|
"%a: failed to uninstall SPCR table - %r\n",
|
|
__FUNCTION__,
|
|
Status
|
|
));
|
|
}
|
|
|
|
break;
|
|
} while (TRUE);
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
OnReadyToBoot (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
CONSOLE_PREF_VARSTORE_DATA ConsolePref;
|
|
UINTN BufferSize;
|
|
EFI_STATUS Status;
|
|
VOID *Gop;
|
|
|
|
BufferSize = sizeof (ConsolePref);
|
|
Status = gRT->GetVariable (
|
|
CONSOLE_PREF_VARIABLE_NAME,
|
|
&gConsolePrefFormSetGuid,
|
|
NULL,
|
|
&BufferSize,
|
|
&ConsolePref
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: variable '%s' could not be read - bailing!\n",
|
|
__FUNCTION__,
|
|
CONSOLE_PREF_VARIABLE_NAME
|
|
));
|
|
return;
|
|
}
|
|
|
|
if (ConsolePref.Console == CONSOLE_PREF_SERIAL) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: serial console preferred - doing nothing\n",
|
|
__FUNCTION__
|
|
));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check if any GOP instances exist: if so, disable stdout-path and SPCR
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: no GOP instances found - doing nothing (%r)\n",
|
|
__FUNCTION__,
|
|
Status
|
|
));
|
|
return;
|
|
}
|
|
|
|
RemoveDtStdoutPath ();
|
|
RemoveSpcrTable ();
|
|
}
|
|
|
|
/**
|
|
The entry point for ConsolePrefDxe driver.
|
|
|
|
@param[in] ImageHandle The image handle of the driver.
|
|
@param[in] SystemTable The system table.
|
|
|
|
@retval EFI_ALREADY_STARTED The driver already exists in system.
|
|
@retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of
|
|
resources.
|
|
@retval EFI_SUCCESS All the related protocols are installed on
|
|
the driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ConsolePrefDxeEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CONSOLE_PREF_VARSTORE_DATA ConsolePref;
|
|
UINTN BufferSize;
|
|
|
|
//
|
|
// Get the current console preference from the ConsolePref variable.
|
|
//
|
|
BufferSize = sizeof (ConsolePref);
|
|
Status = gRT->GetVariable (
|
|
CONSOLE_PREF_VARIABLE_NAME,
|
|
&gConsolePrefFormSetGuid,
|
|
NULL,
|
|
&BufferSize,
|
|
&ConsolePref
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: no console preference found, defaulting to graphical\n",
|
|
__FUNCTION__
|
|
));
|
|
ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
|
|
}
|
|
|
|
if (!EFI_ERROR (Status) &&
|
|
(ConsolePref.Console != CONSOLE_PREF_GRAPHICAL) &&
|
|
(ConsolePref.Console != CONSOLE_PREF_SERIAL))
|
|
{
|
|
DEBUG ((
|
|
DEBUG_WARN,
|
|
"%a: invalid value for %s, defaulting to graphical\n",
|
|
__FUNCTION__,
|
|
CONSOLE_PREF_VARIABLE_NAME
|
|
));
|
|
ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
|
|
Status = EFI_INVALID_PARAMETER; // trigger setvar below
|
|
}
|
|
|
|
//
|
|
// Write the newly selected value back to the variable store.
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
ZeroMem (&ConsolePref.Reserved, sizeof (ConsolePref.Reserved));
|
|
Status = gRT->SetVariable (
|
|
CONSOLE_PREF_VARIABLE_NAME,
|
|
&gConsolePrefFormSetGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (ConsolePref),
|
|
&ConsolePref
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: gRT->SetVariable () failed - %r\n",
|
|
__FUNCTION__,
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
OnReadyToBoot,
|
|
NULL,
|
|
&gEfiEventReadyToBootGuid,
|
|
&mReadyToBootEvent
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return InstallHiiPages ();
|
|
}
|