EmbeddedPkg: Add LoadFile2 for linux initrd

Add support under a pcd feature for using the new interface to pass
initrd to the linux kernel instead of via device tree.
This feature is also enabled if ACPI tables are present, and will skip
locating and installation of device tree.

Signed-off-by: Jeff Brasen <jbrasen@nvidia.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>
This commit is contained in:
Jeff Brasen 2021-09-13 23:18:51 +00:00 committed by mergify[bot]
parent c0cd26f43c
commit 7ea7f9c077
3 changed files with 202 additions and 22 deletions

View File

@ -86,6 +86,7 @@
[PcdsFeatureFlag.common]
gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|FALSE|BOOLEAN|0x0000001b
gEmbeddedTokenSpaceGuid.PcdGdbSerial|FALSE|BOOLEAN|0x00000053
gEmbeddedTokenSpaceGuid.PcdAndroidBootLoadFile2|FALSE|BOOLEAN|0x0000005b
[PcdsFixedAtBuild.common]
gEmbeddedTokenSpaceGuid.PcdPrePiStackBase|0|UINT32|0x0000000b

View File

@ -10,12 +10,16 @@
#include <libfdt.h>
#include <Library/AndroidBootImgLib.h>
#include <Library/PrintLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Protocol/AndroidBootImg.h>
#include <Protocol/LoadFile2.h>
#include <Protocol/LoadedImage.h>
#include <Guid/LinuxEfiInitrdMedia.h>
#define FDT_ADDITIONAL_ENTRIES_SIZE 0x400
typedef struct {
@ -23,7 +27,15 @@ typedef struct {
EFI_DEVICE_PATH_PROTOCOL End;
} MEMORY_DEVICE_PATH;
typedef struct {
VENDOR_DEVICE_PATH VendorMediaNode;
EFI_DEVICE_PATH_PROTOCOL EndNode;
} RAMDISK_DEVICE_PATH;
STATIC ANDROID_BOOTIMG_PROTOCOL *mAndroidBootImg;
STATIC VOID *mRamdiskData = NULL;
STATIC UINTN mRamdiskSize = 0;
STATIC EFI_HANDLE mRamDiskLoadFileHandle = NULL;
STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =
{
@ -46,6 +58,99 @@ STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =
} // End
};
STATIC CONST RAMDISK_DEVICE_PATH mRamdiskDevicePath =
{
{
{
MEDIA_DEVICE_PATH,
MEDIA_VENDOR_DP,
{ sizeof (VENDOR_DEVICE_PATH), 0 }
},
LINUX_EFI_INITRD_MEDIA_GUID
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{ sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
}
};
/**
Causes the driver to load a specified file.
@param This Protocol instance pointer.
@param FilePath The device specific path of the file to load.
@param BootPolicy Should always be FALSE.
@param BufferSize On input the size of Buffer in bytes. On output with a return
code of EFI_SUCCESS, the amount of data transferred to
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
the size of Buffer required to retrieve the requested file.
@param Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
then no the size of the requested file is returned in
BufferSize.
@retval EFI_SUCCESS The file was loaded.
@retval EFI_UNSUPPORTED BootPolicy is TRUE.
@retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
BufferSize is NULL.
@retval EFI_NO_MEDIA No medium was present to load the file.
@retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
@retval EFI_NO_RESPONSE The remote system did not respond.
@retval EFI_NOT_FOUND The file was not found
@retval EFI_ABORTED The file load process was manually canceled.
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current
directory entry. BufferSize has been updated with
the size needed to complete the request.
**/
EFI_STATUS
EFIAPI
AndroidBootImgLoadFile2 (
IN EFI_LOAD_FILE2_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN BOOLEAN BootPolicy,
IN OUT UINTN *BufferSize,
IN VOID *Buffer OPTIONAL
)
{
// Verify if the valid parameters
if (This == NULL ||
BufferSize == NULL ||
FilePath == NULL ||
!IsDevicePathValid (FilePath, 0)) {
return EFI_INVALID_PARAMETER;
}
if (BootPolicy) {
return EFI_UNSUPPORTED;
}
// Check if the given buffer size is big enough
// EFI_BUFFER_TOO_SMALL to allow caller to allocate a bigger buffer
if (mRamdiskSize == 0) {
return EFI_NOT_FOUND;
}
if (Buffer == NULL || *BufferSize < mRamdiskSize) {
*BufferSize = mRamdiskSize;
return EFI_BUFFER_TOO_SMALL;
}
// Copy InitRd
CopyMem (Buffer, mRamdiskData, mRamdiskSize);
*BufferSize = mRamdiskSize;
return EFI_SUCCESS;
}
///
/// Load File Protocol instance
///
STATIC EFI_LOAD_FILE2_PROTOCOL mAndroidBootImgLoadFile2 = {
AndroidBootImgLoadFile2
};
EFI_STATUS
AndroidBootImgGetImgSize (
IN VOID *BootImg,
@ -214,6 +319,60 @@ AndroidBootImgUpdateArgs (
return Status;
}
EFI_STATUS
AndroidBootImgInstallLoadFile2 (
IN VOID *RamdiskData,
IN UINTN RamdiskSize
)
{
mRamDiskLoadFileHandle = NULL;
mRamdiskData = RamdiskData;
mRamdiskSize = RamdiskSize;
return gBS->InstallMultipleProtocolInterfaces (
&mRamDiskLoadFileHandle,
&gEfiLoadFile2ProtocolGuid,
&mAndroidBootImgLoadFile2,
&gEfiDevicePathProtocolGuid,
&mRamdiskDevicePath,
NULL
);
}
EFI_STATUS
AndroidBootImgUninstallLoadFile2 (
VOID
)
{
EFI_STATUS Status;
Status = EFI_SUCCESS;
mRamdiskData = NULL;
mRamdiskSize = 0;
if (mRamDiskLoadFileHandle != NULL) {
Status = gBS->UninstallMultipleProtocolInterfaces (
mRamDiskLoadFileHandle,
&gEfiLoadFile2ProtocolGuid,
&mAndroidBootImgLoadFile2,
&gEfiDevicePathProtocolGuid,
&mRamdiskDevicePath,
NULL
);
mRamDiskLoadFileHandle = NULL;
}
return Status;
}
BOOLEAN AndroidBootImgAcpiSupported (
VOID
)
{
EFI_STATUS Status;
VOID *AcpiTable;
Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, &AcpiTable);
return !EFI_ERROR (Status);
}
EFI_STATUS
AndroidBootImgLocateFdt (
IN VOID *BootImg,
@ -325,23 +484,30 @@ AndroidBootImgUpdateFdt (
goto Fdt_Exit;
}
ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);
if (!ChosenNode) {
goto Fdt_Exit;
}
if (FeaturePcdGet (PcdAndroidBootLoadFile2)) {
Status = AndroidBootImgInstallLoadFile2 (RamdiskData, RamdiskSize);
if (EFI_ERROR (Status)) {
goto Fdt_Exit;
}
} else {
ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);
if (!ChosenNode) {
goto Fdt_Exit;
}
Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
"linux,initrd-start",
(UINTN)RamdiskData);
if (EFI_ERROR (Status)) {
goto Fdt_Exit;
}
Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
"linux,initrd-start",
(UINTN)RamdiskData);
if (EFI_ERROR (Status)) {
goto Fdt_Exit;
}
Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
"linux,initrd-end",
(UINTN)RamdiskData + RamdiskSize);
if (EFI_ERROR (Status)) {
goto Fdt_Exit;
Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
"linux,initrd-end",
(UINTN)RamdiskData + RamdiskSize);
if (EFI_ERROR (Status)) {
goto Fdt_Exit;
}
}
if (mAndroidBootImg->UpdateDtb) {
@ -422,14 +588,21 @@ AndroidBootImgBoot (
goto Exit;
}
Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);
if (EFI_ERROR (Status)) {
goto Exit;
}
if (AndroidBootImgAcpiSupported ()) {
Status = AndroidBootImgInstallLoadFile2 (RamdiskData, RamdiskSize);
if (EFI_ERROR (Status)) {
goto Exit;
}
} else {
Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);
if (EFI_ERROR (Status)) {
goto Exit;
}
Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);
if (EFI_ERROR (Status)) {
goto Exit;
Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);
if (EFI_ERROR (Status)) {
goto Exit;
}
}
KernelDevicePath = mMemoryDevicePathTemplate;
@ -473,5 +646,6 @@ Exit:
NewKernelArg = NULL;
}
}
AndroidBootImgUninstallLoadFile2 ();
return Status;
}

View File

@ -39,6 +39,11 @@
[Protocols]
gAndroidBootImgProtocolGuid
gEfiLoadedImageProtocolGuid
gEfiLoadFile2ProtocolGuid
[Guids]
gEfiAcpiTableGuid
gFdtTableGuid
[FeaturePcd]
gEmbeddedTokenSpaceGuid.PcdAndroidBootLoadFile2