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

886 lines
27 KiB
C

#include <precomp.h>
//
// Global Coordinates
//
#define COL_TITLE 0
#define ROW_TITLE 0
#define COL_OSOPTIONS 2
#define ROW_OSOPTIONS 2
#define COL_PROMPT 0
#define ROW_PROMPT 2
#define CLEAR_LINE L" "
#define PROMPT L"Select> "
#define NUMBER_OF_USER_OPTIONS 3 // options, plus a space seperator
#define MAX_OPTIONS_PER_VAR 7
#define BACKUPNVRFILE L"\\bootentries.bak"
VOID
InitializeStdOut(
IN struct _EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Stash some of the efi stdout pointers
//
ConOut = SystemTable->ConOut;
ClearScreen = ConOut->ClearScreen;
SetCursorPosition = ConOut->SetCursorPosition;
SetMode = ConOut->SetMode;
CursorRow = ConOut->Mode->CursorRow;
CursorColumn = ConOut->Mode->CursorColumn;
EnableCursor = ConOut->EnableCursor;
ConIn = SystemTable->ConIn;
//
// Set the mode to 80, 25 and clear the screen
//
SetMode( ConOut, 0 );
}
VOID
PrintTitle(
)
{
CHAR16 Buffer[256];
ClearScreen( ConOut );
#if 0
PrintAt( 0, 30, L"%H%s%N\n", TITLE1 );
PrintAt( 0, 30, L"%H%s%N", VER_PRODUCTBUILD );
#endif
SPrint(
Buffer,
sizeof(Buffer),
L"%s [Version %d.%d.%d]",
TITLE1,
VER_PRODUCTMAJORVERSION,
VER_PRODUCTMINORVERSION,
VER_PRODUCTBUILD
);
PrintAt( 0, 30, L"%H%s%N\n", Buffer);
}
BOOLEAN
isWindowsOsUserSelection(
UINTN userSelection
)
{
BOOLEAN status;
status = isWindowsOsBootOption((char*)LoadOptions[userSelection],
LoadOptionsSize[userSelection]
);
return status;
}
INTN
BackupBootOptions(
CHAR16* filePath
)
{
INTN status;
//
// backup current boot options
//
Print(L"\nBacking up boot options...\n");
status = SaveAllBootOptions(filePath);
if(status != -1) {
Print(L"Backed up Boot Options to file: %H%s%N\n",filePath);
Print(L"Use %HImport%N command to retrieve saved boot options\n");
} else {
Print(L"Could not backup Boot Options to file: %H%s%N!\n",filePath);
}
return status;
}
VOID
DisplayMainMenu(
)
{
UINT32 done = FALSE;
UINT32 nUserSelection, nSubUserSelection, nModifyVar;
CHAR16 szUserSelection[1024];
CHAR16 szOsLoader[1024];
CHAR16 szInput[512];
VOID* SourceBuffer = NULL;
UINT32 PartitionCount;
EFI_DEVICE_PATH *FilePath;
//
// Display boot options from nvram.
//
PrintTitle();
GetBootManagerVars();
DisplayBootOptions();
//
// Process user input.
//
while( !done ) {
GetUserSelection( szUserSelection );
//
// Handle char string commands
//
if( (!StriCmp( szUserSelection, L"q")) || (!StriCmp( szUserSelection, L"quit"))
|| (!StriCmp( szUserSelection, L"Q")) || (!StriCmp( szUserSelection, L"exit")) ) {
//
// Quit
//
done = TRUE;
}
else if( (!StriCmp( szUserSelection, L"d")) || (!StriCmp( szUserSelection, L"D"))
|| (!StriCmp( szUserSelection, L"display")) ) {
//
// Display command
//
//
// Choose selection
//
Print( L"\n" );
nSubUserSelection = GetSubUserSelection( L"Enter boot option to display: ", (UINT32) GetBootOrderCount() );
if( nSubUserSelection != 0 ) {
nSubUserSelection--;
if (isWindowsOsUserSelection(nSubUserSelection) == FALSE) {
Print (L"\n\nThis tool only displays Windows OS boot options\n");
} else {
if(DisplayExtended( nSubUserSelection ))
;
else {
Print( L"\n" );
Print( L"Wrong Boot Option %d Selected\n", nSubUserSelection+1 );
}
}
Print( L"\n" );
Input( L"Press enter to continue", szInput, sizeof(szInput) );
}
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
}
else if( (!StriCmp( szUserSelection, L"e")) || (!StriCmp( szUserSelection, L"E"))
|| (!StriCmp( szUserSelection, L"erase")) ) {
//
// Erase command
//
BOOLEAN selectedAll;
//
// Choose selection
//
Print( L"\n" );
nSubUserSelection = GetSubUserSelectionOrAll( L"Enter OS boot option to erase (* = All): ",
(UINT32) GetBootOrderCount(),
&selectedAll
);
//
// choose the path based on if the user wants all the os boot options whacked or not
//
if (selectedAll) {
//
// get user confirmation
//
Print( L"\n" );
Input( L"This will erase all OS boot options. Are you Sure? ", szInput, sizeof(szInput) );
if( (!StriCmp( szInput, L"y")) || (!StriCmp( szInput, L"Y"))) {
//
// backup current boot options first
//
if (BackupBootOptions(BACKUPNVRFILE) != -1) {
if(EraseAllOsBootOptions()) {
Print(L"\nAll OS Boot Options Erased.\n");
GetBootManagerVars();
}
else {
Print(L"\nThere are no OS Boot Options to Erase.\n");
}
}
Print( L"\n" );
Input( L"Press enter to continue", szInput, sizeof(szInput) );
}
} else {
CHAR16 buf[256];
if( nSubUserSelection > 0 ) {
SPrint (buf, sizeof(buf), L"This will erase OS boot option %d. Are you Sure? ", nSubUserSelection);
// get user confirmation
//
Print( L"\n" );
Input( buf, szInput, sizeof(szInput) );
if( (!StriCmp( szInput, L"y")) || (!StriCmp( szInput, L"Y"))) {
nSubUserSelection--;
if(EraseOsBootOption(nSubUserSelection)) {
Print(L"\nBoot Option %d erased.\n", nSubUserSelection + 1);
FreeBootManagerVars();
GetBootManagerVars();
}
else {
Print(L"\nInvalid OS Boot Options specified.\n");
}
Print( L"\n" );
Input( L"Press enter to continue", szInput, sizeof(szInput) );
}
}
}
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
} else if( (!StriCmp( szUserSelection, L"p")) || (!StriCmp( szUserSelection, L"P"))
|| (!StriCmp( szUserSelection, L"push")) ) {
//
// Push command
//
//
// Choose selection
//
Print( L"\n" );
nSubUserSelection = GetSubUserSelection( L"Enter the boot option you want to push to top? ", (UINT32) GetBootOrderCount() );
if( nSubUserSelection > 0 ) {
nSubUserSelection--;
if(PushToTop( nSubUserSelection )) {
FreeBootManagerVars();
GetBootManagerVars();
Print( L"\n" );
Print( L"OS Boot Option %d pushed to top of boot order\n", nSubUserSelection+1 );
}
else {
Print( L"\n" );
Print( L"Wrong Boot Option %d Selected\n", nSubUserSelection+1 );
}
Input( L"Press enter to continue", szInput, sizeof(szInput) );
}
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
} else if( (!StriCmp( szUserSelection, L"c")) || (!StriCmp( szUserSelection, L"C"))
|| (!StriCmp( szUserSelection, L"copy")) ) {
//
// Copy command
//
//
// Choose selection
//
Print( L"\n" );
nSubUserSelection = GetSubUserSelection( L"Enter OS boot option to copy: ", (UINT32) GetBootOrderCount() );
if( nSubUserSelection != 0 ) {
nSubUserSelection--;
if(!CopyVar( nSubUserSelection )) {
Print( L"\n" );
Print( L"Wrong Boot Option %d Selected\n",nSubUserSelection+1);
}
else {
SetBootManagerVars();
FreeBootManagerVars();
GetBootManagerVars();
Print( L"\n" );
Print( L"Boot Option %d Copied. ",nSubUserSelection+1);
}
Print( L"\n" );
Input( L"Press enter to continue", szInput, sizeof(szInput) );
}
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
} else if( (!StriCmp( szUserSelection, L"x")) || (!StriCmp( szUserSelection, L"X"))
|| (!StriCmp( szUserSelection, L"export")) ) {
//
// Save command
//
CHAR16 filePath[512];
BOOLEAN selectedAll;
//
// Choose selection
//
Print( L"\n" );
nSubUserSelection = GetSubUserSelectionOrAll( L"Enter OS boot option to export (* = All): ",
(UINT32) GetBootOrderCount(),
&selectedAll
);
if (nSubUserSelection > 0 || selectedAll) {
Print( L"\n" );
Input( L"Enter EXPORT file path: ", filePath, sizeof(filePath) );
if (StrLen(filePath) > 0) {
//
// choose the path based on if the user wants all the os boot options exported or just one
//
if (selectedAll) {
Print(L"\nSaving %d boot options...\n", GetBootOrderCount());
if(SaveAllBootOptions(filePath) != -1) {
Print(L"Saved Boot Options to file: %H%s%N\n",filePath);
Print(L"Use %HImport%N command to retrieve saved boot options\n");
} else {
Print(L"Could not save Boot Options to file: %H%s%N!\n",filePath);
}
} else {
Print(L"\nSaving boot option %d...\n", nSubUserSelection);
if(SaveBootOption(filePath, nSubUserSelection-1) != -1) {
Print(L"Saved Boot Option %d to file: %H%s%N\n",nSubUserSelection, filePath);
Print(L"Use %HImport%N command to retrieve saved boot option\n");
} else {
Print(L"Could not save Boot Option to file: %H%s%N!\n",filePath);
}
}
}
}
Print( L"\n" );
Input( L"Press enter to continue", szInput, sizeof(szInput) );
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
} else if( (!StriCmp( szUserSelection, L"i")) || (!StriCmp( szUserSelection, L"I"))
|| (!StriCmp( szUserSelection, L"import")) ) {
//
// Restore command
//
CHAR16 filePath[512];
Print( L"\n" );
Input( L"Enter IMPORT file path: ", filePath, sizeof(filePath) );
if (StrLen(filePath) > 0) {
if(RestoreFileExists(filePath) == TRUE) {
if(RestoreNvr(filePath) != -1) {
Print( L"\n" );
Print(L"Imported Boot Options from file: %H%s%N\n",filePath);
FreeBootManagerVars();
GetBootManagerVars();
}
else {
Print(L"Restore failed!\n");
}
} else {
Print(L"\n\nError: Restore file not found: %s\n\n", filePath);
}
}
Print( L"\n" );
Input( L"Press enter to continue", szInput, sizeof(szInput) );
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
}
#if 0
else if( (!StriCmp( szUserSelection, L"a")) || (!StriCmp( szUserSelection, L"A"))
|| (!StriCmp( szUserSelection, L"add")) ) {
//
// Add command
//
//
// Get EFI system partition
//
PartitionCount = GetPartitions();
if( PartitionCount > 0 ) {
Print( L"\n" );
Input( L"Name of New BootOption: ", szInput, sizeof(szInput) );
FilePath = FileDevicePath(
GetDeviceHandleForPartition(),
L"os\\winnt50\\ia64ldr.efi"
);
PackAndWriteToNvr(
-1,
"multi(0)disk(0)rdisk(0)partition(1)",
"multi(0)disk(0)rdisk(0)partition(1)\\os\\winnt50\\ia64ldr.efi",
"multi(0)disk(0)rdisk(0)partition(2)",
"\\WINNT64",
szInput[0] ? szInput : L"New Boot Option",
"",
(char*) FilePath
);
Print( L"\nAdded %H%s%N. Use %HModify%N command to change any of the default values.\n",
szInput[0] ? szInput : L"New Boot Option" );
Input( L"Press enter to continue", szInput, sizeof(szInput) );
FreeBootManagerVars();
GetBootManagerVars();
} else {
Print( L"No partitions found. To use this option, you must have an EFI or FAT16\n" );
Print( L"partition that will be used as your System Partition.\n" );
Input( L"Press enter to continue", szInput, sizeof(szInput) );
}
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
}
#endif
else if( (!StriCmp( szUserSelection, L"h")) || (!StriCmp( szUserSelection, L"H"))
|| (!StriCmp( szUserSelection, L"help")) ) {
//
// Help command
//
PrintTitle();
//
// Display Help text.
//
Print( L"\n" );
Print( L"%HDisplay%N - Display an OS boot option's environment variables.\n" );
Print( L"%HModify%N - Modify an OS boot option's environment variable.\n" );
Print( L"%HCopy%N - Copy (duplicate) an OS boot option.\n" );
Print( L"%HExport%N - Export all/one OS boot option(s) to disk.\n" );
Print( L"%HImport%N - Import (and append) OS boot option(s) from disk.\n" );
Print( L"%HErase%N - Erase all OS boot options from NVRAM.\n" );
Print( L"%HPush%N - Push a OS boot option to top of boot order.\n" );
Print( L"%HHelp%N - This display.\n" );
Print( L"%HQuit%N - Quit.\n" );
Print( L"\n");
Print( L"Note: When importing/exporting boot options, all specified file paths\n");
Print( L" are absolute and relative to the current disk device.\n");
Print( L"\n");
Print( L" Example: To import Boot0000 from the Windows loader directory WINNT50.0\n");
Print( L" on fs1, you would run nvrboot.efi on fs1 and use the path:\n");
Print( L"\n");
Print( L" \\EFI\\Microsoft\\WINNT50.0\\Boot0000\n");
Print( L"\n");
Input( L"Press enter to continue", szInput, sizeof(szInput) );
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
}
else if( (!StriCmp( szUserSelection, L"m")) || (!StriCmp( szUserSelection, L"M"))
|| (!StriCmp( szUserSelection, L"modify")) ) {
//
// Modify command
//
//
// Choose selection
//
Print( L"\n" );
nSubUserSelection = GetSubUserSelection( L"Enter OS boot option to modify: ", (UINT32) GetBootOrderCount() );
if( nSubUserSelection > 0 ) {
nSubUserSelection--;
if (isWindowsOsUserSelection(nSubUserSelection) == FALSE) {
Print( L"\n\nThis tool only modifies Windows OS boot options\n" );
} else {
if(DisplayExtended( nSubUserSelection )) {
//
// Choose var
//
nModifyVar = GetSubUserSelection( L"Enter var to modify: ", MAX_OPTIONS_PER_VAR );
if( nModifyVar > 0) {
Print( L"\n" );
//
// Map variable to env var
//
switch( nModifyVar ) {
case 1:
Input( L"LoadIdentifier = ", szInput, sizeof(szInput) );
nModifyVar = DESCRIPTION;
break;
case 2:
Input( L"OsLoadOptions = ", szInput, sizeof(szInput) );
nModifyVar = OSLOADOPTIONS;
break;
case 3:
Print (L"This field currently not modifiable\n");
#if 0
Input( L"EfiOsLoaderFilePath = ", szInput, sizeof(szInput) );
#endif
nModifyVar = EFIFILEPATHLIST;
break;
case 4:
Print (L"This field currently not modifiable\n");
#if 0
Input( L"OsLoaderFilePath = ", szInput, sizeof(szInput) );
#endif
nModifyVar = OSFILEPATHLIST;
break;
default:
break;
}
//
// Write all vars to NV-RAM
//
SetFieldFromLoadOption(
nSubUserSelection,
nModifyVar,
szInput
);
DisplayExtended(nSubUserSelection);
FreeBootManagerVars();
GetBootManagerVars();
}
Print( L"\n" );
}
}
Input( L"Press enter to continue", szInput, sizeof(szInput) );
}
}
//
// Display boot options from nvram
//
PrintTitle();
DisplayBootOptions();
}
}
UINT32
GetConfirmation(
IN CHAR16 *szConfirm
)
{
CHAR16 szIn[80];
UINT32 saveRow;
Print( L"\n" );
saveRow = CursorRow;
if( szConfirm ) {
Input( szConfirm, szIn, sizeof(szIn) );
} else {
Input( L"Are you sure? ", szIn, sizeof(szIn) );
}
// Clear previous input
SetCursorPosition( ConOut, 0, saveRow );
PrintAt( 0, saveRow, CLEAR_LINE );
if( (!StriCmp( szIn, L"y")) || (!StriCmp( szIn, L"yes")) )
return TRUE;
return FALSE;
}
VOID
GetUserSelection(
OUT CHAR16 *szUserSelection
)
{
UINT32 numSelections;
UINT32 row, col;
numSelections = (UINT32) GetOsBootOptionsCount();
numSelections += NUMBER_OF_USER_OPTIONS;
// note, we use ROW_PROMPT as an offset
row = ROW_OSOPTIONS + numSelections + ROW_PROMPT;
col = COL_PROMPT;
// Clear previous input
SetCursorPosition( ConOut, col, row );
PrintAt( col, row, CLEAR_LINE );
// Get the input
SetCursorPosition( ConOut, col, row );
Input( PROMPT, szUserSelection, 1024 );
}
VOID
DisplayBootOptions(
)
{
UINT32 i;
UINT32 j;
CHAR16 LoadIdentifier[200];
UINTN bootOrderCount;
bootOrderCount = GetBootOrderCount();
if (bootOrderCount > 0) {
for ( i=0,j=0; i<GetBootOrderCount(); i++ ) {
if(LoadOptionsSize[i] == 0) {
//
// It's possible a null load option could be in the list
// we naturally want to catch this...
//
#if EFI_DEBUG
Print(L"\nNVRAM Boot Entry %d has 0 length!\n", i);
ASSERT(LoadOptionsSize[i] > 0);
#endif
//
// if we are not in debug mode, just let the use know what is
// going on other wise the menu may be screwed up
//
PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS + j, L"%2d. (0 length Boot Entry)\n", i+1);
} else if(GetLoadIdentifier( i, LoadIdentifier)) {
if (isWindowsOsBootOption((char*)LoadOptions[i], LoadOptionsSize[i]) == TRUE)
{
PrintAt( COL_OSOPTIONS - 1, ROW_OSOPTIONS + j, L"*%2d. %s\n", i+1, LoadIdentifier );
}
else {
PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS + j, L"%2d. %s\n", i+1, LoadIdentifier );
}
j++;
}
}
PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS + ++j, L"* = Windows OS boot option\n" );
j++;
} else {
PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS, L"[No Boot Entries Present]\n");
j = 2;
}
//
// Display Maitainence Menu
//
#if 0
PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS + ++j, L"%H(D)%Nisplay %H(M)%Nodify %H(C)%Nopy\n" );
PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS + ++j, L"%H(S)%Nave %H(R)%Nestore %H(E)%Nrase\n" );
// PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS + ++j, L"%H(A)%Ndd %H(P)%Nush %H(H)%Nelp %H(Q)%Nuit\n" );
PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS + ++j, L"%H(P)%Nush %H(H)%Nelp %H(Q)%Nuit\n" );
#endif
PrintAt( COL_OSOPTIONS, ROW_OSOPTIONS + ++j, L"%H(D)%Nisplay %H(M)%Nodify %H(C)%Nopy E%H(x)%Nport %H(I)%Nmport %H(E)%Nrase %H(P)%Nush %H(H)%Nelp %H(Q)%Nuit\n" );
}
#if 0
#define L_SYSTEMPARTITION L"SystemPartition"
#define L_OSLOADER L"OsLoader"
#define L_OSLOADPARTITION L"OsLoadPartition"
#define L_OSLOADFILENAME L"OsLoadFilename"
#define L_LOADIDENTIFIER L"LoadIdentifier"
#define L_OSLOADOPTIONS L"OsLoadOptions"
#define L_OSLOADPATH L"OsLoadOptions"
#define L_EFIFILEPATH L"EfiOsLoaderFilePath"
#define L_COUNTDOWN L"COUNTDOWN"
#define L_AUTOLOAD L"AUTOLOAD"
#define L_LASTKNOWNGOOD L"LastKnownGood"
#define L_BOOTSELECTION L"BootSelection"
#endif
BOOLEAN
DisplayExtended(
IN UINT32 Selection
)
{
char OsLoadOptions[200];
CHAR16 LoadIdentifier[200];
unsigned char EfiFilePath[1024];
unsigned char OsLoadPath[1024];
CHAR16 FilePathShort[200];
BOOLEAN status;
PFILE_PATH pFilePath;
#if DEBUG_PACK
DisplayELOFromLoadOption(Selection);
#endif
status = GetOsLoadOptionVars(
Selection,
LoadIdentifier,
OsLoadOptions,
EfiFilePath,
OsLoadPath
);
if (status == FALSE) {
return status;
}
Print( L"\n" );
Print( L"1. LoadIdentifier = %s\n", LoadIdentifier );
Print( L"2. OsLoadOptions = %s\n", OsLoadOptions );
GetFilePathShort( (EFI_DEVICE_PATH*) EfiFilePath, FilePathShort );
Print( L"3. EfiOsLoaderFilePath = %s\n", FilePathShort );
pFilePath = (FILE_PATH*)OsLoadPath;
GetFilePathShort( (EFI_DEVICE_PATH*)pFilePath->FilePath, FilePathShort );
Print( L"4. OsLoaderFilePath = %s\n", FilePathShort );
return TRUE;
}
UINT32
GetSubUserSelectionOrAll(
IN CHAR16* szConfirm,
IN UINT32 MaxSelection,
OUT BOOLEAN* selectedAll
)
{
CHAR16 szIn[80];
UINT32 nUserSelection = 0;
if( szConfirm ) {
Input( szConfirm, szIn, sizeof(szIn) );
} else {
Input( L"Enter Selection (* = ALL)? ", szIn, sizeof(szIn) );
}
*selectedAll = FALSE;
if (StrCmp(szIn, L"*") == 0) {
*selectedAll = TRUE;
} else {
nUserSelection = (int) Atoi( szIn );
if(( nUserSelection>0 ) && ( nUserSelection <= MaxSelection))
return nUserSelection;
}
return 0;
}
UINT32
GetSubUserSelection(
IN CHAR16 *szConfirm,
IN UINT32 MaxSelection
)
{
CHAR16 szIn[80];
UINT32 nUserSelection = 0;
if( szConfirm ) {
Input( szConfirm, szIn, sizeof(szIn) );
} else {
Input( L"Enter Selection? ", szIn, sizeof(szIn) );
}
nUserSelection = (int) Atoi( szIn );
if(( nUserSelection>0 ) && ( nUserSelection <= MaxSelection))
return nUserSelection;
return 0;
}