blob: b94cd4da25d1c3308404c31bd5827a04162e6145 [file] [log] [blame]
/** @file
*
* Copyright (c) 2017, Linaro, Ltd. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
#include <Library/DtPlatformDtbLoaderLib.h>
#include <Library/HiiLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include "DtPlatformDxe.h"
extern UINT8 DtPlatformHiiBin[];
extern UINT8 DtPlatformDxeStrings[];
typedef struct {
VENDOR_DEVICE_PATH VendorDevicePath;
EFI_DEVICE_PATH_PROTOCOL End;
} HII_VENDOR_DEVICE_PATH;
STATIC HII_VENDOR_DEVICE_PATH mDtPlatformDxeVendorDevicePath = {
{
{
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
{
(UINT8)(sizeof (VENDOR_DEVICE_PATH)),
(UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
}
},
DT_PLATFORM_FORMSET_GUID
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
(UINT8)(END_DEVICE_PATH_LENGTH),
(UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
}
}
};
STATIC
EFI_STATUS
InstallHiiPages (
VOID
)
{
EFI_STATUS Status;
EFI_HII_HANDLE HiiHandle;
EFI_HANDLE DriverHandle;
DriverHandle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverHandle,
&gEfiDevicePathProtocolGuid,
&mDtPlatformDxeVendorDevicePath,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
HiiHandle = HiiAddPackages (
&gDtPlatformFormSetGuid,
DriverHandle,
DtPlatformDxeStrings,
DtPlatformHiiBin,
NULL
);
if (HiiHandle == NULL) {
gBS->UninstallMultipleProtocolInterfaces (
DriverHandle,
&gEfiDevicePathProtocolGuid,
&mDtPlatformDxeVendorDevicePath,
NULL
);
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
/**
The entry point for DtPlatformDxe 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
DtPlatformDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
DT_ACPI_VARSTORE_DATA DtAcpiPref;
UINTN BufferSize;
VOID *Dtb;
UINTN DtbSize;
Dtb = NULL;
Status = DtPlatformLoadDtb (&Dtb, &DtbSize);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_WARN,
"%a: no DTB blob could be loaded, defaulting to ACPI (Status == %r)\n",
__func__,
Status
));
DtAcpiPref.Pref = DT_ACPI_SELECT_ACPI;
} else {
//
// Get the current DT/ACPI preference from the DtAcpiPref variable.
//
BufferSize = sizeof (DtAcpiPref);
Status = gRT->GetVariable (
DT_ACPI_VARIABLE_NAME,
&gDtPlatformFormSetGuid,
NULL,
&BufferSize,
&DtAcpiPref
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_WARN,
"%a: no DT/ACPI preference found, defaulting to %a\n",
__func__,
PcdGetBool (PcdDefaultDtPref) ? "DT" : "ACPI"
));
DtAcpiPref.Pref = PcdGetBool (PcdDefaultDtPref) ? DT_ACPI_SELECT_DT
: DT_ACPI_SELECT_ACPI;
}
}
if (!EFI_ERROR (Status) &&
(DtAcpiPref.Pref != DT_ACPI_SELECT_ACPI) &&
(DtAcpiPref.Pref != DT_ACPI_SELECT_DT))
{
DEBUG ((
DEBUG_WARN,
"%a: invalid value for %s, defaulting to %a\n",
__func__,
DT_ACPI_VARIABLE_NAME,
PcdGetBool (PcdDefaultDtPref) ? "DT" : "ACPI"
));
DtAcpiPref.Pref = PcdGetBool (PcdDefaultDtPref) ? DT_ACPI_SELECT_DT
: DT_ACPI_SELECT_ACPI;
Status = EFI_INVALID_PARAMETER; // trigger setvar below
}
//
// Write the newly selected default value back to the variable store.
//
if (EFI_ERROR (Status)) {
Status = gRT->SetVariable (
DT_ACPI_VARIABLE_NAME,
&gDtPlatformFormSetGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
sizeof (DtAcpiPref),
&DtAcpiPref
);
if (EFI_ERROR (Status)) {
goto FreeDtb;
}
}
if (DtAcpiPref.Pref == DT_ACPI_SELECT_ACPI) {
//
// ACPI was selected: install the gEdkiiPlatformHasAcpiGuid GUID as a
// NULL protocol to unlock dispatch of ACPI related drivers.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEdkiiPlatformHasAcpiGuid,
NULL,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"%a: failed to install gEdkiiPlatformHasAcpiGuid as a protocol\n",
__func__
));
goto FreeDtb;
}
} else if (DtAcpiPref.Pref == DT_ACPI_SELECT_DT) {
//
// DT was selected: copy the blob into newly allocated memory and install
// a reference to it as the FDT configuration table.
//
Status = gBS->InstallConfigurationTable (&gFdtTableGuid, Dtb);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"%a: failed to install FDT configuration table\n",
__func__
));
goto FreeDtb;
}
} else {
ASSERT (FALSE);
}
//
// No point in installing the HII pages if ACPI is the only description
// we have
//
if (Dtb == NULL) {
return EFI_SUCCESS;
}
//
// Note that we don't uninstall the gEdkiiPlatformHasAcpiGuid protocol nor
// the FDT configuration table if the following call fails. While that will
// cause loading of this driver to fail, proceeding with ACPI and DT both
// disabled will guarantee a failed boot, and so it is better to leave them
// installed in that case.
//
return InstallHiiPages ();
FreeDtb:
if (Dtb != NULL) {
FreePool (Dtb);
}
return Status;
}