slimbootloader/PayloadPkg/OsLoader/ModService.c

320 lines
8.6 KiB
C

/** @file
Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "OsLoader.h"
/**
Load a file into memory from path.
@param[in] Path File path to load.
@param[in] Buffer Buffer pointer to store the loaded file.
@param[in] Length Buffer pointer to store the loaded file size.
@retval EFI_SUCCESS File was loaded successfully.
@retval EFI_UNSUPPORTED Unsupported file path.
@retval EFI_INVALID_PARAMETER File path is NULL.
**/
EFI_STATUS
EFIAPI
LoadFile (
IN CHAR8 *Path,
IN OUT VOID **Buffer,
IN OUT UINT32 *Length
)
{
EFI_STATUS Status;
if (Path == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_UNSUPPORTED;
// Handle special path !XXXX/YYYY
// Load file from a container
if ((AsciiStrLen(Path) == 10) && (Path[0] == '!') && (Path[5] == '/')) {
Status = LoadComponent (SIGNATURE_32 (Path[1], Path[2], Path[3], Path[4]),
SIGNATURE_32 (Path[6], Path[7], Path[8], Path[9]),
(VOID **)Buffer, Length);
}
return Status;
}
/**
Save SETUP config data back into flash.
@param[in] Buffer CFGDATA buffer pointer.
@param[in] DataLen CFGDATA buffer length.
@retval EFI_SUCCESS Config data was saved successfully.
@retval EFI_BUFFER_TOO_SMALL Flash space allocated for CFGDATA is too small.
@retval EFI_NOT_FOUND Could not find CFGB component.
@retval EFI_INVALID_PARAMETER Buffer is NULL.
**/
EFI_STATUS
EFIAPI
SaveConfigData (
UINT8 *Buffer,
UINT32 DataLen
)
{
EFI_STATUS Status;
UINT8 *CfgAddr;
UINT32 CfgLen;
UINT32 RgnBase;
UINT32 RgnSize;
UINT32 Offset;
UINT32 DataOff;
LOADER_COMPRESSED_HEADER LzHeader;
CDATA_BLOB *CdataBlob;
SPI_FLASH_SERVICE *SpiService;
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
CdataBlob = (CDATA_BLOB *)Buffer;
if (CdataBlob->Signature != CFG_DATA_SIGNATURE) {
return EFI_UNSUPPORTED;
}
if (CdataBlob->HeaderLength != sizeof(CDATA_BLOB)) {
return EFI_UNSUPPORTED;
}
if (CdataBlob->UsedLength != DataLen) {
return EFI_UNSUPPORTED;
}
SpiService = (SPI_FLASH_SERVICE *)GetServiceBySignature (SPI_FLASH_SERVICE_SIGNATURE);
if (SpiService == NULL) {
return EFI_UNSUPPORTED;
}
CfgAddr = NULL;
CfgLen = 0;
Status = LocateComponent (CONTAINER_SETUP_SIGNATURE, CFG_DATA_SIGNATURE, (VOID **)&CfgAddr, &CfgLen);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
if (DataLen > CfgLen) {
DEBUG ((DEBUG_INFO, "Insufficant space for SETP/CFGD !\n"));
return EFI_BUFFER_TOO_SMALL;
}
// Update check sum
CdataBlob->ExtraInfo.InternalDataOffset = 0;
CdataBlob->ExtraInfo.InternalDataOffset = CalculateCheckSum16 ((UINT16 *)CdataBlob, CdataBlob->UsedLength);
// Do not update signature yet
CdataBlob->Signature = 0xFFFFFFFF;
Status = SpiService->SpiInit ();
if (!EFI_ERROR (Status)) {
Status = SpiService->SpiGetRegion (FlashRegionBios, &RgnBase, &RgnSize);
if (!EFI_ERROR (Status)) {
DataOff = sizeof(LzHeader);
CopyMem (&LzHeader, CfgAddr, DataOff);
LzHeader.CompressedSize = DataLen;
LzHeader.Size = DataLen;
Offset = (UINT32)(UINTN)CfgAddr + RgnSize;
Status = SpiService->SpiErase (FlashRegionBios, Offset, ALIGN_UP(DataLen, SIZE_4KB));
if (!EFI_ERROR (Status)) {
Status = SpiService->SpiWrite (FlashRegionBios, Offset, DataOff, (UINT8 *)&LzHeader);
}
if (!EFI_ERROR (Status)) {
Status = SpiService->SpiWrite (FlashRegionBios, Offset + DataOff, DataLen, Buffer);
}
if (!EFI_ERROR (Status)) {
CdataBlob->Signature = CFG_DATA_SIGNATURE;
Status = SpiService->SpiWrite (FlashRegionBios, Offset + DataOff, 4, (UINT8 *)&CdataBlob->Signature);
}
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "Write flash failed, please check if FLASH is locked - %r !\n", Status));
}
}
}
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "Failed to save SETP/CFGD - %r !\n", Status));
} else {
DEBUG ((DEBUG_INFO, "SETP/CFGD was saved successfully !\n"));
}
return Status;
}
/**
Reset the platform.
This function does not return.
@param[in] Type Requested console row.
**/
VOID
EFIAPI
PlatformReset (
UINT32 Type
)
{
PLATFORM_SERVICE *PlatformService;
// Reset platform
PlatformService = (PLATFORM_SERVICE *) GetServiceBySignature (PLATFORM_SERVICE_SIGNATURE);
if ((PlatformService != NULL) && (PlatformService->ResetSystem != NULL)) {
DEBUG ((DEBUG_INFO, "Reboot system\n"));
PlatformService->ResetSystem (EfiResetCold);
}
CpuHalt (NULL);
}
/**
Intialize console.
@param[in] Row Requested console row.
@param[in] Col Requested console col.
@retval EFI_SUCCESS Console was initialized successfully.
@retval Others Console initialization failed.
**/
EFI_STATUS
EFIAPI
ConsoleInit (
IN UINT32 Row,
IN UINT32 Col
)
{
return LocalConsoleInit (TRUE);
}
// Provide paylaod module API service function table
VOID *mSerivceMapTbl[] = {
"DebugPrint", (VOID *)((UINTN)&DebugPrint),
"ConsoleInit", (VOID *)((UINTN)&ConsoleInit),
"ConsolePoll", (VOID *)((UINTN)&ConsolePoll),
"ConsoleRead", (VOID *)((UINTN)&ConsoleRead),
"ConsoleWrite", (VOID *)((UINTN)&ConsoleWrite),
"MicroSecondDelay", (VOID *)((UINTN)&MicroSecondDelay),
"AllocatePages", (VOID *)((UINTN)&AllocatePages),
"FreePages", (VOID *)((UINTN)&FreePages),
"SerialPortWrite", (VOID *)((UINTN)&SerialPortWrite),
"LoadFile", (VOID *)((UINTN)&LoadFile),
"PlatformReset", (VOID *)((UINTN)&PlatformReset),
"DrawFrameBuffer", NULL,
"BuildConfigData", NULL,
"SaveConfigData", NULL,
};
/**
Get a function pointer from the function name.
@param[in] FuncName Function name
@retval Function pointer for the given funciton name.
@retval NULL Failed to get the function address.
**/
VOID *
EFIAPI
GetProcAddress (
IN CHAR8 *FuncName
)
{
UINT32 Index;
if (FuncName != NULL) {
for (Index = 0; Index < sizeof(mSerivceMapTbl) / sizeof(mSerivceMapTbl[0]); Index += 2) {
if ((AsciiStrCmp (FuncName, mSerivceMapTbl[Index]) == 0) && \
(mSerivceMapTbl[Index + 1] != NULL)) {
return (VOID *)mSerivceMapTbl[Index + 1];
}
}
DEBUG ((DEBUG_ERROR, "Service '%a' not found !\n", FuncName));
}
return NULL;
}
/**
Update a function pointer iin the API service table.
@param[in] FuncName Function name
@param[in] FuncPointer Function pointer
@retval EFI_SUCCESS API has been updated successfully.
@retval EFI_NOT_FOUND Not found the entry to update.
**/
EFI_STATUS
EFIAPI
UpdateProcAddress (
IN CHAR8 *FuncName,
IN VOID *FuncPointer
)
{
UINT32 Index;
for (Index = 0; Index < sizeof(mSerivceMapTbl) / sizeof(mSerivceMapTbl[0]); Index += 2) {
if (AsciiStrCmp (FuncName, mSerivceMapTbl[Index]) == 0) {
mSerivceMapTbl[Index + 1] = FuncPointer;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Initialize payload module serivce table and paramters.
@param[in] PldModParam Payload module parameter pointer
@param[in] ModuleName Payload module name
**/
VOID
EFIAPI
PayloadModuleInit (
IN PLD_MOD_PARAM *PldModParam,
IN CHAR8 *ModuleName
)
{
CHAR8 *ModCmdLineBuf;
if (PldModParam == NULL) {
return;
}
if (ModuleName != NULL) {
if (AsciiStrnCmp ((CONST CHAR8 *)ModuleName, "!SETP/MPYM", 10) == 0) {
// Setup, enable additional services
UpdateProcAddress ("BuildConfigData", (VOID *)((UINTN)&BuildConfigData));
UpdateProcAddress ("SaveConfigData", (VOID *)((UINTN)&SaveConfigData));
UpdateProcAddress ("DrawFrameBuffer", (VOID *)((UINTN)&DrawFrameBuffer));
}
ModCmdLineBuf = PldModParam->CmdLineBuf;
if (ModCmdLineBuf == NULL) {
return;
}
if (PldModParam->CmdLineLen >= 11) {
if ((ModuleName[0] == '!') && ((ModuleName[5] == '/')) && (ModuleName[10] == ':')) {
// !SETP/MPYM:????, here ???? is the script component name
// So build a path like !SETP/???? for command line.
CopyMem (ModCmdLineBuf, ModuleName, 6);
CopyMem (ModCmdLineBuf + 6, ModuleName + 11, 4);
ModCmdLineBuf[10] = 0;
} else {
ModCmdLineBuf[0] = 0;
}
}
}
}