/*
|
# Copyright (c) 2014-2018, Linaro Limited. All rights reserved.
|
#
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
#
|
*/
|
#include <RdkBootManagerLib.h>
|
|
#define MAX_VAR 6
|
|
/**
|
* list_for_each_entry - iterate over list of given type
|
* @pos: the type * to use as a loop cursor.
|
* @head: the head for your list.
|
* @member: the name of the list_struct within the struct.
|
*/
|
#define LIST_FOR_EACH_ENTRY(Pos, Head, Member) \
|
for (Pos = BASE_CR((Head)->ForwardLink, typeof(*Pos), Member); \
|
&Pos->Member != (Head); \
|
Pos = BASE_CR(Pos->Member.ForwardLink, typeof(*Pos), Member))
|
|
/**
|
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
* @pos: the type * to use as a loop cursor.
|
* @n: another type * to use as temporary storage
|
* @head: the head for your list.
|
* @member: the name of the list_struct within the struct.
|
*/
|
#define LIST_FOR_EACH_ENTRY_SAFE(Pos, N, Head, Member) \
|
for (Pos = BASE_CR((Head)->ForwardLink, typeof(*Pos), Member), \
|
N = BASE_CR(Pos->Member.ForwardLink, typeof(*Pos), Member); \
|
&Pos->Member != (Head); \
|
Pos = N, N = BASE_CR(N->Member.ForwardLink, typeof(*N), Member))
|
|
/* ************************** */
|
|
typedef struct {
|
CHAR16 *Name;
|
LIST_ENTRY List;
|
} DIR_NODE;
|
/* ************************** */
|
|
STATIC UINT8 VarablesInitialzed = 0;
|
STATIC CHAR16 *VarResult[MAX_VAR][2];
|
|
STATIC
|
VOID
|
SaveString (
|
OUT CHAR16 **Dest,
|
IN CHAR16 *String1,
|
IN CHAR16 *String2
|
)
|
{
|
UINTN StringLength;
|
|
StringLength = StrLen (String1) + StrLen (String2) + 1;
|
*Dest = AllocatePool (StringLength * sizeof (CHAR16));
|
ASSERT (Dest != NULL);
|
StrCpyS (*Dest, StringLength, String1);
|
StrCatS (*Dest, StringLength, String2);
|
}
|
|
STATIC
|
EFI_STATUS
|
LsFiles (
|
IN CONST CHAR16 *DirPath,
|
IN CONST CHAR16 *TargetFile,
|
OUT CHAR16 **Result,
|
IN LIST_ENTRY *Head
|
)
|
{
|
EFI_STATUS Status;
|
EFI_FILE_INFO *FileInfo;
|
EFI_FILE_PROTOCOL *FileHandle;
|
BOOLEAN NoFile;
|
CHAR16 *TempPath;
|
DIR_NODE *Node;
|
UINTN StringLength;
|
|
NoFile = FALSE;
|
StringLength = StrLen(DirPath) + 2;
|
TempPath = AllocatePool (StringLength * sizeof (CHAR16));
|
StrCpyS (TempPath, StringLength, DirPath);
|
StrCatS (TempPath, StringLength, L"/");
|
|
Status = GetFileHandler (&FileHandle, DirPath, EFI_FILE_MODE_READ);
|
ASSERT_EFI_ERROR (Status);
|
|
for ( Status = FileHandleFindFirstFile (FileHandle, &FileInfo);
|
!EFI_ERROR (Status) && !NoFile;
|
Status = FileHandleFindNextFile (FileHandle, FileInfo, &NoFile)
|
) {
|
if ( (FileInfo->Attribute & EFI_FILE_DIRECTORY) &&
|
(StrCmp (FileInfo->FileName, L".") != 0) &&
|
(StrCmp (FileInfo->FileName, L"..") != 0)) {
|
Node = AllocateZeroPool (sizeof (DIR_NODE));
|
//append directory name to the path
|
SaveString (&Node->Name, TempPath, FileInfo->FileName);
|
InsertHeadList (Head, &Node->List);
|
} else if (StrCmp (FileInfo->FileName, TargetFile) == 0) {
|
//append file to the absolute path
|
SaveString (Result, TempPath, FileInfo->FileName);
|
Status = EFI_SUCCESS;
|
goto Exit;
|
}
|
}
|
|
Status = EFI_NOT_FOUND;
|
|
Exit:
|
FreePool (TempPath);
|
return Status;
|
}
|
|
STATIC
|
VOID
|
DelDirList (
|
IN LIST_ENTRY *Head
|
)
|
{
|
DIR_NODE *Node;
|
DIR_NODE *Temp;
|
|
LIST_FOR_EACH_ENTRY_SAFE (Node, Temp, Head, List) {
|
RemoveEntryList (&Node->List);
|
FreePool (Node->Name);
|
FreePool (Node);
|
}
|
}
|
|
STATIC
|
EFI_STATUS
|
FindFileInDir (
|
IN CONST CHAR16 *DevPath,
|
IN CONST CHAR16 *TargetFile,
|
OUT CHAR16 **Result
|
)
|
{
|
UINT8 Current;
|
UINT8 Next;
|
DIR_NODE *Temp;
|
LIST_ENTRY DirList[2];
|
|
*Result = NULL;
|
EFI_STATUS Status = EFI_NOT_FOUND;
|
|
InitializeListHead (&DirList[0]);
|
InitializeListHead (&DirList[1]);
|
|
for (Current = Next = 0, Status = LsFiles (\
|
DevPath, TargetFile, Result, &DirList[Current]);
|
!IsListEmpty (&DirList[Current]);
|
Current = Next) {
|
Next = Current ^ 1;
|
DelDirList (&DirList[Next]);
|
|
LIST_FOR_EACH_ENTRY (Temp, &DirList[Current], List) {
|
Status = LsFiles (Temp->Name, TargetFile, Result, &DirList[Next]);
|
if (!EFI_ERROR (Status)) {
|
DelDirList (&DirList[Current]);
|
break;
|
}
|
}
|
}
|
|
DelDirList (&DirList[Next]);
|
return Status;
|
}
|
|
STATIC
|
UINTN
|
StrSpn (
|
IN CHAR8 *String,
|
IN CHAR8 *CharSet
|
)
|
{
|
UINTN Count;
|
|
for (Count = 0;
|
String[Count] && ! (String[Count] == CharSet[0]);
|
Count++);
|
return Count;
|
}
|
|
STATIC
|
EFI_STATUS
|
InitVarList (
|
IN CHAR8 *FileData,
|
IN UINTN FileSize
|
)
|
{
|
UINTN InnerLoopIndex;
|
UINTN OuterLoopIndex;
|
UINTN Current;
|
UINTN Next;
|
CHAR8 *VarDelimiter[2];
|
EFI_STATUS Status;
|
UINTN StringLength;
|
|
VarDelimiter[0] = "=";
|
VarDelimiter[1] = "\"";
|
Status = EFI_SUCCESS;
|
|
//Initialize to NULL
|
for (OuterLoopIndex = 0; OuterLoopIndex < MAX_VAR; OuterLoopIndex++) {
|
VarResult[OuterLoopIndex][0] = VarResult[OuterLoopIndex][1] = NULL;
|
}
|
|
for (OuterLoopIndex = 0, Next=0;
|
OuterLoopIndex < MAX_VAR && Next < FileSize;
|
OuterLoopIndex++) {
|
for (InnerLoopIndex = 0; InnerLoopIndex < 2; InnerLoopIndex++) {
|
Current = Next;
|
Next += StrSpn (&FileData[Next], VarDelimiter[InnerLoopIndex]);
|
FileData[Next] = '\0';
|
if (VarResult[OuterLoopIndex][InnerLoopIndex]) {
|
FreePool (VarResult[OuterLoopIndex][InnerLoopIndex]);
|
}
|
StringLength = AsciiStrLen (&FileData[Current]) + 1;
|
VarResult[OuterLoopIndex][InnerLoopIndex] = AllocatePool (StringLength);
|
AsciiStrToUnicodeStrS (&FileData[Current],
|
VarResult[OuterLoopIndex][InnerLoopIndex], StringLength);
|
//skip new line
|
Next += 2;
|
}
|
}
|
|
return Status;
|
}
|
|
STATIC
|
EFI_STATUS
|
InitRdkVariables (
|
VOID
|
)
|
{
|
EFI_STATUS Status;
|
UINTN RdkSize;
|
UINT8 *RdkData;
|
CHAR16 *Result;
|
CONST CHAR16 *DevPath;
|
CONST CHAR16 *RdkFileName;
|
|
DevPath = (CONST CHAR16 *)FixedPcdGetPtr (PcdRdkConfFileDevicePath);
|
RdkFileName = (CONST CHAR16 *)FixedPcdGetPtr (PcdRdkConfFileName);
|
|
Status = FindFileInDir (DevPath, RdkFileName, &Result);
|
if (EFI_ERROR (Status)) {
|
DEBUG ((DEBUG_ERROR, "Failed to find file %s in %s\n", \
|
RdkFileName, DevPath));
|
return Status;
|
}
|
|
Status = RdkReadFile ((CONST CHAR16 *)Result, \
|
(VOID**)&RdkData, &RdkSize);
|
if (EFI_ERROR (Status)) {
|
DEBUG ((DEBUG_ERROR, "Failed to read file %s\n", RdkFileName));
|
return Status;
|
}
|
|
Status = InitVarList ((CHAR8 *)RdkData, RdkSize);
|
return Status;
|
}
|
|
STATIC
|
EFI_STATUS
|
GetVarValue (
|
IN CONST CHAR16 *Name,
|
OUT CONST CHAR16 **Value
|
)
|
{
|
UINTN Count;
|
EFI_STATUS Status;
|
|
if (!VarablesInitialzed) {
|
Status = InitRdkVariables ();
|
if (EFI_ERROR (Status)) {
|
return Status;
|
}
|
|
VarablesInitialzed = 1;
|
}
|
|
//Initialize to NULL
|
*Value = NULL;
|
|
for (Count = 0; Count < MAX_VAR; Count++) {
|
if (VarResult[Count][0] != NULL &&
|
StrCmp (Name, VarResult[Count][0]) == 0) {
|
*Value = VarResult[Count][1];
|
return EFI_SUCCESS;
|
}
|
}
|
|
return EFI_NOT_FOUND;
|
}
|
|
EFI_STATUS
|
GetRdkVariable (
|
IN CONST CHAR16 *Name,
|
OUT CONST CHAR16 **Value
|
)
|
{
|
EFI_STATUS Status;
|
|
Status = GetVarValue (Name, Value);
|
return Status;
|
}
|
|
EFI_STATUS
|
RdkReadFile (
|
IN CONST CHAR16 *Path,
|
IN OUT VOID **BufferPtr,
|
OUT UINTN *FileSize
|
)
|
{
|
UINTN BufferSize;
|
UINT64 SourceFileSize;
|
VOID *Buffer;
|
EFI_STATUS Status;
|
EFI_FILE_HANDLE FileHandle;
|
|
Status = GetFileHandler (&FileHandle, Path, EFI_FILE_MODE_READ);
|
ASSERT_EFI_ERROR (Status);
|
|
Buffer = NULL;
|
|
// Get the file size
|
Status = FileHandle->SetPosition (FileHandle, (UINT64) -1);
|
if (EFI_ERROR (Status)) {
|
goto Exit;
|
}
|
|
Status = FileHandle->GetPosition (FileHandle, &SourceFileSize);
|
if (EFI_ERROR (Status)) {
|
goto Exit;
|
}
|
|
Status = FileHandle->SetPosition (FileHandle, 0);
|
if (EFI_ERROR (Status)) {
|
goto Exit;
|
}
|
|
BufferSize = (UINTN)SourceFileSize;
|
Buffer = AllocateZeroPool (BufferSize);
|
if (Buffer == NULL) {
|
return EFI_OUT_OF_RESOURCES;
|
}
|
|
if (FileSize != NULL) *FileSize = BufferSize;
|
|
Status = FileHandle->Read (FileHandle, &BufferSize, Buffer);
|
if (EFI_ERROR (Status) || BufferSize != SourceFileSize) {
|
FreePool (Buffer);
|
Buffer = NULL;
|
Status = EFI_BAD_BUFFER_SIZE;
|
goto Exit;
|
}
|
|
Exit:
|
*BufferPtr = Buffer;
|
return Status;
|
}
|
|
EFI_STATUS
|
RdkWriteFile (
|
IN CONST CHAR16 *Path,
|
IN OUT VOID **BufferPtr,
|
OUT UINTN *FileSize
|
)
|
{
|
EFI_STATUS Status;
|
EFI_FILE_HANDLE FileHandle;
|
|
if (FileSize == NULL) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
Status = GetFileHandler (&FileHandle, Path, \
|
EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE);
|
ASSERT_EFI_ERROR (Status);
|
|
Status = FileHandle->Write (FileHandle, FileSize, *BufferPtr);
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
}
|