#include #include #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; }