|
|
/*++
Module Name:
nvrio.c
Abstract:
Access function to r/w environment variables from NVRAM
Author:
Mudit Vats (v-muditv) 12-13-99
Revision History:
--*/ #include <precomp.h>
#define FIELD_OFFSET(type, field) ((UINT32)(UINTN)&(((type *)0)->field))
#define ALIGN_DOWN(length, type) \
((UINT32)(length) & ~(sizeof(type) - 1))
#define ALIGN_UP(length, type) \
(ALIGN_DOWN(((UINT32)(length) + sizeof(type) - 1), type))
#define EFI_ATTR EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
VOID* LoadOptions [MAXBOOTVARS]; UINT64 LoadOptionsSize [MAXBOOTVARS];
VOID* BootOrder; UINT64 BootOrderCount; UINT64 OsBootOptionCount;
#define LOAD_OPTION_ACTIVE 0x00000001
INT32 SafeWcslen ( CHAR16 *String, CHAR16 *Max ) { CHAR16 *p = String; while ( (p < Max) && (*p != 0) ) { p++; }
if ( p < Max ) { return(UINT32)(p - String); }
return -1;
} // SafeWclen
#define ISWINDOWSOSCHECK_DEBUG 0
BOOLEAN isWindowsOsBootOption( char* elo, UINT64 eloSize ) //
// Purpose: determine if the EFI_LOAD_OPTION structure in question is referring to
// a Windows OS boot option
//
// Return:
//
// TRUE elo refers to a Windows OS option
//
{ CHAR16 *max; INT32 l; UINTN length; PEFI_LOAD_OPTION pElo; char* devicePath; char* osOptions; PWINDOWS_OS_OPTIONS pOsOptions; char* aOsOptions; BOOLEAN status;
status = TRUE; aOsOptions = NULL;
pElo = (EFI_LOAD_OPTION*)elo;
if ( eloSize < sizeof(EFI_LOAD_OPTION) ) { status = FALSE; goto Done; }
#if ISWINDOWSOSCHECK_DEBUG
Print( L"Is %s a Windows OS boot option?\n", pElo->Description ); #endif
//
// Is the description properly terminated?
//
max = (CHAR16 *)(elo + eloSize); l = SafeWcslen( pElo->Description, max ); if ( l < 0 ) { #if ISWINDOWSOSCHECK_DEBUG
Print (L"Failed: SafeWcslen( pElo->Description, max )\n"); #endif
status = FALSE; goto Done; }
//
// get the WINDOWS_OS_OPTIONS structure from the OptionalData field
//
osOptions = elo + FIELD_OFFSET(EFI_LOAD_OPTION,Description) + StrSize(pElo->Description) + pElo->FilePathListLength; length = (UINTN)eloSize; length -= (UINTN)(osOptions - elo); #if ISWINDOWSOSCHECK_DEBUG
Print (L"length = %x\n", length); #endif
//
// make sure osOptions are atleast the size of the
// WINDOWS_OS_OPTIONS header
//
//
if ( length < FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions) ) { #if ISWINDOWSOSCHECK_DEBUG
Print (L"Failed: invalid length: %x\n", length); #endif
status = FALSE; goto Done; }
//
// align the os options
//
aOsOptions = GetAlignedOsOptions(elo, eloSize); pOsOptions = (WINDOWS_OS_OPTIONS*)aOsOptions;
#if ISWINDOWSOSCHECK_DEBUG
DisplayOsOptions(aOsOptions); #endif
//
// Does the OsOptions structure look like a WINDOWS_OS_OPTIONS structure?
//
if ( (length != pOsOptions->Length) || (WINDOWS_OS_OPTIONS_VERSION != pOsOptions->Version) || (strcmpa(pOsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) != 0) ) { #if ISWINDOWSOSCHECK_DEBUG
Print (L"Failed: OsOptions doesn't look like WINDOWS_OS_OPTIONS structure.\n"); Print (L"test1: %x\n", length != pOsOptions->Length); Print (L"test2: %x\n", WINDOWS_OS_OPTIONS_VERSION != pOsOptions->Version); Print (L"test3: %x\n", strcmpa(pOsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) != 0 ); #endif
status = FALSE; goto Done; } //
// Is the OsLoadOptions string properly terminated?
//
//
// create a new max ptr to accomodate the fact that we are
// now using an aligned copy of OsOptions from the Pool
//
max = (CHAR16*)(aOsOptions + pOsOptions->Length);
#if ISWINDOWSOSCHECK_DEBUG
Print (L"max = %x, osloadoptions = %x, diff = %x, strsize=%x\n", max, pOsOptions->OsLoadOptions, (char*)max - (char*)pOsOptions->OsLoadOptions, StrSize(pOsOptions->OsLoadOptions) ); #endif
l = SafeWcslen( pOsOptions->OsLoadOptions, max ); if ( l < 0 ) { #if ISWINDOWSOSCHECK_DEBUG
Print (L"Failed: SafeWcslen( osLoadOptions, max ) = %x\n", l); #endif
status = FALSE; goto Done; }
Done: //
// we are done with the os options
//
if (aOsOptions != NULL) { FreePool(aOsOptions); }
return status; }
#define GETBOOTVARS_DEBUG 0
VOID GetBootManagerVars( ) { UINT32 i,j; CHAR16 szTemp[10]; VOID* bootvar; UINT64 BootOrderSize = 0;
//
// Initialize EFI LoadOptions.
//
BootOrderSize = 0; BootOrderCount = 0; OsBootOptionCount = 0; BootOrder = NULL;
#if 0
ZeroMem( LoadOptions, sizeof(VOID*) * MAXBOOTVARS ); ZeroMem( LoadOptionsSize, sizeof(UINT64) * MAXBOOTVARS ); #endif
//
// Ensure that the Load Options have been freed
//
ASSERT(BootOrderCount == 0);
//
// Get BootOrder.
//
BootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &BootOrderSize );
if ( BootOrder ) {
BootOrderCount = BootOrderSize / sizeof(CHAR16);
#if GETBOOTVARS_DEBUG
Print (L"BootOrderCount = %x\n", BootOrderCount); #endif
//
// Get the boot options.
//
for ( i=0; i<BootOrderCount; i++ ) { SPrint( szTemp, sizeof(szTemp), L"Boot%04x", ((CHAR16*) BootOrder)[i] );
ASSERT(LoadOptions[i] == NULL); ASSERT(LoadOptionsSize[i] == 0);
LoadOptions[i] = LibGetVariableAndSize( szTemp, &VenEfi, &(LoadOptionsSize[i]) );
#if GETBOOTVARS_DEBUG
Print (L"i = %x, szTemp = %s, BOCnt = %x, LOptions = %x, BSize = %x\n", i, szTemp, OsBootOptionCount, LoadOptions[i], LoadOptionsSize[i] ); #endif
OsBootOptionCount++; } } }
#define ERASEBOOTOPT_DEBUG 0
BOOLEAN EraseOsBootOption( UINTN BootVarNum ) { UINTN j; CHAR16 szTemp[10]; CHAR16* tmpBootOrder; VOID* bootvar; UINT64 BootOrderSize = 0; VOID* pDummy; UINTN dummySize;
//
// Initialize EFI LoadOptions.
//
BootOrderSize = 0; BootOrderCount = 0; BootOrder = NULL;
//
// Get BootOrder.
//
BootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &BootOrderSize );
BootOrderCount = BootOrderSize / sizeof(CHAR16);
ASSERT(BootOrderCount == OsBootOptionCount); ASSERT(BootVarNum < MAXBOOTVARS); ASSERT(BootOrderCount >= 1); #if ERASEBOOTOPT_DEBUG
Print (L"BootOrderCount = %x\n", BootOrderCount); Print (L"BootVarNum = %x\n", BootVarNum); #endif
//
// if the boot option is populated, then erase it
//
if (LoadOptions[BootVarNum]) {
//
// free the local load option
//
FreePool(LoadOptions[BootVarNum]);
//
// zero the local memory for the load options
//
LoadOptions[BootVarNum] = (VOID*)0; LoadOptionsSize[BootVarNum] = 0;
//
// Get the boot option
//
SPrint( szTemp, sizeof(szTemp), L"Boot%04x", ((CHAR16*) BootOrder)[BootVarNum] );
#if ERASEBOOTOPT_DEBUG
Print (L"BootXXXX = %s\n", szTemp); #endif
pDummy = LibGetVariableAndSize( szTemp, &VenEfi, &dummySize ); //
// whack the nvram entry
//
SetVariable( szTemp, &VenEfi, EFI_ATTR, 0, NULL );
#if ERASEBOOTOPT_DEBUG
Print (L"Adjusting boot order [begin]\n"); #endif
//
// adjust the counters for os boot options
//
OsBootOptionCount--; BootOrderCount--;
//
// Shift the remaining entries in the boot order and the load options
//
tmpBootOrder = (CHAR16*)BootOrder;
for (j = BootVarNum; j < BootOrderCount; j++) { tmpBootOrder[j] = tmpBootOrder[j + 1]; LoadOptions[j] = LoadOptions[j + 1]; LoadOptionsSize[j] = LoadOptionsSize[j + 1];
} //
// Set the modified boot order
//
SetVariable( L"BootOrder", &VenEfi, EFI_ATTR, BootOrderCount * sizeof(CHAR16), BootOrder );
#if ERASEBOOTOPT_DEBUG
Print (L"Adjusting boot order [end]\n"); #endif
return TRUE;
} return FALSE; }
BOOLEAN EraseAllOsBootOptions( ) { UINT32 i; UINT64 BootOrderSize = 0; BOOLEAN status; UINT64 maxBootCount; #if ERASEBOOTOPT_DEBUG
CHAR16 szInput[1024]; #endif
//
// Initialize EFI LoadOptions.
//
BootOrderSize = 0; BootOrderCount = 0; BootOrder = NULL;
//
// Get BootOrder.
//
BootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &BootOrderSize ); BootOrderCount = BootOrderSize / sizeof(CHAR16); ASSERT(BootOrderCount == OsBootOptionCount);
//
// Make sure there is atleast one OS boot option
//
if ( BootOrder && OsBootOptionCount) {
maxBootCount = BootOrderCount;
//
// erase invidual boot options.
//
for ( i = 0; i < maxBootCount; i++ ) { #if ERASEBOOTOPT_DEBUG
Print (L"BootOrderCount = %x, Erasing boot option: %x\n", BootOrderCount, i); #endif
//
// remove the boot entry at the head of the list
//
status = EraseOsBootOption(0); #if ERASEBOOTOPT_DEBUG
Input (L"Here!\n", szInput, sizeof(szInput)); Print(L"\n"); #endif
if (status == FALSE) {
Print (L"Error: failed to erase boot entry %x\n", i);
break;
} } } return status; }
BOOLEAN PushToTop( IN UINT32 BootVarNum ) { UINT32 i; CHAR16 szTemp[10]; char* osbootoption; UINT64 osbootoptionsize; CHAR16 savBootOption; CHAR16* tmpBootOrder; UINT64 BootOrderSize = 0;
i=0; BootOrderSize = 0; BootOrder = NULL;
//
// Get BootOrder.
//
BootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &BootOrderSize );
//
// Make sure there is atleast one OS boot option
//
if ( BootOrder && OsBootOptionCount) {
BootOrderCount = BootOrderSize / sizeof(CHAR16);
//
// Get the boot option.
//
tmpBootOrder = (CHAR16*)BootOrder; savBootOption = tmpBootOrder[BootVarNum]; SPrint( szTemp, sizeof(szTemp), L"Boot%04x", savBootOption );
osbootoption = LibGetVariableAndSize( szTemp, &VenEfi, &osbootoptionsize ); //
// Now adjust the boot order
//
i=BootVarNum; while (i > 0) { tmpBootOrder[i] = tmpBootOrder[i-1]; i--; }
tmpBootOrder[0] = savBootOption; //
// Set the changed boot order
//
SetVariable( L"BootOrder", &VenEfi, EFI_ATTR, BootOrderCount * sizeof(CHAR16), BootOrder ); return TRUE; } return FALSE; }
VOID FreeBootManagerVars( ) { UINTN i;
for ( i=0; i<BootOrderCount; i++ ) { if ( LoadOptions[i] ) FreePool( LoadOptions[i] ); }
if ( BootOrder ) FreePool( BootOrder );
//
// zero the local memory for the load options
//
ZeroMem( LoadOptions, sizeof(VOID*) * MAXBOOTVARS ); ZeroMem( LoadOptionsSize, sizeof(UINT64) * MAXBOOTVARS );
}
BOOLEAN CopyVar( IN UINT32 VarNum ) { CHAR16 i;
if ( VarNum < BootOrderCount ) {
LoadOptions[BootOrderCount] = AllocateZeroPool( LoadOptionsSize[VarNum] );
if ( LoadOptions[BootOrderCount] && LoadOptions[VarNum] ) {
CopyMem( LoadOptions[BootOrderCount], LoadOptions[VarNum], LoadOptionsSize[VarNum] ); LoadOptionsSize[BootOrderCount] = LoadOptionsSize[VarNum];
BootOrder = ReallocatePool( (VOID*) BootOrder, BootOrderCount * sizeof(CHAR16), ( BootOrderCount + 1 ) * sizeof(CHAR16) );
((CHAR16*) BootOrder)[BootOrderCount] = FindFreeBootOption();
BootOrderCount++; OsBootOptionCount++; return TRUE; } else return FALSE; } return FALSE; }
CHAR16 FindFreeBootOption( ) { CHAR16 i; CHAR16 BootOptionBitmap[MAXBOOTVARS];
SetMem( BootOptionBitmap, sizeof(BootOptionBitmap), 0 );
for ( i=0; i<BootOrderCount; i++ ) { BootOptionBitmap[ ((CHAR16*)BootOrder)[i] ] = 1; }
for ( i=0; i < MAXBOOTVARS; i++ ) { if ( BootOptionBitmap[i] == 0 ) return i; }
return 0xFFFF; }
BOOLEAN SetBootManagerVar( UINTN BootVarNum ) { CHAR16 szTemp[50]; BOOLEAN status;
status = TRUE;
SPrint( szTemp, sizeof(szTemp), L"Boot%04x", ((CHAR16*) BootOrder)[BootVarNum] ); if (LoadOptions[BootVarNum]) { SetVariable( szTemp, &VenEfi, EFI_ATTR, LoadOptionsSize[BootVarNum], LoadOptions[BootVarNum] ); SetVariable( L"BootOrder", &VenEfi, EFI_ATTR, BootOrderCount * sizeof(CHAR16), BootOrder ); } else { status = FALSE; }
return status; }
VOID SetBootManagerVars( ) { UINTN BootVarNum; BOOLEAN status;
for ( BootVarNum = 0; BootVarNum < BootOrderCount; BootVarNum++ ) {
status = SetBootManagerVar(BootVarNum);
if (status == FALSE) { Print (L"ERROR: Attempt to write non-existent boot option to NVRAM!\n"); } } }
UINT64 GetBootOrderCount( ) { return BootOrderCount; }
UINT64 GetOsBootOptionsCount( ) { return OsBootOptionCount; }
VOID SetEnvVar( IN CHAR16* szVarName, IN CHAR16* szVarValue, IN UINT32 deleteOnly ) /*
deleteOnly TRUE - Env var szVarName is deleted from nvr. FALSE - Env var szVarName overwrites or creates */ { EFI_STATUS status;
//
// Erase the previous value
//
SetVariable( szVarName, &VenEfi, 0, 0, NULL );
if ( !deleteOnly ) {
//
// Store the new value
//
status = SetVariable( szVarName, &VenEfi, EFI_ATTR, StrSize( szVarValue ), szVarValue ); } }
VOID SubString( IN OUT char* Dest, IN UINT32 Start, IN UINT32 End, IN char* Src ) { UINTN i; UINTN j=0;
for ( i=Start; i<End; i++ ) { Dest[ j++ ] = Src[ i ]; }
Dest[ j ] = '\0'; }
VOID InsertString( IN OUT char* Dest, IN UINT32 Start, IN UINT32 End, IN char* InsertString ) { UINT32 i; UINT32 j=0; char first[1024]; char last[1024];
SubString( first, 0, Start, Dest ); SubString( last, End, (UINT32) StrLenA(Dest), Dest );
StrCatA( first, InsertString ); StrCatA( first, last );
StrCpyA( Dest, first ); }
VOID UtoA( OUT char* c, IN CHAR16* u ) { UINT32 i = 0;
while ( u[i] ) { c[i] = u[i] & 0xFF; i++; }
c[i] = '\0'; }
VOID AtoU( OUT CHAR16* u, IN char* c ) { UINT32 i = 0;
while ( c[i] ) { u[i] = (CHAR16)c[i]; i++; }
u[i] = (CHAR16)'\0'; }
VOID SetFieldFromLoadOption( IN UINT32 BootVarNum, IN UINT32 FieldType, IN VOID* Data ) { CHAR16 LoadIdentifier[200]; char OsLoadOptions[200]; char EfiFilePath[1024]; char OsLoadPath[1024];
//
// Make sure it is a valid OS load option
//
if (BootVarNum >= BootOrderCount) return ; if (LoadOptions[BootVarNum] == NULL) return;
GetOsLoadOptionVars( BootVarNum, LoadIdentifier, OsLoadOptions, EfiFilePath, OsLoadPath );
//
// Set the field.
//
switch (FieldType) { case DESCRIPTION: StrCpy( LoadIdentifier, Data ); break;
case OSLOADOPTIONS: StrCpy( (CHAR16*)OsLoadOptions, (CHAR16*)Data ); break;
#if 0
case EFIFILEPATHLIST: SetFilePathFromShort( (EFI_DEVICE_PATH*) EfiFilePath, (CHAR16*) Data ); break;
case OSFILEPATHLIST: {
PFILE_PATH pFilePath; pFilePath = (FILE_PATH*)OsLoadPath; SetFilePathFromShort( (EFI_DEVICE_PATH*) pFilePath->FilePath, (CHAR16*) Data );
break; } #endif
default: break;
}
//
// Pack the new parameters into the the current load option
//
PackLoadOption( BootVarNum, LoadIdentifier, (CHAR16*)OsLoadOptions, EfiFilePath, OsLoadPath );
//
// save the new load option into NVRAM
//
SetBootManagerVar(BootVarNum);
}
VOID GetFilePathShort( EFI_DEVICE_PATH *FilePath, CHAR16 *FilePathShort ) { UINT32 i, j, End; EFI_DEVICE_PATH *n = FilePath;
//
// Advance to FilePath node.
//
while (( n->Type != END_DEVICE_PATH_TYPE ) && ( n->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ) ) {
if (( n->Type == MEDIA_DEVICE_PATH ) && ( n->SubType == MEDIA_FILEPATH_DP )) {
j = 0; End = DevicePathNodeLength(n);
for ( i=sizeof(EFI_DEVICE_PATH); i<End; i++ ) { ((char*) FilePathShort)[j++] = ( (char*) n)[i]; }
break; }
n = NextDevicePathNode(n); } }
VOID SetFilePathFromShort( EFI_DEVICE_PATH *FilePath, CHAR16* FilePathShort ) { UINT32 i, j, End; EFI_DEVICE_PATH *n = FilePath; UINT64 DevicePathSize;
//
// Advance to FilePath node.
//
while (( n->Type != END_DEVICE_PATH_TYPE ) && ( n->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ) ) {
if (( n->Type == MEDIA_DEVICE_PATH ) && ( n->SubType == MEDIA_FILEPATH_DP )) {
j = 0; End = DevicePathNodeLength(n);
//
// Set the new file path
//
DevicePathSize = GetDevPathSize(n); for ( i=sizeof(EFI_DEVICE_PATH); i<DevicePathSize; i++ ) { ((char*) n)[i] = 0; }
j=sizeof(EFI_DEVICE_PATH);
for ( i=0; i<StrSize(FilePathShort); i++ ) { ((char*)n)[j++] = ((char*)FilePathShort)[i]; }
SetDevicePathNodeLength( n, StrSize(FilePathShort) + sizeof(EFI_DEVICE_PATH) );
n = NextDevicePathNode(n); SetDevicePathEndNode(n); break; }
n = NextDevicePathNode(n); } }
char* GetAlignedELOFilePath( char* elo ) { UINTN abufSize; char* abuf; PEFI_LOAD_OPTION pElo; pElo = (EFI_LOAD_OPTION*)elo;
abufSize = pElo->FilePathListLength;
abuf = AllocatePool(abufSize);
CopyMem(abuf, elo + FIELD_OFFSET(EFI_LOAD_OPTION, Description) + StrSize(pElo->Description), abufSize );
return abuf; }
char* GetAlignedOptionalData( char* elo, UINT64 eloSize, UINT64* dataSize ) { UINTN abufSize; char* abuf; PEFI_LOAD_OPTION pElo; UINTN offset; pElo = (EFI_LOAD_OPTION*)elo;
offset = FIELD_OFFSET(EFI_LOAD_OPTION, Description) + StrSize(pElo->Description) + pElo->FilePathListLength;
abufSize = eloSize - offset; abuf = AllocatePool(abufSize);
CopyMem(abuf, elo + offset, abufSize );
*dataSize = abufSize;
return abuf; }
char* GetAlignedOsOptions( char* elo, UINT64 eloSize ) { UINT64 dummy; char* abuf;
abuf = GetAlignedOptionalData(elo, eloSize, &dummy );
return abuf; }
char* GetAlignedOsLoadPath( IN char* osOptions, OUT UINTN* osLoadPathSize ) //
// we need to align the FilePath structure because the load options are
// variable in length, so the FilePath structure may not be aligned
//
{ UINTN abufSize; char* abuf; PWINDOWS_OS_OPTIONS pOsOptions;
pOsOptions = (WINDOWS_OS_OPTIONS*)osOptions;
abufSize = pOsOptions->Length - FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions) - StrSize(pOsOptions->OsLoadOptions);
abuf = AllocatePool(abufSize);
CopyMem(abuf, &osOptions[pOsOptions->OsLoadPathOffset], abufSize );
*osLoadPathSize = abufSize;
return abuf; }
VOID DisplayLoadPath( char* osLoadPath ) { PFILE_PATH pFilePath; pFilePath = (FILE_PATH*)osLoadPath; Print (L"osOptions->FILE_PATH->Version = %x\n", pFilePath->Version); Print (L"osOptions->FILE_PATH->Length = %x\n", pFilePath->Length); Print (L"osOptions->FILE_PATH->Type = %x\n", pFilePath->Type); if (pFilePath->Type == FILE_PATH_TYPE_EFI) {
CHAR16 FilePathShort[200];
GetFilePathShort( (EFI_DEVICE_PATH *)pFilePath->FilePath, FilePathShort );
Print (L"osOptions->FILE_PATH->FilePath(EFI:DP:Short) = %s\n", FilePathShort);
} }
VOID DisplayOsOptions( char* osOptions ) { PWINDOWS_OS_OPTIONS pOsOptions; CHAR16 wideSig[256]; char* aOsLoadPath; UINTN aOsLoadPathSize;
pOsOptions = (WINDOWS_OS_OPTIONS*)osOptions;
Print (L">>>>\n");
//
// display the attributes
//
AtoU(wideSig, pOsOptions->Signature);
Print (L"osOptions->Signature = %s\n", wideSig); Print (L"osOptions->Version = %x\n", pOsOptions->Version); Print (L"osOptions->Length = %x\n", pOsOptions->Length); Print (L"osOptions->OsLoadPathOffset = %x\n", pOsOptions->OsLoadPathOffset);
// display the os load options
Print (L"osOptions->OsLoadOptions = %s\n", pOsOptions->OsLoadOptions);
//
// display the FILE PATH
//
//
// we need to align the FilePath structure because the load options are
// variable in length, so the FilePath structure may not be aligned
//
aOsLoadPath = GetAlignedOsLoadPath(osOptions, &aOsLoadPathSize);
DisplayLoadPath(aOsLoadPath);
FreePool(aOsLoadPath);
Print (L"<<<<\n");
}
VOID DisplayELO( char* elo, UINT64 eloSize ) { PEFI_LOAD_OPTION pElo; #if 0
UINT64 eloSize; #endif
CHAR16 FilePathShort[200]; char* aOsOptions;
pElo = (EFI_LOAD_OPTION*)elo;
Print (L"elo->Attributes = %x\n", pElo->Attributes); Print (L"elo->FilePathListLength = %x\n", pElo->FilePathListLength); Print (L"elo->Description = %s\n", pElo->Description);
GetFilePathShort( (EFI_DEVICE_PATH *)&elo[FIELD_OFFSET(EFI_LOAD_OPTION, Description) + StrSize(pElo->Description)], FilePathShort ); Print (L"elo->FilePath(EFI:DP:SHORT) = %s\n", FilePathShort);
#if 0
eloSize = FIELD_OFFSET(EFI_LOAD_OPTION, Description) + StrSize(pElo->Description) + pElo->FilePathListLength; DisplayOsOptions(&elo[eloSize]); #else
aOsOptions = GetAlignedOsOptions( elo, eloSize );
DisplayOsOptions(aOsOptions); FreePool(aOsOptions);
#endif
}
VOID BuildNewOsOptions( IN CHAR16* osLoadOptions, IN char* osLoadPath, OUT char** osOptions ) //
//
// Note: osLoadPath must be aligned
//
{ char* newOsOptions; PWINDOWS_OS_OPTIONS pNewOsOptions; UINT32 osLoadOptionsLength; UINT32 osOptionsLength; PFILE_PATH pOsLoadPath;
//
// NOTE: aligning the FILE_PATH structure (osLoadPath) works
// by aligning the osLoadOptionsLength because the
// WINDOWS_OS_OPTIONS structure has a UINT32 variable
// before the OsLoadOptions. If anything changes above
// the OsLoadOptions in the WINDOWS_OS_OPTIONS structure
// the alignment method may have to change in this structure.
//
//
//
// determine the size of the os load options (UNICODE) string
//
osLoadOptionsLength = (UINT32)StrSize(osLoadOptions); osLoadOptionsLength = ALIGN_UP(osLoadOptionsLength, UINT32);
#if DEBUG_PACK
Print (L"osLoadOptionsLength = %x\n", osLoadOptionsLength); #endif
pOsLoadPath = (FILE_PATH*)osLoadPath;
#if DEBUG_PACK
Print (L"pOsLoadPath->Length = %x\n", pOsLoadPath->Length); #endif
//
// determine the size of the new WINDOWS_OS_OPTIONS structure
//
osOptionsLength = FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions) + osLoadOptionsLength + pOsLoadPath->Length; #if DEBUG_PACK
Print (L"osOptionsLength = %x\n", osOptionsLength); #endif
//
// Allocate memory for the WINDOWS_OS_OPTIONS
//
newOsOptions = AllocatePool(osOptionsLength);
ASSERT(newOsOptions != NULL);
pNewOsOptions = (WINDOWS_OS_OPTIONS*)newOsOptions;
//
// populate the new os options
//
StrCpyA((char *)pNewOsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE); pNewOsOptions->Version = WINDOWS_OS_OPTIONS_VERSION; pNewOsOptions->Length = (UINT32)osOptionsLength; pNewOsOptions->OsLoadPathOffset = FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions) + osLoadOptionsLength; StrCpy(pNewOsOptions->OsLoadOptions, osLoadOptions); CopyMem( &newOsOptions[pNewOsOptions->OsLoadPathOffset], osLoadPath, pOsLoadPath->Length ); *osOptions = newOsOptions; }
VOID PackLoadOption( IN UINT32 BootVarNum, IN CHAR16* LoadIdentifier, IN CHAR16* OsLoadOptions, IN char* EfiFilePath, IN char* OsLoadPath ) /*
PackLoadOption Purpose: To construct an EFI_LOAD_OPTION structure using user arguments and load the structure into into BootXXXX, where XXXX = BootVarNum. See EFI spec, ch. 17 Args: BootVarNum The boot option being written/modified */ { PEFI_LOAD_OPTION pOldElo; PEFI_LOAD_OPTION pElo; char* elo; char* oldElo; UINT64 oldEloSize; UINT64 eloSize; UINT8* oldEloFilePath; UINT64 TempEfiFilePathListSize; char* aFilePath;
#if DEBUG_PACK
CHAR16 szInput[1024];
Print (L"BootVarNum = %x\n", BootVarNum); Print (L"LoadIdentifier = %s\n", LoadIdentifier); Print (L"OsLoadOptions = %s\n", OsLoadOptions);
Input (L"Here! [Pack begin] \n", szInput, sizeof(szInput)); Print(L"\n");
#endif
oldElo = LoadOptions[BootVarNum]; oldEloSize = LoadOptionsSize[BootVarNum];
#if DEBUG_PACK
DisplayELO(oldElo, oldEloSize); Input (L"Here! [Pack begin] \n", szInput, sizeof(szInput)); Print(L"\n");
#endif
//
// allocate the elo structure with maximal amount of memory allowed for
// an EFI_LOAD_OPTION
//
elo = AllocatePool(MAXBOOTVARSIZE); if (elo == NULL) { Print (L"PackAndWriteToNvr: AllocatePool\n"); return; }
pElo = (EFI_LOAD_OPTION*)elo; pOldElo = (EFI_LOAD_OPTION*)oldElo;
//
// Efi Attribute.
//
pElo->Attributes = pOldElo->Attributes; eloSize = sizeof(UINT32);
//
// FilePathListLength
//
pElo->FilePathListLength = pOldElo->FilePathListLength; eloSize += sizeof(UINT16);
//
// Description.
//
StrCpy( pElo->Description, LoadIdentifier ); eloSize += StrSize(LoadIdentifier);
//
// copy the FilePath from the old/existing ELO structure
//
// Note: we don't actually need an aligned filepath block for this
// copy, but there may come a time when we want to modify
// the filepath, which will require an aligned block.
//
aFilePath = GetAlignedELOFilePath(oldElo); CopyMem( &elo[eloSize], aFilePath, pOldElo->FilePathListLength ); eloSize += pOldElo->FilePathListLength; FreePool(aFilePath);
#if DEBUG_PACK
Print (L"eloSize = %x\n", eloSize); Input (L"Here! \n", szInput, sizeof(szInput)); Print(L"\n");
#endif
//
// add or modify the boot option
//
if ( BootVarNum == -1 ) {
Print(L"Adding currently disabled\n");
} else { char* osOptions; char* aOsLoadPath; char* aOldOsOptions; PWINDOWS_OS_OPTIONS pOldOsOptions; PWINDOWS_OS_OPTIONS pOsOptions; UINTN aOsLoadPathSize;
//
// OptionalData.
//
// For a Windows OS boot option, the OptionalData field in the EFI_LOAD_OPTION
// structure is a WINDOWS_OS_OPTION structure.
//
// get the WINDOWS_OS_OPTIONS from the old/existing boot entry
//
aOldOsOptions = GetAlignedOsOptions(oldElo, oldEloSize); pOldOsOptions = (WINDOWS_OS_OPTIONS*)aOldOsOptions;
//
// Get the LoadPath from the old/existing WINDOWS_OS_OPTIONS structure
//
// we need to align the FilePath structure because the load options are
// variable in length, so the FilePath structure may not be aligned
//
aOsLoadPath = GetAlignedOsLoadPath(aOldOsOptions, &aOsLoadPathSize);
FreePool(aOldOsOptions); //
// Construct a new WINDOWS_OS_STRUCTURE with the new values
//
BuildNewOsOptions( OsLoadOptions, aOsLoadPath, &osOptions ); FreePool(aOsLoadPath); #if DEBUG_PACK
Input (L"build\n", szInput, sizeof(szInput) ); Print(L"\n");
DisplayOsOptions(osOptions); Input (L"elo freed\n", szInput, sizeof(szInput) ); Print(L"\n");
#endif
pOsOptions = (WINDOWS_OS_OPTIONS*)osOptions;
//
// Copy the new WINDOWS_OS_OPTIONS structure into the new EFI_LOAD_OPTION structure
//
CopyMem( &elo[eloSize], osOptions, pOsOptions->Length);
eloSize += pOsOptions->Length; #if DEBUG_PACK
Print (L"osOptions->Length = %x\n", pOsOptions->Length); Print (L"eloSize = %x\n", eloSize); #endif
FreePool(osOptions);
//
// Modify current boot options.
//
LoadOptions[BootVarNum] = ReallocatePool( LoadOptions[BootVarNum], LoadOptionsSize[BootVarNum], eloSize ); LoadOptionsSize[BootVarNum] = eloSize;
CopyMem( LoadOptions[BootVarNum], elo, eloSize ); }
FreePool(elo);
ASSERT(eloSize < MAXBOOTVARSIZE);
#if DEBUG_PACK
Input (L"elo freed\n", szInput, sizeof(szInput) ); Print(L"\n"); Print (L">>\n"); DisplayELO((char*)LoadOptions[BootVarNum], LoadOptionsSize[BootVarNum]); Print (L"<<\n"); Input (L"pack done\n", szInput, sizeof(szInput) ); Print(L"\n"); #endif
}
EFI_STATUS AppendEntryToBootOrder( UINT16 BootNumber ) { EFI_STATUS status; UINT64 oldBootOrderSize; UINT64 newBootOrderSize; VOID* newBootOrder; VOID* oldBootOrder;
newBootOrder = NULL; oldBootOrder = NULL;
//
// get the existing boot order array
//
oldBootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &oldBootOrderSize ); if ((!oldBootOrder) && (oldBootOrderSize != 0) ) { Print(L"\nError: Failed to get old boot order array.\n"); status = EFI_OUT_OF_RESOURCES; goto Done; }
//
// allocate the new boot order array
//
newBootOrderSize = oldBootOrderSize + sizeof(BootNumber); newBootOrder = AllocatePool( newBootOrderSize ); if (! newBootOrder) { Print(L"\nError: Failed to allocate new boot order array.\n"); status = EFI_OUT_OF_RESOURCES; goto Done; }
//
// append the new boot entry to the bottom of the list
//
CopyMem( (CHAR8*)newBootOrder, oldBootOrder, oldBootOrderSize ); CopyMem( (CHAR8*)newBootOrder + oldBootOrderSize, &BootNumber, sizeof(BootNumber) );
status = SetVariable( L"BootOrder", &VenEfi, EFI_ATTR, newBootOrderSize, newBootOrder );
Done:
if (oldBootOrder) { FreePool( oldBootOrder ); } if (newBootOrder) { FreePool(newBootOrder); }
return status;
}
EFI_STATUS WritePackedDataToNvr( UINT16 BootNumber, VOID *BootOption, UINT32 BootSize ) { EFI_STATUS status; CHAR16 VariableName[10];
SPrint( VariableName, sizeof(VariableName), L"Boot%04x", BootNumber ); status = SetVariable( VariableName, &VenEfi, EFI_ATTR, BootSize, BootOption ); if (status == EFI_SUCCESS) { status = AppendEntryToBootOrder(BootNumber); if (status != EFI_SUCCESS) { Print(L"\nError: Failed to append new boot entry to boot order array\n");
goto Done;
}
} else {
Print(L"\nError: Failed to set new boot entry variable\n");
goto Done; }
//
// repopulate the local info about boot entries
//
FreeBootManagerVars(); GetBootManagerVars();
Done:
return status;
}
#if DEBUG_PACK
VOID DisplayELOFromLoadOption( IN UINT32 OptionNum ) { char* elo; PEFI_LOAD_OPTION pElo;
//
// Make sure it is a valid OS load option
//
if (OptionNum > BootOrderCount) { return; } if (LoadOptions[OptionNum] == NULL) { return; }
pElo = (EFI_LOAD_OPTION*)LoadOptions[OptionNum]; elo = (char*)LoadOptions[OptionNum];
DisplayELO(elo, LoadOptionsSize[OptionNum]);
} #endif
VOID GetFieldFromLoadOption( IN UINT32 OptionNum, IN UINT32 FieldType, OUT VOID* Data, OUT UINT64* DataSize ) { char* elo; PEFI_LOAD_OPTION pElo;
//
// Make sure it is a valid OS load option
//
if (OptionNum > BootOrderCount) { return; } if (LoadOptions[OptionNum] == NULL) { *DataSize = 0; return; }
pElo = (EFI_LOAD_OPTION*)LoadOptions[OptionNum]; elo = (char*)LoadOptions[OptionNum];
switch ( FieldType ) { case ATTRIBUTE: {
*((UINT32*) Data) = pElo->Attributes; *DataSize = sizeof(UINT32);
break; } case FILEPATHLISTLENGTH: {
*((UINT16*) Data) = pElo->FilePathListLength; *DataSize = sizeof(UINT16);
break; } case DESCRIPTION: {
StrCpy((CHAR16*)Data, pElo->Description); *DataSize = StrSize(pElo->Description);
break; } case EFIFILEPATHLIST: {
char* aFilePath;
aFilePath = GetAlignedELOFilePath(elo);
CopyMem(Data, aFilePath, pElo->FilePathListLength );
FreePool(aFilePath);
*DataSize = pElo->FilePathListLength;
break; } case OPTIONALDATA: {
char* aOptionalData; UINT64 eloSize;
eloSize = LoadOptionsSize[OptionNum];
aOptionalData = GetAlignedOptionalData(elo, eloSize, DataSize );
CopyMem(Data, aOptionalData, *DataSize);
FreePool(aOptionalData);
break;
} default:
*DataSize = 0;
break; } }
BOOLEAN GetLoadIdentifier( IN UINT32 BootVarNum, OUT CHAR16* LoadIdentifier ) { UINT64 DataSize = 0;
GetFieldFromLoadOption( BootVarNum, DESCRIPTION, LoadIdentifier, &DataSize ); if (!DataSize) return FALSE; return TRUE; }
VOID GetEfiOsLoaderFilePath( IN UINT32 BootVarNum, OUT char* FilePath ) { UINT64 DataSize = 0;
GetFieldFromLoadOption( BootVarNum, EFIFILEPATHLIST, FilePath, &DataSize ); }
BOOLEAN GetOsLoadOptionVars( IN UINT32 BootVarNum, OUT CHAR16* LoadIdentifier, OUT char* OsLoadOptions, OUT char* EfiFilePath, OUT char* OsLoadPath ) { if (BootVarNum >= BootOrderCount) return FALSE; if (!LoadOptions[BootVarNum]) return FALSE;
GetLoadIdentifier( BootVarNum, LoadIdentifier );
GetOptionalDataValue( BootVarNum, OSLOADOPTIONS, OsLoadOptions ); GetEfiOsLoaderFilePath( BootVarNum, EfiFilePath );
GetOptionalDataValue( BootVarNum, OSLOADPATH, OsLoadPath);
return TRUE; }
VOID GetOptionalDataValue( IN UINT32 BootVarNum, IN UINT32 Selection, OUT char* OptionalDataValue ) { char osOptions[MAXBOOTVARSIZE]; UINT64 osOptionsSize; PWINDOWS_OS_OPTIONS pOsOptions;
if (BootVarNum < MAXBOOTVARS) {
GetFieldFromLoadOption( BootVarNum, OPTIONALDATA, osOptions, &osOptionsSize );
pOsOptions = (PWINDOWS_OS_OPTIONS)osOptions;
switch (Selection) { case OSLOADOPTIONS: {
StrCpy( (CHAR16*)OptionalDataValue, pOsOptions->OsLoadOptions );
break; }
case OSLOADPATH: { char* aOsLoadPath; UINTN aOsLoadPathSize;
aOsLoadPath = GetAlignedOsLoadPath(osOptions, &aOsLoadPathSize);
CopyMem(OptionalDataValue, aOsLoadPath, aOsLoadPathSize );
FreePool(aOsLoadPath);
break; }
default: {
break;
} } } }
UINTN GetDevPathSize( IN EFI_DEVICE_PATH *DevPath ) { EFI_DEVICE_PATH *Start;
//
// Search for the end of the device path structure
//
Start = DevPath; while (DevPath->Type != END_DEVICE_PATH_TYPE) { DevPath = NextDevicePathNode(DevPath); }
//
// Compute the size
//
return(UINTN) ((UINT64) DevPath - (UINT64) Start); }
UINT32 GetPartitions( ) {
EFI_HANDLE EspHandles[100],FSPath; UINT64 HandleArraySize = 100 * sizeof(EFI_HANDLE); UINT64 CachedDevicePaths[100]; UINTN i, j; UINTN CachedDevicePathsCount; UINT64 SystemPartitionPathSize; EFI_DEVICE_PATH *dp; EFI_STATUS Status; UINT32 PartitionCount; char AlignedNode[1024];
//
// Get all handles that supports the block I/O protocol.
//
ZeroMem( EspHandles, HandleArraySize );
Status = LocateHandle ( ByProtocol, &EfiESPProtocol, 0, (UINTN *) &HandleArraySize, EspHandles );
//
// Cache all of the EFI Device Paths.
//
for (i = 0; EspHandles[i] != 0; i++) {
Status = HandleProtocol ( EspHandles[i], &DevicePathProtocol, &( (EFI_DEVICE_PATH *) CachedDevicePaths[i] ) ); }
//
// Save the number of cached Device Paths.
//
CachedDevicePathsCount = i; PartitionCount = 0;
//
// Find the first partition on the first hard drive
// partition. That is our SystemPartition.
//
for ( i=0; i<CachedDevicePathsCount; i++ ) {
dp = (EFI_DEVICE_PATH*) CachedDevicePaths[i];
while (( DevicePathType(dp) != END_DEVICE_PATH_TYPE ) && ( DevicePathSubType(dp) != END_ENTIRE_DEVICE_PATH_SUBTYPE )) {
if (( DevicePathType(dp) == MEDIA_DEVICE_PATH ) && ( DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP )) { CopyMem( AlignedNode, dp, DevicePathNodeLength(dp) );
HandleProtocol (EspHandles[i],&FileSystemProtocol,&FSPath); if ( FSPath != NULL) { PartitionCount++; } } dp = NextDevicePathNode(dp); } }
return PartitionCount; }
EFI_HANDLE GetDeviceHandleForPartition( ) { EFI_HANDLE EspHandles[100],FSPath; UINT64 HandleArraySize = 100 * sizeof(EFI_HANDLE); UINT64 CachedDevicePaths[100]; UINTN i, j; UINTN CachedDevicePathsCount; UINT64 SystemPartitionPathSize; EFI_DEVICE_PATH *dp; EFI_STATUS Status; char AlignedNode[1024];
//
// Get all handles that supports the block I/O protocol.
//
ZeroMem( EspHandles, HandleArraySize );
Status = LocateHandle ( ByProtocol, &EfiESPProtocol, 0, (UINTN *) &HandleArraySize, EspHandles );
//
// Cache all of the EFI Device Paths.
//
for (i = 0; EspHandles[i] != 0; i++) {
Status = HandleProtocol ( EspHandles[i], &DevicePathProtocol, &( (EFI_DEVICE_PATH *) CachedDevicePaths[i] ) ); }
//
// Save the number of cached Device Paths.
//
CachedDevicePathsCount = i;
//
// Find the first ESP partition on the first hard drive
// partition. That is our SystemPartition.
//
for ( i=0; i<CachedDevicePathsCount; i++ ) {
dp = (EFI_DEVICE_PATH*) CachedDevicePaths[i];
while (( DevicePathType(dp) != END_DEVICE_PATH_TYPE ) && ( DevicePathSubType(dp) != END_ENTIRE_DEVICE_PATH_SUBTYPE )) {
if (( DevicePathType(dp) == MEDIA_DEVICE_PATH ) && ( DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP )) { CopyMem( AlignedNode, dp, DevicePathNodeLength(dp) );
HandleProtocol (EspHandles[i],&FileSystemProtocol,&FSPath); if ( FSPath != NULL) { //
// Found the correct device path partition.
// Return the device handle.
//
return( EspHandles[i] );
} }
dp = NextDevicePathNode(dp); } }
return NULL; }
/*
** BUGBUG: These functions need to be eventually placed in lib\str.c */ INTN RUNTIMEFUNCTION StrCmpA ( IN CHAR8 *s1, IN CHAR8 *s2 ) /* compare strings */ { while (*s1) { if (*s1 != *s2) { break; }
s1 += 1; s2 += 1; }
return *s1 - *s2; }
VOID RUNTIMEFUNCTION StrCpyA ( IN CHAR8 *Dest, IN CHAR8 *Src ) /* copy strings */ { while (*Src) { *(Dest++) = *(Src++); } *Dest = 0; }
VOID RUNTIMEFUNCTION StrCatA ( IN CHAR8 *Dest, IN CHAR8 *Src ) { StrCpyA(Dest+StrLenA(Dest), Src); }
UINTN RUNTIMEFUNCTION StrLenA ( IN CHAR8 *s1 ) /* string length */ { UINTN len;
for (len=0; *s1; s1+=1, len+=1) ; return len; }
UINTN RUNTIMEFUNCTION StrSizeA ( IN CHAR8 *s1 ) /* string size */ { UINTN len;
for (len=0; *s1; s1+=1, len+=1) ; return(len + 1) * sizeof(CHAR8); }
|