Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

681 lines
15 KiB

#include <efi.h>
#include <efilib.h>
#define MAX_ENV_SIZE 1024
#define MAXUSHORT (0xFFFF)
//
// Globals for stdout
//
SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut;
SIMPLE_INPUT_INTERFACE *ConIn;
//
// Globals for protocol handler
//
EFI_HANDLE_PROTOCOL HandleProtocol;
EFI_LOCATE_HANDLE LocateHandle;
EFI_LOCATE_DEVICE_PATH LocateDevicePath;
EFI_IMAGE_LOAD LoadImage;
EFI_IMAGE_START StartImage;
EFI_SET_VARIABLE SetVariable;
EFI_HANDLE MenuImageHandle;
EFI_LOADED_IMAGE *ExeImage;
//
// globals for managing boot entries
//
UINT32 NvrAttributes;
UINTN NvrOrderCount;
UINT16 *NvrOrder;
//
// prototypes
//
UINT32 GetInputKey();
void DisplayKey(UINT32);
EFI_STATUS
OpenCreateFile (
UINT64 OCFlags,
EFI_FILE_HANDLE* StartHdl,
CHAR16* Name
);
EFI_STATUS
InsertBootOption(
VOID *BootOption,
UINT64 BootOptionSize
);
INTN
ParseNvrFile (
EFI_FILE_HANDLE NvrFile
);
EFI_STATUS
FindFreeBootOption(
CHAR16 *FreeIdx
);
INTN
RestoreNvr (
CHAR16* fileName
);
VOID
InitializeStdOut(
IN struct _EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Stash some of the efi stdout pointers
//
ConOut = SystemTable->ConOut;
ConIn = SystemTable->ConIn;
}
//
//
//
void
InitializeProtocols(
IN struct _EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_BOOT_SERVICES *bootServices;
EFI_RUNTIME_SERVICES *runtimeServices;
//
// Stash some of the handle protocol pointers
//
bootServices = SystemTable->BootServices;
HandleProtocol = bootServices->HandleProtocol;
LocateHandle = bootServices->LocateHandle;
LocateDevicePath = bootServices->LocateDevicePath;
LoadImage = bootServices->LoadImage;
StartImage = bootServices->StartImage;
//
// Stash some of the Runtime services pointers
//
runtimeServices = SystemTable->RuntimeServices;
SetVariable = runtimeServices->SetVariable;
}
EFI_STATUS
Init(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINTN BufferSize;
do {
//
// Initialize EFI routines
//
InitializeProtocols( SystemTable );
InitializeStdOut( SystemTable );
InitializeLib( ImageHandle, SystemTable );
//
// Save Image Handle
//
MenuImageHandle = ImageHandle;
BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, &ExeImage);
//
//
//
NvrOrder = AllocatePool(MAX_ENV_SIZE + 32);
if (! NvrOrder) {
Status = EFI_OUT_OF_RESOURCES;
break;
}
//
// get boot order from nvram
//
BufferSize = MAX_ENV_SIZE;
Status = RT->GetVariable (
VarBootOrder,
&EfiGlobalVariable,
&NvrAttributes,
&BufferSize,
NvrOrder
);
if (EFI_ERROR(Status)) {
Print(L"Nvr: failed to load boot order array. defaulting\n");
BufferSize = 0;
NvrAttributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
Status = EFI_SUCCESS;
}
//
// get how many boot options there are
//
NvrOrderCount = BufferSize / sizeof(UINT16);
} while ( FALSE );
return Status;
}
VOID
Shutdown(
VOID
)
{
if (NvrOrder) {
FreePool(NvrOrder);
}
}
EFI_STATUS
EfiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINT32 ch, user, cnt;
CHAR8 *LangCode;
// Initialize the EFI SDX libraries
InitializeLib( ImageHandle, SystemTable );
//
//
//
LangCode = LibGetVariable (VarLanguage, &EfiGlobalVariable);
if (LangCode) {
UINTN i;
Print(L"LangCode: ");
for (i = 0; i < ISO_639_2_ENTRY_SIZE; i++) {
Print(L"%c", LangCode[i]);
}
Print(L"\n");
FreePool(LangCode);
}
//
//
//
Status = Init(ImageHandle, SystemTable);
if (EFI_ERROR(Status)) {
return TRUE;
}
//
//
//
ch = cnt = 0;
user = 0;
while ( user != (UINT32) 'q' && ch <= (UINT32) 0xFF ) {
Print( L"Please press any key to continue (q to quit)\n");
user = GetInputKey();
if (user == L'q') {
break;
}
Print(L"Adding a boot entry\n");
RestoreNvr(L"blob.nvr");
}
//
// clean up
//
Shutdown();
// If you return the status, EFI will kindly give the user an English
// error message.
return TRUE;
}
UINT32 GetInputKey()
{
EFI_INPUT_KEY pKey;
EFI_STATUS Status;
// Wait until a keystroke is available
WaitForSingleEvent(
ST->ConIn->WaitForKey,
0);
// Read the key that has been pressed
Status = ST->ConIn->ReadKeyStroke(
ST->ConIn,
&pKey);
if (EFI_ERROR(Status) || pKey.ScanCode != 0) {
return 0x20; // space
}
return pKey.UnicodeChar;
}
EFI_STATUS
InsertBootOption(
VOID *BootOption,
UINT64 BootOptionSize
)
{
EFI_STATUS Status;
CHAR16 OptionStr[40];
Print(L"InsertBootOption: enter\n");
//
// attempt to insert boot option
//
do {
UINT16 Target;
//
//
//
Status = FindFreeBootOption(&Target);
if (EFI_ERROR(Status)) {
Print (L"Nvr: failed to find free boot option id: %hr\n", Status);
break;
}
//
// update nvram with the new boot option
//
SPrint( OptionStr, sizeof(OptionStr), VarBootOption, Target);
Print(L"InsertBootOption: target = %x, OptionStr = %s\n", Target, OptionStr);
Status = RT->SetVariable (
OptionStr,
&EfiGlobalVariable,
NvrAttributes,
BootOptionSize,
BootOption
);
if (EFI_ERROR(Status)) {
Print (L"Nvr: failed to add %hs - %hr\n", OptionStr, Status);
break;
}
//
// replace boot order with one including the new option
//
NvrOrder[NvrOrderCount] = Target;
NvrOrderCount++;
Status = RT->SetVariable (
VarBootOrder,
&EfiGlobalVariable,
NvrAttributes,
NvrOrderCount * sizeof(UINT16),
NvrOrder
);
if (EFI_ERROR(Status)) {
Print (L"Nvr: failed to update %hs - %hr\n", VarBootOrder, Status);
break;
}
#if 1
//
// validate what we just wrote
//
{
UINTN BlobSize;
CHAR8 *Blob;
UINT16 i;
BlobSize = BootOptionSize;
Blob = AllocatePool(BootOptionSize);
do {
Status = RT->GetVariable (
OptionStr,
&EfiGlobalVariable,
NULL,
&BlobSize,
Blob
);
if (EFI_ERROR(Status)) {
Print (L"Nvr: failed to read comparison blob: %hr\n", Status);
break;
}
for (i = 0; i < BootOptionSize; i++) {
if (((CHAR8*)BootOption)[i] != Blob[i]) {
Print(L"Nvr: diff[%d]: BootOption = %d, Blob = %d\n", i, ((CHAR8*)BootOption)[i], Blob[i]);
}
}
} while ( FALSE );
FreePool(Blob);
}
#endif
} while ( FALSE );
Print(L"InsertBootOption: exit\n");
return Status;
}
EFI_STATUS
FindFreeBootOption(
CHAR16 *FreeIdx
)
{
EFI_STATUS Status;
UINT16 id;
UINT16 i;
BOOLEAN Found;
BOOLEAN HaveFreeIdx;
Print(L"FindFreeBootOption: enter\n");
HaveFreeIdx = FALSE;
*FreeIdx = MAXUSHORT;
//
// use a brute force search to find a new boot option id
//
for ( id = 0; id <= MAXUSHORT; id++ ) {
Print(L"FindFreeBootOption: id = %x\n", id);
Found = FALSE;
for (i = 0; i < NvrOrderCount; i++) {
if (NvrOrder[i] == id) {
Found = TRUE;
break;
}
}
if (! Found) {
*FreeIdx = id;
HaveFreeIdx = TRUE;
break;
}
}
if (HaveFreeIdx) {
Status = EFI_SUCCESS;
} else {
Status = EFI_OUT_OF_RESOURCES;
}
Print(L"FindFreeBootOption: FreeIdx = %x, status = %x\n", *FreeIdx, Status);
Print(L"FindFreeBootOption: exit\n");
return Status;
}
INTN
RestoreNvr (
CHAR16* fileName
)
{
EFI_STATUS Status;
EFI_FILE_HANDLE nvrFile;
//
// Read from saved boot options file
//
Status = OpenCreateFile (EFI_FILE_MODE_READ,&nvrFile,fileName);
if (EFI_ERROR (Status)) {
Print(L"\nCan not open the file %s\n",fileName);
return Status;
}
//
// This updates nvram with saved boot options
//
return (ParseNvrFile (nvrFile));
}
EFI_STATUS
OpenCreateFile (
UINT64 OCFlags,
EFI_FILE_HANDLE* StartHdl,
CHAR16* Name
)
{
EFI_FILE_IO_INTERFACE *Vol;
EFI_FILE_HANDLE RootFs;
EFI_FILE_HANDLE CurDir;
EFI_FILE_HANDLE FileHandle;
CHAR16 FileName[100],*DevicePathAsString;
EFI_STATUS Status;
Print(L"OpenCreateFile: enter\n");
do {
//
// Open the volume for the device where the nvrutil was started.
//
Status = BS->HandleProtocol (
ExeImage->DeviceHandle,
&FileSystemProtocol,
&Vol
);
if (EFI_ERROR(Status)) {
Print(L"\n");
Print(L"Can not get a FileSystem handle for %s DeviceHandle\n",ExeImage->FilePath);
break;
}
Status = Vol->OpenVolume (Vol, &RootFs);
if (EFI_ERROR(Status)) {
Print(L"\n");
Print(L"Can not open the volume for the file system\n");
break;
}
CurDir = RootFs;
//
// Open saved boot options file
//
FileName[0] = 0;
DevicePathAsString = DevicePathToStr(ExeImage->FilePath);
if (DevicePathAsString!=NULL) {
StrCpy(FileName,DevicePathAsString);
FreePool(DevicePathAsString);
}
StrCpy(FileName, L".\\");
StrCat(FileName,Name);
Status = CurDir->Open (CurDir,
&FileHandle,
FileName,
OCFlags,
0
);
*StartHdl=FileHandle;
} while ( FALSE );
Print(L"OpenCreateFile: exit\n");
return Status;
}
INTN
ParseNvrFile (
EFI_FILE_HANDLE NvrFile
)
{
BOOLEAN bSuccess;
EFI_STATUS Status;
CHAR8 *buffer;
UINTN k,size;
UINT64 BootNumber;
UINT64 BootSize;
VOID *BootOption;
UINTN blockBegin;
EFI_FILE_INFO *fileInfo;
Print(L"ParseNvrFile: enter\n");
buffer = NULL;
do {
//
//
//
size = 0;
Status = NvrFile->GetInfo(NvrFile,&GenericFileInfo,&size,NULL);
if (Status != EFI_BUFFER_TOO_SMALL) {
break;
}
Print(L"ParseNvrFile: size = %d vs %d\n", size, SIZE_OF_EFI_FILE_INFO+255*sizeof (CHAR16));
fileInfo = AllocateZeroPool(size);
if (fileInfo == NULL) {
Print(L"\n");
Print (L"Failed to allocate memory for File Info buffer!\n");
Status = EFI_OUT_OF_RESOURCES;
break;
}
//
//
//
Status = NvrFile->GetInfo(NvrFile,&GenericFileInfo,&size,fileInfo);
size=(UINTN) fileInfo->FileSize;
FreePool (fileInfo);
buffer = AllocateZeroPool ((size+1));
if (buffer == NULL) {
Print(L"\n");
Print (L"Failed to allocate memory for File buffer!\n");
Status = EFI_OUT_OF_RESOURCES;
break;
}
Status = NvrFile->Read(NvrFile,&size,buffer);
NvrFile->Close (NvrFile);
if (EFI_ERROR (Status)) {
Print(L"\n");
Print (L"Failed to read nvr file!\n");
break;
}
//
//
//
k=0;
while(k < size ) {
blockBegin = k;
CopyMem( &BootNumber, &buffer[k], sizeof(BootNumber));
k += sizeof(UINT64);
CopyMem( &BootSize, &buffer[k], sizeof(BootSize));
k += sizeof(UINT64);
BootOption = (VOID *)((CHAR8*)buffer + k);
k += BootSize;
//
// sanity check the file position vs. what the
// file header information tells us. The value
// k should be <= to size now.
//
if (k > size) {
Print (L"\nThe NVRAM file is corrupted.\n");
Status = EFI_BAD_BUFFER_SIZE;
break;
}
//
// write the current boot entry at free location
//
Status = InsertBootOption(
BootOption,
BootSize
);
if (EFI_ERROR(Status)) {
Print(L"\nError: Failed to append new boot entry to boot order array\n");
break;
}
}
} while ( FALSE );
if (buffer) {
FreePool (buffer);
}
Print(L"ParseNvrFile: exit\n");
return Status;
}