windows-nt/Source/XPSP1/NT/base/efiutil/efintldr/efintldr.c
2020-09-26 16:20:57 +08:00

1454 lines
33 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
efintldr.c
Abstract:
Revision History:
Jeff Sigman 05/01/00 Created
Jeff Sigman 05/10/00 Version 1.5 released
Jeff Sigman 10/18/00 Fix for Soft81 bug(s)
--*/
#include "precomp.h"
//
// Open the IA64LDR.EFI image and load the OS
//
BOOLEAN
LaunchOS(
IN char* String,
IN EFI_HANDLE ImageHandle,
IN EFI_FILE_HANDLE* CurDir,
IN EFI_LOADED_IMAGE* LoadedImage
)
{
CHAR16* uniBuf = NULL;
BOOLEAN bError = TRUE;
EFI_STATUS Status;
EFI_HANDLE exeHdl = NULL;
EFI_INPUT_KEY Key;
EFI_FILE_HANDLE FileHandle = NULL;
EFI_DEVICE_PATH* ldrDevPath = NULL;
do
{
//
// Convert OS path to unicode from ACSII
//
uniBuf = RutlUniStrDup(String);
if (!uniBuf)
{
break;
}
//
// Open the ia64ldr.efi
//
Status = (*CurDir)->Open(
*CurDir,
&FileHandle,
uniBuf,
EFI_FILE_MODE_READ,
0);
if (EFI_ERROR(Status))
{
break;
}
ldrDevPath = FileDevicePath(LoadedImage->DeviceHandle, uniBuf);
if (!ldrDevPath)
{
break;
}
Status = BS->LoadImage(
FALSE,
ImageHandle,
ldrDevPath,
NULL,
0,
&exeHdl);
if (EFI_ERROR(Status))
{
break;
}
Print (L"\nAttempting to launch... %s\n", uniBuf);
WaitForSingleEvent(ST->ConIn->WaitForKey, 5000000);
ST->ConIn->ReadKeyStroke(ST->ConIn, &Key);
//
// Clean up
//
ldrDevPath = RutlFree(ldrDevPath);
uniBuf = RutlFree(uniBuf);
String = RutlFree(String);
//
// Disable the cursor
//
ST->ConOut->EnableCursor(ST->ConOut, FALSE);
bError = FALSE;
//
// Start the OS baby!!
//
BS->StartImage(exeHdl, 0, NULL);
//
// If we get here the OS failed to load
//
bError = TRUE;
//
// Re-enable the cursor
//
ST->ConOut->EnableCursor(ST->ConOut, TRUE);
} while (FALSE);
//
// Clean up
//
if (ldrDevPath)
{
ldrDevPath = RutlFree(ldrDevPath);
}
if (uniBuf)
{
uniBuf = RutlFree(uniBuf);
}
if (FileHandle)
{
FileHandle->Close(FileHandle);
}
if (String)
{
String = RutlFree(String);
}
//
// Where the heck is the lib for this?
//
// if (exeHdl)
// UnloadImage(&exeHdl);
return bError;
}
//
// Struct Cleanup
//
BOOLEAN
FreeBootData(
IN VOID* hBootData
)
{
UINTN i;
BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
if (!pBootData)
{
return TRUE;
}
for (i = 0; i < pBootData->dwIndex; i++)
{
pBootData->pszSPart[i] = RutlFree(pBootData->pszSPart[i]);
pBootData->pszOSLdr[i] = RutlFree(pBootData->pszOSLdr[i]);
pBootData->pszLPart[i] = RutlFree(pBootData->pszLPart[i]);
pBootData->pszFileN[i] = RutlFree(pBootData->pszFileN[i]);
pBootData->pszIdent[i] = RutlFree(pBootData->pszIdent[i]);
pBootData->pszShort[i] = RutlFree(pBootData->pszShort[i]);
}
pBootData->pszShort[pBootData->dwIndex] =
RutlFree(pBootData->pszShort[pBootData->dwIndex]);
pBootData->pszIdent[pBootData->dwIndex] =
RutlFree(pBootData->pszIdent[pBootData->dwIndex]);
if (pBootData->pszLoadOpt)
{
pBootData->pszLoadOpt = RutlFree(pBootData->pszLoadOpt);
}
pBootData->dwLastKnown = 0;
pBootData->dwIndex = 0;
pBootData->dwCount = 0;
return FALSE;
}
//
// Sort the load options based placing the passed option first
//
BOOLEAN
SortLoadOptions(
IN VOID* hBootData,
IN char* Buffer,
IN UINTN* dwSize,
IN UINTN* dwOption,
IN UINTN* dwMax,
IN EFI_FILE_HANDLE* FileHandle
)
{
char *FndTok[BOOT_MAX],
*Start = NULL,
*End = NULL,
*NewOpt = NULL,
*Sortme = NULL,
*Token = NULL,
*Last = NULL,
*Find = NULL;
UINTN i = 0,
j = 0,
dwIndex = 0,
dwStLen = 0,
dwOrigLen = 0,
dwLen = 0;
BOOLEAN bError = FALSE;
BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
do
{
//
// Find the BOOT_LDOPT option
//
Start = strstr(Buffer, BOOT_LDOPT);
if (!Start)
{
bError = TRUE;
break;
}
//
// Find the end of the option
//
End = (Start += strlena(BOOT_LDOPT));
while (*(End++) != '\r')
;
dwOrigLen = (End - Start) - 1;
//
// Create buffer to use for temp sort storage
//
NewOpt = AllocateZeroPool(dwOrigLen + 1);
if (!NewOpt)
{
bError = TRUE;
break;
}
//
// Copy only that option to a new buffer
//
CopyMem(NewOpt, Start, dwOrigLen);
//
// Replace any leading ';' with a nodebug
//
while ((NewOpt[i] == ';') && (i < *dwMax))
{
FndTok[i] = RutlStrDup(BL_DEBUG_NONE);
if (!FndTok[i])
{
bError = TRUE;
break;
}
dwIndex += strlena(FndTok[i++]);
}
//
// Remove tokens
//
Token = strtok(NewOpt, BOOT_TOKEN);
while ((Token != NULL) &&
(Token < (NewOpt + dwOrigLen)) &&
(i < *dwMax)
)
{
if (Find = FindAdvLoadOptions(Token))
{
//
// User has booted using adv options, clearing them out
//
// Add a NULL at the location of the adv opt
//
*Find = '\0';
FndTok[i] = RutlStrDup(Token);
}
else
{
FndTok[i] = RutlStrDup(Token);
if (!FndTok[i])
{
bError = TRUE;
break;
}
}
dwIndex += strlena(FndTok[i++]);
Token = strtok(NULL, BOOT_TOKEN);
}
while (i < *dwMax)
{
FndTok[i] = RutlStrDup(BL_DEBUG_NONE);
if (!FndTok[i])
{
bError = TRUE;
break;
}
dwIndex += strlena(FndTok[i++]);
}
//
// Create buffer to store sorted data
//
Sortme = AllocateZeroPool(dwLen = dwIndex + *dwMax + 1);
if (!Sortme)
{
bError = TRUE;
break;
}
//
// Copy selected option as the first option
//
if (pBootData->pszLoadOpt)
{
//
// if user has selected an adv boot option, it is plum'd here
//
dwStLen = strlena(pBootData->pszLoadOpt) + dwLen + strlena(SPACES);
Sortme = ReallocatePool(Sortme, dwLen, dwStLen);
if (!Sortme)
{
bError = TRUE;
break;
}
//
// they will need to match up later
//
dwLen = dwStLen;
dwIndex = strlena(FndTok[*dwOption]);
CopyMem(Sortme, FndTok[*dwOption], dwIndex);
dwStLen = dwIndex;
dwIndex = strlena(SPACES);
CopyMem(Sortme + dwStLen, SPACES, dwIndex);
dwStLen += dwIndex;
dwIndex = strlena(pBootData->pszLoadOpt);
CopyMem(Sortme + dwStLen, pBootData->pszLoadOpt, dwIndex);
dwStLen += dwIndex;
}
else
{
CopyMem(Sortme, FndTok[*dwOption], strlena(FndTok[*dwOption]));
dwStLen = strlena(FndTok[*dwOption]);
}
//
// Append a seperator
//
*(Sortme + (dwStLen++)) = ';';
//
// Smash the rest of the options back in
//
for (j = 0; j < i; j++)
{
//
// Skip the option that was moved to the front
//
if (j == *dwOption)
{
continue;
}
CopyMem(Sortme + dwStLen, FndTok[j], strlena(FndTok[j]));
dwStLen += strlena(FndTok[j]);
//
// Append a seperator
//
*(Sortme + (dwStLen++)) = ';';
}
dwStLen--;
*(Sortme + dwStLen++) = '\r';
*(Sortme + dwStLen++) = '\n';
if (dwLen != dwStLen)
{
bError = TRUE;
break;
}
//
// Write new sorted load options to file
//
(*FileHandle)->SetPosition(*FileHandle, (Start - Buffer));
(*FileHandle)->Write(*FileHandle, &dwStLen, Sortme);
//
// Write options that following load options back to file
//
(*FileHandle)->SetPosition(*FileHandle, (Start - Buffer) + dwStLen - 1);
dwStLen = *dwSize - (End - Buffer);
(*FileHandle)->Write(*FileHandle, &dwStLen, End);
//
// Set last known good
//
if (Last = strstr(End, BOOT_LASTK))
{
(*FileHandle)->SetPosition(
*FileHandle,
(Start - Buffer) + dwLen + (Last - End) - 1);
if (pBootData->dwLastKnown)
{
dwIndex = strlena(LAST_TRUE);
(*FileHandle)->Write(*FileHandle, &dwIndex, LAST_TRUE);
}
else
{
dwIndex = strlena(LAST_FALSE);
(*FileHandle)->Write(*FileHandle, &dwIndex, LAST_FALSE);
}
}
//
// Subtract the terminators
//
dwLen -= 2;
if (dwOrigLen <= dwLen)
{
break;
}
//
// append semi-colon's at the end of the file if we have left over room
//
// don't reuse 'i', need it below to free
//
for (j = 0; j < (dwOrigLen - dwLen); j++)
{
dwStLen = 1;
(*FileHandle)->Write(*FileHandle, &dwStLen, ";");
}
} while (FALSE);
if (Sortme)
{
Sortme = RutlFree(Sortme);
}
for (j = 0; j < i; j++)
{
FndTok[j] = RutlFree(FndTok[j]);
}
if (NewOpt)
{
NewOpt = RutlFree(NewOpt);
}
return bError;
}
//
// Sort the boot options based placing the passed option first
//
BOOLEAN
SortBootData(
IN char* Option,
IN char* StrArr[],
IN UINTN* dwOption,
IN UINTN* dwMax,
IN char* Buffer
)
{
char *Start = NULL,
*End = NULL,
*NewOpt = NULL;
UINTN i,
dwIndex = 0,
dwLen = 0;
BOOLEAN bError = TRUE;
do
{
//
// Find the option header
//
Start = strstr(Buffer, Option);
if (!Start)
{
break;
}
//
// Find the end of the option
//
End = (Start += strlena(Option));
while (*(End++) != '\n')
;
dwLen = End - Start;
//
// Create buffer to use for temp sort storage
//
NewOpt = AllocateZeroPool(dwLen);
if (!NewOpt)
{
break;
}
//
// Copy only that option to a new buffer
//
CopyMem(NewOpt, StrArr[*dwOption], strlena(StrArr[*dwOption]));
dwIndex += strlena(StrArr[*dwOption]);
//
// Append a seperator
//
*(NewOpt+(dwIndex++)) = ';';
for (i = 0; i < *dwMax; i++)
{
if (i == *dwOption)
{
continue;
}
CopyMem(NewOpt + dwIndex, StrArr[i], strlena(StrArr[i]));
dwIndex += strlena(StrArr[i]);
*(NewOpt+(dwIndex++)) = ';';
}
while (dwIndex++ < (dwLen - 1))
{
*(NewOpt + (dwIndex - 1)) = ';';
}
*(NewOpt + (dwLen - 2)) = '\r';
*(NewOpt + dwLen - 1) = '\n';
if (dwIndex != dwLen)
{
break;
}
//
// Copy new sorted data in the buffer
//
CopyMem(Start, NewOpt, dwIndex);
bError = FALSE;
} while (FALSE);
if (NewOpt)
{
NewOpt = RutlFree(NewOpt);
}
return bError;
}
//
// Parse options from file data
//
BOOLEAN
OrderBootFile(
IN UINTN dwOption,
IN char* Buffer,
IN VOID* hBootData
)
{
BOOLEAN bError = TRUE;
BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
do
{
//
// Find/sort the BOOT_SPART option
//
if (SortBootData(
BOOT_SPART,
pBootData->pszSPart,
&dwOption,
&(pBootData->dwIndex),
Buffer))
{
Print(L"OrderBootFile() failed for BOOT_SPART option!\n");
break;
}
//
// Find/sort the BOOT_OSLDR option
//
if (SortBootData(
BOOT_OSLDR,
pBootData->pszOSLdr,
&dwOption,
&(pBootData->dwIndex),
Buffer))
{
Print(L"OrderBootFile() failed for BOOT_OSLDR option!\n");
break;
}
//
// Find/sort the BOOT_LPART option
//
if (SortBootData(
BOOT_LPART,
pBootData->pszLPart,
&dwOption,
&(pBootData->dwIndex),
Buffer))
{
Print(L"OrderBootFile() failed for BOOT_LPART option!\n");
break;
}
//
// Find/sort the BOOT_FILEN option
//
if (SortBootData(
BOOT_FILEN,
pBootData->pszFileN,
&dwOption,
&(pBootData->dwIndex),
Buffer))
{
Print(L"OrderBootFile() failed for BOOT_FILEN option!\n");
break;
}
//
// Find/sort the BOOT_IDENT option
//
if (SortBootData(
BOOT_IDENT,
pBootData->pszIdent,
&dwOption,
&(pBootData->dwIndex),
Buffer))
{
Print(L"OrderBootFile() failed for BOOT_IDENT option!\n");
break;
}
bError = FALSE;
} while (FALSE);
return bError;
}
//
// Chop-up name to be short to 'pretty up' the menu
//
BOOLEAN
CreateShortNames(
IN VOID* hBootData
)
{
char *start = NULL,
*end = NULL;
UINTN i,
Len = 0;
BOOLEAN bError = FALSE;
BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
do
{
for (i = 0; i < pBootData->dwIndex; i++)
{
start = strstr(pBootData->pszOSLdr[i], wacks);
end = strstr(pBootData->pszOSLdr[i], EFIEXT);
//
// check for foo case (thx jhavens)
//
if ((end == NULL) ||
(start == NULL)
)
{
start = pBootData->pszOSLdr[i];
end = start;
while (*(end++) != '\0')
;
Len = end - start;
}
//
// Non-foo case, person has atleast one '\' && '.efi'
//
if (!Len)
{
start += 1;
while (*end != wackc)
{
if (end <= start)
{
start = pBootData->pszOSLdr[i];
end = strstr(pBootData->pszOSLdr[i], wacks);
break;
}
end--;
}
Len = end - start;
}
if ((end == NULL) ||
(start == NULL) ||
(Len < 1)
)
{
bError = TRUE;
break;
}
pBootData->pszShort[i] = AllocateZeroPool(Len + 1);
if (!pBootData->pszShort[i])
{
bError = TRUE;
break;
}
CopyMem(pBootData->pszShort[i], start, end - start);
Len = 0;
start = NULL;
end = NULL;
}
} while (FALSE);
return bError;
}
//
// Find the passed option from the file data
//
BOOLEAN
FindOpt(
IN char* pszOption,
IN char* Buffer,
OUT char* pszArray[],
OUT UINTN* dwCount
)
{
char *Start = NULL,
*End = NULL,
*Option = NULL,
*Token = NULL;
UINTN dwIndex = 0;
BOOLEAN bError = TRUE;
do
{
//
// Find the option
//
Start = strstr(Buffer, pszOption);
if (!Start)
{
break;
}
//
// Find the end of the option
//
Start += strlena(pszOption);
End = Start;
while (*(End++) != '\r')
;
Option = AllocateZeroPool((End-Start));
if (!Option)
{
break;
}
//
// Copy only that option to a new buffer
//
CopyMem(Option, Start, (End-Start)-1);
*(Option+((End-Start)-1)) = 0x00;
//
// Remove tokens
//
Token = strtok(Option, BOOT_TOKEN);
if (!Token)
{
break;
}
if (!(*dwCount))
{
while ((Token != NULL) &&
(dwIndex < BOOT_MAX)
)
{
pszArray[(dwIndex)++] = RutlStrDup(Token);
Token = strtok(NULL, BOOT_TOKEN);
}
*dwCount = dwIndex;
}
else
{
while ((Token != NULL) &&
(dwIndex < *dwCount)
)
{
pszArray[(dwIndex)++] = RutlStrDup(Token);
Token = strtok(NULL, BOOT_TOKEN);
}
}
if (dwIndex == 0)
{
break;
}
bError = FALSE;
} while (FALSE);
if (Option)
{
Option = RutlFree(Option);
}
return bError;
}
//
// Get the options in their entirety from the file data
//
BOOLEAN
GetBootData(
IN VOID* hBootData,
IN char* Buffer
)
{
UINTN i;
char* TempStr = NULL;
CHAR16* UniStr = NULL;
BOOLEAN bError = TRUE;
BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
do
{
//
// Find the BOOT_IDENT option
//
if (FindOpt(
BOOT_IDENT,
Buffer,
pBootData->pszIdent,
&pBootData->dwIndex))
{
break;
}
pBootData->pszIdent[pBootData->dwIndex] = RutlStrDup(BL_EXIT_EFI1);
if (!pBootData->pszIdent[pBootData->dwIndex])
{
break;
}
//
// Find the BOOT_SPART option
//
if (FindOpt(
BOOT_SPART,
Buffer,
pBootData->pszSPart,
&pBootData->dwIndex))
{
break;
}
//
// Find the BOOT_OSLDR option
//
if (FindOpt(
BOOT_OSLDR,
Buffer,
pBootData->pszOSLdr,
&pBootData->dwIndex))
{
break;
}
if (CreateShortNames(pBootData))
{
break;
}
//
// Append 'exit' to the end of the menu
//
pBootData->pszShort[pBootData->dwIndex] = RutlStrDup(BL_EXIT_EFI2);
if (!pBootData->pszShort[pBootData->dwIndex])
{
break;
}
//
// Find the BOOT_LPART option
//
if (FindOpt(
BOOT_LPART,
Buffer,
pBootData->pszLPart,
&pBootData->dwIndex))
{
break;
}
//
// Find the BOOT_FILEN option
//
if (FindOpt(
BOOT_FILEN,
Buffer,
pBootData->pszFileN,
&pBootData->dwIndex))
{
break;
}
//
// Find the BOOT_CNTDW option
//
if (TempStr = strstr(Buffer, BOOT_CNTDW))
{
UniStr = RutlUniStrDup(TempStr + strlena(BOOT_CNTDW));
if ((UniStr != NULL) &&
(Atoi(UniStr) > 0) &&
(Atoi(UniStr) < BOOT_COUNT)
)
{
pBootData->dwCount = Atoi(UniStr);
bError = FALSE;
break;
}
}
//
// Set the count to the default if setting it failed
//
if (!pBootData->dwCount)
{
pBootData->dwCount = BOOT_COUNT;
}
bError = FALSE;
} while (FALSE);
if (UniStr)
{
UniStr = RutlFree(UniStr);
}
return bError;
}
//
// fill out startup.nsh with the name of this program
//
void
PopulateStartFile(
IN EFI_FILE_HANDLE* StartFile
)
{
UINTN size;
CHAR16 UnicodeMarker = UNICODE_BYTE_ORDER_MARK;
size = sizeof(UnicodeMarker);
(*StartFile)->Write(*StartFile, &size, &UnicodeMarker);
size = (StrLen(THISFILE)) * sizeof(CHAR16);
(*StartFile)->Write(*StartFile, &size, THISFILE);
return;
}
//
// Parse cmdline params
//
void
ParseArgs(
IN EFI_FILE_HANDLE* CurDir,
IN EFI_LOADED_IMAGE* LoadedImage
)
{
EFI_STATUS Status;
EFI_FILE_HANDLE StartFile = NULL;
do
{
if (MetaiMatch(LoadedImage->LoadOptions, REGISTER1) ||
MetaiMatch(LoadedImage->LoadOptions, REGISTER2)
)
{
Status = (*CurDir)->Open(
*CurDir,
&StartFile,
STARTFILE,
EFI_FILE_MODE_READ |
EFI_FILE_MODE_WRITE |
EFI_FILE_MODE_CREATE,
0);
if (EFI_ERROR(Status))
{
break;
}
Status = StartFile->Delete(StartFile);
if (EFI_ERROR(Status))
{
break;
}
StartFile = NULL;
Status = (*CurDir)->Open(
*CurDir,
&StartFile,
STARTFILE,
EFI_FILE_MODE_READ |
EFI_FILE_MODE_WRITE |
EFI_FILE_MODE_CREATE,
0);
if (!EFI_ERROR(Status))
{
PopulateStartFile(&StartFile);
}
}
} while (FALSE);
//
// Clean up
//
if (StartFile)
{
StartFile->Close(StartFile);
}
return;
}
//
// Read in BOOT.NVR and return buffer of contents
//
void*
ReadBootFile(
IN UINTN* Size,
IN EFI_FILE_HANDLE* FileHandle
)
{
char* Buffer = NULL;
EFI_STATUS Status;
EFI_FILE_INFO* BootInfo = NULL;
do
{
*Size = (SIZE_OF_EFI_FILE_INFO + 255) * sizeof(CHAR16);
BootInfo = AllocateZeroPool(*Size);
if (!BootInfo)
{
break;
}
Status = (*FileHandle)->GetInfo(
*FileHandle,
&GenericFileInfo,
Size,
BootInfo);
if (EFI_ERROR(Status))
{
break;
}
//
// Find out how much we will need to alloc
//
*Size = (UINTN) BootInfo->FileSize;
Buffer = AllocateZeroPool((*Size) + 1);
if (!Buffer)
{
break;
}
Status = (*FileHandle)->Read(*FileHandle, Size, Buffer);
if (EFI_ERROR(Status))
{
Buffer = RutlFree(Buffer);
break;
}
} while (FALSE);
//
// Clean up
//
if (BootInfo)
{
BootInfo = RutlFree(BootInfo);
}
return Buffer;
}
//
// Remove any extra semi-colons from BOOT.NVR
//
BOOLEAN
CleanBootFile(
IN EFI_FILE_HANDLE* FileHandle,
IN EFI_FILE_HANDLE* CurDir
)
{
char *Buffer = NULL,
*CpBuffer = NULL;
UINTN i,
Size = 0,
NewSize = 0;
BOOLEAN bError = TRUE;
EFI_STATUS Status;
EFI_FILE_HANDLE NewFile = NULL;
do
{
(*FileHandle)->SetPosition(*FileHandle, 0);
Buffer = ReadBootFile(&Size, FileHandle);
if (!Buffer)
{
break;
}
CpBuffer = AllocateZeroPool(Size);
if (!CpBuffer)
{
break;
}
for (i = 0; i < Size; i++)
{
if ((*(Buffer + i) == ';') &&
((*(Buffer + i + 1) == ';') ||
(*(Buffer + i + 1) == '\r') ||
(i + 1 == Size)
)
)
{
continue;
}
*(CpBuffer + NewSize) = *(Buffer + i);
NewSize++;
}
//
// Remove the exisiting BOOT.NVR
//
Status = (*FileHandle)->Delete(*FileHandle);
if (EFI_ERROR(Status))
{
break;
}
*FileHandle = NULL;
Status = (*CurDir)->Open(
*CurDir,
&NewFile,
BOOT_NVR,
EFI_FILE_MODE_READ |
EFI_FILE_MODE_WRITE |
EFI_FILE_MODE_CREATE,
0);
if (EFI_ERROR(Status))
{
break;
}
Status = NewFile->Write(NewFile, &NewSize, CpBuffer);
if (EFI_ERROR(Status))
{
break;
}
bError = FALSE;
} while (FALSE);
//
// Clean up
//
if (NewFile)
{
NewFile->Close(NewFile);
}
if (CpBuffer)
{
CpBuffer = RutlFree(CpBuffer);
}
if (Buffer)
{
Buffer = RutlFree(Buffer);
}
return bError;
}
//
// Backup the BOOT.NVR so we have a fall back
//
BOOLEAN
BackupBootFile(
IN char* Buffer,
IN UINTN* Size,
IN EFI_FILE_HANDLE* CurDir
)
{
BOOLEAN bError = FALSE;
EFI_STATUS Status;
EFI_FILE_HANDLE FileHandle = NULL;
do
{
//
// Delete the backup file if already exists
//
Status = (*CurDir)->Open(
*CurDir,
&FileHandle,
BACKUP_NVR,
EFI_FILE_MODE_READ |
EFI_FILE_MODE_WRITE,
0);
if (!EFI_ERROR(Status))
{
Status = FileHandle->Delete(FileHandle);
if (EFI_ERROR(Status))
{
break;
}
}
FileHandle = NULL;
//
// Copy current file data to a newly created backup file
//
Status = (*CurDir)->Open(
*CurDir,
&FileHandle,
BACKUP_NVR,
EFI_FILE_MODE_READ |
EFI_FILE_MODE_WRITE |
EFI_FILE_MODE_CREATE,
0);
if (!EFI_ERROR(Status))
{
Status = FileHandle->Write(FileHandle, Size, Buffer);
}
} while (FALSE);
//
// Clean up
//
if (FileHandle)
{
FileHandle->Close(FileHandle);
}
if (EFI_ERROR(Status))
{
bError = TRUE;
}
return bError;
}
//
// EFI Entry Point
//
EFI_STATUS
EfiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE* ST
)
{
char* Buffer = NULL;
char* OSPath = NULL;
UINTN Size = 0,
Launch = 0,
Menu = 0;
BOOT_DATA* pBootData = NULL;
EFI_STATUS Status;
EFI_FILE_HANDLE FileHandle = NULL,
RootFs = NULL;
EFI_DEVICE_PATH* DevicePath = NULL;
EFI_LOADED_IMAGE* LoadedImage = NULL;
do
{
InitializeLib(ImageHandle, ST);
//
// Get the device handle and file path to the EFI OS Loader itself.
//
Status = BS->HandleProtocol(
ImageHandle,
&LoadedImageProtocol,
&LoadedImage);
if (EFI_ERROR(Status))
{
Print(L"Can not retrieve LoadedImageProtocol handle\n");
break;
}
Status = BS->HandleProtocol(
LoadedImage->DeviceHandle,
&DevicePathProtocol,
&DevicePath);
if (EFI_ERROR(Status) || DevicePath == NULL)
{
Print(L"Can not find DevicePath handle\n");
break;
}
//
// Open volume for the device where the EFI OS Loader was loaded from
//
RootFs = LibOpenRoot(LoadedImage->DeviceHandle);
if (!RootFs)
{
Print(L"Can not open the volume for the file system\n");
break;
}
//
// Look for any cmd line params
//
ParseArgs(&RootFs, LoadedImage);
//
// Attempt to open the boot.nvr
//
Status = RootFs->Open(
RootFs,
&FileHandle,
BOOT_NVR,
EFI_FILE_MODE_READ |
EFI_FILE_MODE_WRITE,
0);
if (EFI_ERROR(Status))
{
Print(L"Can not open the file %s\n", BOOT_NVR);
break;
}
Buffer = ReadBootFile(&Size, &FileHandle);
if (!Buffer)
{
Print(L"ReadBootFile() failed!\n");
break;
}
if (BackupBootFile(Buffer, &Size, &RootFs))
{
Print(L"BackupBootFile() failed!\n");
break;
}
//
// Alloc for boot file data struct
//
pBootData = (BOOT_DATA*) AllocateZeroPool(sizeof(BOOT_DATA));
if (!pBootData)
{
Print(L"Failed to allocate memory for BOOT_DATA!\n");
break;
}
if (GetBootData(pBootData, Buffer))
{
Print(L"Failed in GetBootData()!\n");
break;
}
Menu = DisplayMenu(pBootData);
if (Menu < pBootData->dwIndex)
{
if (!OrderBootFile(Menu, Buffer, pBootData))
{
FileHandle->SetPosition(FileHandle, 0);
FileHandle->Write(FileHandle, &Size, Buffer);
if (SortLoadOptions(
pBootData,
Buffer,
&Size,
&Menu,
&(pBootData->dwIndex),
&FileHandle)
)
{
Print(L"Failed to SortLoadOptions()!\n");
break;
}
if (CleanBootFile(&FileHandle, &RootFs))
{
Print(L"Failed to CleanBootFile()!\n");
break;
}
}
else
{
Print(L"Failed to OrderBootFile()!\n");
break;
}
}
else
{
break;
}
OSPath = RutlStrDup(strstr(pBootData->pszOSLdr[Menu], wacks) + 1);
if (!OSPath)
{
Print(L"Failed to allocate memory for OSPath!\n");
break;
}
Launch = 1;
} while (FALSE);
//
// Clean up
//
if (pBootData)
{
if (pBootData->dwIndex)
{
FreeBootData(pBootData);
}
pBootData = RutlFree(pBootData);
}
if (Buffer)
{
Buffer = RutlFree(Buffer);
}
if (FileHandle)
{
FileHandle->Close(FileHandle);
}
if (Launch)
{
if (LaunchOS(OSPath, ImageHandle, &RootFs, LoadedImage))
{
Print (L"Failed to LaunchOS()!\n");
}
}
return EFI_SUCCESS;
}