boot.c
来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 1,972 行 · 第 1/5 页
C
1,972 行
if (EFI_ERROR(Status)) {
PrintAt (ResultContext->Menu->Col, ResultContext->Menu->Row + 3, L"NVRAM update failed");
} else {
NVRAMNeedsUpdating = FALSE;
}
break;
case BOOT_MENU_SELECTION:
//
// Toggle selection
//
OrderOption(ResultContext,Direction,&NVRAMNeedsUpdating);
break;
default:
break;
}
}
FreeSpecificBootMenuOption(&BootMenu, SaveNvramContext);
FreeSpecificBootMenuOption(&BootMenu, BootHelpContext);
FreeSpecificBootMenuOption(&BootMenu, BootExitContext);
ST->ConOut->ClearScreen (ST->ConOut);
return EFI_SUCCESS;
}
EFI_STATUS
OrderOption(
IN BOOT_MENU_CONTEXT *Context,
IN UINTN Direction,
OUT BOOLEAN *UpdateNvram
)
{
EFI_INPUT_KEY Key;
SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut;
SIMPLE_INPUT_INTERFACE *ConIn;
UINTN EndRow;
UINTN MaxColumn, ScreenSize;
MENU_OPTION *MenuOption;
MENU_OPTION *MenuOption_Next;
MENU_OPTION *MenuOption_Prev;
BOOT_MENU_CONTEXT *BootContext;
BOOT_MENU_CONTEXT *BootContext_Next;
BOOT_MENU_CONTEXT *BootContext_Prev;
LIST_ENTRY *List;
LIST_ENTRY *List_Next;
LIST_ENTRY *List_Prev;
ConOut = ST->ConOut;
ConIn = ST->ConIn;
ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &MaxColumn, &ScreenSize);
EndRow = ScreenSize - BootMenu.FooterHeight - 1;
List = BootMenu.Head.Flink;
while (List != &BootMenu.Head) {
MenuOption = CR(List, MENU_OPTION, Link, MENU_OPTION_SIGNATURE);
// get the next & previous members
List_Next = List->Flink;
List_Prev = List->Blink;
BootContext = (BOOT_MENU_CONTEXT *)MenuOption->Context;
if ((BootContext != NULL) && (BootContext == Context)) {
//
// if direction is down and next one is not BOOT_MENU_SELECTION, then
// we cannot move down
//
if (Direction == DIRECTION_DOWN) {
if (List_Next != &BootMenu.Head) {
MenuOption_Next = CR(List_Next, MENU_OPTION, Link, MENU_OPTION_SIGNATURE);
BootContext_Next = (BOOT_MENU_CONTEXT *)MenuOption_Next->Context;
if(BootContext_Next->MenuOption == BOOT_MENU_SELECTION) {
// list_next before List
SwapListEntries(List,List_Next);
*UpdateNvram = TRUE;
break;
} else {
ConOut->SetAttribute (ConOut, BootMenu.ReverseScreenAttribute);
PrintAt(BootMenu.Col,EndRow,L"Selected option bottom of list. Cannot move down. Press any key...");
WaitForSingleEvent (ConIn->WaitForKey, 0);
ConIn->ReadKeyStroke (ConIn, &Key);
ConOut->SetAttribute (ConOut, BootMenu.ScreenAttribute);
}
}
}
//
// if direction is up and above one is not BOOT_MENU_SELECTION, then
// we cannot move down
//
if (Direction == DIRECTION_UP) {
if (List_Prev != &BootMenu.Head) {
MenuOption_Prev = CR(List_Prev, MENU_OPTION, Link, MENU_OPTION_SIGNATURE);
BootContext_Prev = (BOOT_MENU_CONTEXT *)MenuOption_Prev->Context;
if(BootContext_Prev->MenuOption == BOOT_MENU_SELECTION) {
// list before List_Prev
SwapListEntries(List_Prev,List);
*UpdateNvram = TRUE;
break;
}
} else {
ConOut->SetAttribute (ConOut, BootMenu.ReverseScreenAttribute);
PrintAt(BootMenu.Col,EndRow,L"Selected option top of list. Cannot move up. Press any key...");
WaitForSingleEvent (ConIn->WaitForKey, 0);
ConIn->ReadKeyStroke (ConIn, &Key);
ConOut->SetAttribute (ConOut, BootMenu.ScreenAttribute);
}
}
}
List = List->Flink;
}
return EFI_SUCCESS;
}
VOID
BootContextPrint (
IN MENU_OPTION *MenuOption,
IN BOOT_MENU_CONTEXT *Context,
IN UINTN *Row,
IN UINTN Column
)
{
CHAR16 *OptionString;
CHAR16 *OptionDevicePath;
CHAR16 *VariableName;
CHAR16 *LoadOption,*TempLoadOption;
CHAR8 *AsciiChar;
PrintAt (Column, *Row+1, L"%-.80s", L"");
PrintAt (Column, *Row+2, L"%-.80s", L"");
PrintAt (Column, *Row+3, L"%-.80s", L"");
PrintAt (Column, *Row+4, L"%-.80s", L"");
LoadOption = NULL;
if (Context->MenuOption == BOOT_MENU_SELECTION) {
OptionString = Context->Description;
OptionDevicePath = Context->FilePathString;
VariableName = &Context->BootString[0];
if (Context->LoadOptionsSize) {
LoadOption = Context->LoadOptions;
}
} else {
OptionString = L"";
OptionDevicePath = L"";
VariableName = NULL;
}
*Row += 1;
PrintAt (Column, *Row, L"%-.80s", OptionDevicePath);
*Row += 1;
if (VariableName) {
PrintAt (Column, *Row, L"%-.80s", VariableName);
*Row += 1;
}
//
// Crude check. Currently loadoption can be either
// ascii or Unicode string only..
// hence test 2nd byte to see if it is non-zero
// if non-zero then string is ascii else, unicode
// Bugbug: NEED TO GET A BETTER METHOD (like a header)
// to figure out type of data
if (LoadOption) {
AsciiChar = (UINT8 *)LoadOption;
AsciiChar++;
if(*AsciiChar) {
// ascii string. hence form unicode string
LoadOption = AllocateZeroPool(Context->LoadOptionsSize * sizeof(CHAR16));
ASSERT(LoadOption);
TempLoadOption = LoadOption;
AsciiChar = (UINT8 *)Context->LoadOptions;
for ( ; *AsciiChar != '\0';AsciiChar++) {
*LoadOption = *AsciiChar;
LoadOption++;
}
*LoadOption = '\0';
PrintAt(Column, *Row,L"%-.80s",TempLoadOption);
FreePool(TempLoadOption);
} else {
// unicode string
PrintAt(Column, *Row,L"%-.80s",LoadOption);
}
*Row += 1;
}
if(Context->IsBootNext) {
PrintAt (Column, *Row, L"%-.80s", L"BootNext Option");
} else {
PrintAt (Column, *Row, L"%-.80s", L"");
}
*Row += 1;
}
BOOT_MENU_CONTEXT *
AllocateSpecialBootOption (
IN EFI_MENU *Menu,
IN CHAR16 *String,
IN UINTN Attribute,
IN UINTN Option
)
{
BOOT_MENU_CONTEXT *Context;
Context = AllocateZeroPool (sizeof(BOOT_MENU_CONTEXT));
ASSERT (Context);
Context->MenuOption = Option;
Context->Menu = AllocateMenuOption (Menu, String, Attribute, Context);
Context->Menu->ContextPrint = BootContextPrint;
return Context;
}
EFI_STATUS
SetNvramForBootMenu (
IN EFI_MENU *Menu
)
{
MENU_OPTION *MenuOption;
BOOT_MENU_CONTEXT *BootContext;
LIST_ENTRY *List;
EFI_STATUS Status;
BOOLEAN WriteBootOption, SavedBootNext;
UINT16 *VarBootOrderList;
UINTN VarBootOrderListSize;
UINT16 *BootOrderList;
UINTN BootOrderListSize,SaveListSize;
VarBootOrderList = LibGetVariableAndSize (VarBootOrder, &EfiGlobalVariable, &VarBootOrderListSize);
BootOrderList = AllocateZeroPool (0x1024);
BootOrderListSize = 0;
SavedBootNext = FALSE;
for (List = Menu->Head.Flink ;List != &Menu->Head; List = List->Flink) {
MenuOption = CR(List, MENU_OPTION, Link, MENU_OPTION_SIGNATURE);
BootContext = (BOOT_MENU_CONTEXT *)MenuOption->Context;
if (BootContext == NULL) {
continue;
}
// we want to add old ones only if we read a valid rawoption data for this
// boot option
if ((BootContext->OptionNumber != NEWADDITION_OPTIONNUMBER) && (BootContext->RawOption)) {
BootOrderList[BootOrderListSize] = BootContext->OptionNumber;
BootOrderListSize++;
}
if (BootContext->OptionNumber == NEWADDITION_OPTIONNUMBER) {
BootOrderList[BootOrderListSize] = NEWADDITION_OPTIONNUMBER;
BootOrderListSize++;
}
}
SaveListSize = BootOrderListSize;
BootOrderListSize = 0;
for (List = Menu->Head.Flink ;List != &Menu->Head; List = List->Flink) {
MenuOption = CR(List, MENU_OPTION, Link, MENU_OPTION_SIGNATURE);
BootContext = (BOOT_MENU_CONTEXT *)MenuOption->Context;
if (BootContext == NULL) {
continue;
}
// add any new boot option
if (BootContext->OptionNumber == NEWADDITION_OPTIONNUMBER) {
BootContext->OptionNumber = AllocateBootOrder (BootOrderList, SaveListSize);
BootOrderList[BootOrderListSize] = BootContext->OptionNumber;
SPrint (BootContext->BootString, sizeof(BootContext->BootString), VarBootOption, BootContext->OptionNumber);
}
if (BootContext->LoadOptionModified) {
// may need to update MenuOption description as it might changed as part of
// loadoptions
FreePool(MenuOption->Description);
MenuOption->Description = StrDuplicate(BootContext->Description);
Status = RT->SetVariable (
BootContext->BootString, &EfiGlobalVariable,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
BootContext->RawOptionSize, (VOID*) (BootContext->RawOption)
);
//
// BugBug: Should not assert after code is debugged
//
ASSERT (!EFI_ERROR(Status));
}
//
// Store BootNext option number
//
if(BootContext->IsBootNext) {
Status = RT->SetVariable (
VarBootNext, &EfiGlobalVariable,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
sizeof(BootContext->OptionNumber), &(BootContext->OptionNumber)
);
ASSERT (!EFI_ERROR(Status));
SavedBootNext = TRUE;
}
BootOrderListSize++;
}
if (SaveListSize*sizeof(UINT16) != VarBootOrderListSize) {
WriteBootOption = TRUE;
} else {
if (VarBootOrderList) {
WriteBootOption = (CompareMem (VarBootOrderList, BootOrderList, VarBootOrderListSize) != 0);
} else {
//
// No NVRAM variable case
//
WriteBootOption = TRUE;
}
}
if (WriteBootOption) {
Status = RT->SetVariable (
VarBootOrder, &EfiGlobalVariable,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
SaveListSize*sizeof(UINT16), BootOrderList
);
}
if (!SavedBootNext) {
LibDeleteVariable (VarBootNext, &EfiGlobalVariable);
}
if (VarBootOrderList) {
FreePool (VarBootOrderList);
}
if (BootOrderList) {
FreePool (BootOrderList);
}
return EFI_SUCCESS;
}
UINT16
AllocateBootOrder (
IN UINT16 *BootOrderList,
IN UINTN BootOrderSize
)
{
UINT16 BootOption;
UINTN Index;
BOOLEAN Match;
for (BootOption = 0; BootOption <= 0xffff; BootOption++) {
for (Index = 0, Match = FALSE; (Index < BootOrderSize) && !Match; Index++) {
Match = (BootOrderList[Index] == BootOption);
}
if (!Match) {
return BootOption;
}
}
return 0xffff;
}
BOOLEAN
IsInVarBootOrder (
IN UINT16 BootOption,
IN UINT16 *BootOrderList,
IN UINTN BootOrderSize
)
{
UINTN Index;
for (Index = 0; Index < BootOrderSize; Index++) {
if (BootOrderList[Index] == BootOption) {
return TRUE;
}
}
return FALSE;
}
VOID
FreeAllOfBootMenu (
IN EFI_MENU *Menu
)
{
MENU_OPTION *MenuOption;
BOOT_MENU_CONTEXT *BootContext;
LIST_ENTRY *List;
//
// Delete the menu option's Context
//
List = Menu->Head.Flink;
while (List != &Menu->Head) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?