/** @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; | |
} |