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 + -
显示快捷键?