/*++ 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 #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 #if !defined(_WIN64) typedef unsigned long ULONG_PTR, *PULONG_PTR; #else typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; #endif #ifndef POINTER_IS_ALIGNED // BOOL // POINTER_IS_ALIGNED( // IN LPVOID Ptr, // IN DWORD Pow2 // undefined if this isn't a power of 2. // ); // #define POINTER_IS_ALIGNED(Ptr,Pow2) \ ( ( ( ((ULONG_PTR)(Ptr)) & (((Pow2)-1)) ) == 0) ? TRUE : FALSE ) #endif // !POINTER_IS_ALIGNED VOID* LoadOptions [MAXBOOTVARS]; UINT64 LoadOptionsSize [MAXBOOTVARS]; VOID* BootOrder; UINT64 BootOrderCount; UINT64 OsBootOptionCount; #define LOAD_OPTION_ACTIVE 0x00000001 // // local routines // BOOLEAN SetBootManagerVar( UINTN BootVarNum ); BOOLEAN SetBootManagerVarCheck( UINTN BootVarNum ); 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 GLOBAL_DEBUG VOID GetBootManagerVars( ) { UINT32 i,j; CHAR16 szTemp[10]; VOID* bootvar; UINT64 BootOrderSize = 0; UINT64 maxBootCount; // // Initialize EFI LoadOptions. // BootOrderSize = 0; BootOrderCount = 0; OsBootOptionCount = 0; BootOrder = NULL; #if 1 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 maxBootCount = (MAXBOOTVARS < BootOrderCount) ? MAXBOOTVARS : BootOrderCount; // // Get the boot options. // for ( i=0; i= 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 ); // // The NVRAM variables are case sensitive. If we were unable to // find the variable, perhaps the Boot Entry string has uppercase // alpha characters in the hexadecimal string. try again with // an uppercase string // if (pDummy == NULL && dummySize == 0) { SPrint( szTemp, sizeof(szTemp), L"Boot%04X", ((CHAR16*) BootOrder)[BootVarNum] ); 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++) { // // adjust the boot order for all entries // tmpBootOrder[j] = tmpBootOrder[j + 1]; // // only have a maximum of MAXBOOTVARS boot entries. // only adjust if we can. // if (j < OsBootOptionCount) { 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); // // Make sure there is atleast one OS boot option // if ( BootOrder && OsBootOptionCount) { maxBootCount = (MAXBOOTVARS < BootOrderCount) ? MAXBOOTVARS : 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 savBootOption; CHAR16* tmpBootOrder; UINT64 BootOrderSize = 0; // // check BootVarNum // if (MAXBOOTVARS <= BootVarNum) { return FALSE; } 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]; // // 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) return ; if (BootVarNum >= MAXBOOTVARS) return; if (LoadOptions[BootVarNum] == NULL) return; status = GetOsLoadOptionVars( BootVarNum, LoadIdentifier, OsLoadOptions, EfiFilePath, OsLoadPath ); if (status == FALSE) { #ifdef DEBUG_PACK Print (L"\nSetFieldFromLoadOption: GetOsLoadOptionVars failed\n"); #endif // DEBUG_PACK return; } // // Set the field. // switch (FieldType) { case DESCRIPTION: StrCpy( LoadIdentifier, Data ); break; case OSLOADOPTIONS: StrCpy( (CHAR16*)OsLoadOptions, (CHAR16*)Data ); break; #if 1 case EFIFILEPATHLIST: efiFilePathListLength = SetFilePathFromShort( (EFI_DEVICE_PATH*) EfiFilePath, (CHAR16*) Data ); break; case OSFILEPATHLIST: { PFILE_PATH pFilePath; pFilePath = (FILE_PATH*)OsLoadPath; osLoadPathListLength = SetFilePathFromShort( (EFI_DEVICE_PATH*) pFilePath->FilePath, (CHAR16*) Data ); if ( osLoadPathListLength ) { osLoadPathListLength += (UINT16) FIELD_OFFSET( FILE_PATH, FilePath ); } } break; #endif default: break; } // // Pack the new parameters into the the current load option // PackLoadOption( BootVarNum, LoadIdentifier, (CHAR16*)OsLoadOptions, EfiFilePath, efiFilePathListLength, OsLoadPath, osLoadPathListLength ); // // save the new load option into NVRAM // SetBootManagerVarCheck(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); iType != END_DEVICE_PATH_TYPE ) && ( n->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ) ) { if (( n->Type == MEDIA_DEVICE_PATH ) && ( n->SubType == MEDIA_HARDDRIVE_DP )) { harddriveDp = (HARDDRIVE_DEVICE_PATH *)n; CopyMem( DiskGuid, &harddriveDp->Signature, sizeof(harddriveDp->Signature) ); break; } n = NextDevicePathNode(n); } } UINT16 // new FilePathListLength if updated. 0 otherwise. SetFilePathFromShort( EFI_DEVICE_PATH *FilePath, CHAR16* FilePathShort ) { UINT32 i, j, End; EFI_DEVICE_PATH *n = FilePath; UINT64 DevicePathSize; UINT16 length = 0; // // 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 )) { #if DEBUG_PACK Print (L"SetFilePathFromShort: Entry found...\n"); #endif // DEBUG_PACK j = 0; End = DevicePathNodeLength(n); // // Set the new file path // DevicePathSize = GetDevPathSize(n); for ( i=sizeof(EFI_DEVICE_PATH); iType != END_DEVICE_PATH_TYPE ) && ( n->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ) ) { if (( n->Type == MEDIA_DEVICE_PATH ) && ( n->SubType == MEDIA_FILEPATH_DP )) { harddriveDp = (HARDDRIVE_DEVICE_PATH *)n; CopyMem( &harddriveDp->Signature, DiskGuid, sizeof(harddriveDp->Signature) ); 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 UINT16 EfiFilePathListLength, // 0 if not updated IN char* OsLoadPath, IN UINT16 OsLoadPathListLength // 0 if not updated ) /* 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; UINT16 filePathListLength; UINT16 loadPathListLength; #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 // // The following code assumes EfiFilePath and OsLoadPath are pointer-aligned // if the corresponding length exposes an update by the caller. // Checking and failing at the function entry avoids unneeded memory allocations. // if ( EfiFilePathListLength && !POINTER_IS_ALIGNED(EfiFilePath, sizeof(void *))) { ASSERT( POINTER_IS_ALIGNED(EfiFilePath, sizeof(void *)) ); Print (L"PackLoadOption: EfiFilePath unaligned.\n"); return; } if ( OsLoadPathListLength && !POINTER_IS_ALIGNED(OsLoadPath, sizeof(void *))) { ASSERT( POINTER_IS_ALIGNED(OsLoadPath, sizeof(void *)) ); Print (L"PackLoadOption: OsLoadPath unaligned.\n"); return; } 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"PackLoadOption: elo allocation failed. size=%d\n", MAXBOOTVARSIZE); return; } pElo = (EFI_LOAD_OPTION*)elo; pOldElo = (EFI_LOAD_OPTION*)oldElo; // // Efi Attribute. // eloSize = sizeof(pElo->Attributes); pElo->Attributes = pOldElo->Attributes; // // FilePathListLength // eloSize += sizeof(pElo->FilePathListLength); filePathListLength = EfiFilePathListLength ? EfiFilePathListLength : pOldElo->FilePathListLength; pElo->FilePathListLength = filePathListLength; // // Description. // StrCpy( pElo->Description, LoadIdentifier ); eloSize += StrSize(LoadIdentifier); if ( EfiFilePathListLength == 0 ) { // // 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); } else { // already checked: ASSERT( POINTER_IS_ALIGNED(EfiFilePath, sizeof(void *)) ); aFilePath = EfiFilePath; } CopyMem( &elo[eloSize], aFilePath, filePathListLength ); eloSize += filePathListLength; if ( EfiFilePathListLength == 0 ) { 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 = NULL; 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 // if ( OsLoadPathListLength == 0 ) { aOsLoadPath = GetAlignedOsLoadPath(aOldOsOptions, &aOsLoadPathSize); } else { FILE_PATH *filePath; // already checked: ASSERT( POINTER_IS_ALIGNED(OsLoadPath, sizeof(void *)) ); aOsLoadPath = OsLoadPath; filePath = (FILE_PATH *)aOsLoadPath; filePath->Length = OsLoadPathListLength; } FreePool(aOldOsOptions); // // Construct a new WINDOWS_OS_STRUCTURE with the new values // BuildNewOsOptions( OsLoadOptions, aOsLoadPath, &osOptions ); if ( OsLoadPathListLength == 0 ) { 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]; // // Don't attempt to write the BootEntry if it has no size. // if (BootSize == 0) { return EFI_SUCCESS; } 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 (OptionNum >= MAXBOOTVARS) { 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 (OptionNum >= MAXBOOTVARS) { 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 (BootVarNum >= MAXBOOTVARS) { 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; ASSERT(DevPath->Type != END_DEVICE_PATH_TYPE); // // Search for the end of the device path structure // Start = DevPath; do { DevPath = NextDevicePathNode(DevPath); } while (DevPath->Type != END_DEVICE_PATH_TYPE); // // 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