boot.c

来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 1,972 行 · 第 1/5 页

C
1,972
字号
        MenuOption = CR(List, MENU_OPTION, Link, MENU_OPTION_SIGNATURE);
        
        BootContext = (BOOT_MENU_CONTEXT *)MenuOption->Context;
        if (BootContext != NULL) {
            if (BootContext->FilePathString) {
                FreePool (BootContext->FilePathString);
            }
            if (BootContext->RawOption) {
                FreePool (BootContext->RawOption);
            }
            FreePool (MenuOption->Context);
        }
        
        List = List->Flink;
    }
    MenuFree (Menu);
}

VOID
FreeSpecificBootMenuOption (
    IN EFI_MENU             *Menu,
    IN BOOT_MENU_CONTEXT    *Context
    )
{
    MENU_OPTION         *MenuOption;
    BOOT_MENU_CONTEXT   *BootContext;
    LIST_ENTRY          *List;   

    //
    // Delete the menu option's Context
    //
    List = Menu->Head.Flink;
    while (List != &Menu->Head) {
        MenuOption = CR(List, MENU_OPTION, Link, MENU_OPTION_SIGNATURE);
        
        // get the next list in case we end up freeing the current one
        List = List->Flink;

        BootContext = (BOOT_MENU_CONTEXT *)MenuOption->Context;
        if ((BootContext != NULL) && (BootContext == Context)) {
            if (BootContext->FilePathString) {
                FreePool (BootContext->FilePathString);
            }
            if (BootContext->Description) {
                FreePool (BootContext->Description);
            }
            if (BootContext->RawOption) {
                FreePool (BootContext->RawOption);
            }
            FreePool (MenuOption->Context);
            MenuOption->Context = NULL;
            FreePool (MenuOption->Description);
            MenuOption->Description = NULL;
            RemoveEntryList (&MenuOption->Link);
            ASSERT(MenuOption->Signature == MENU_OPTION_SIGNATURE);
            FreePool (MenuOption);
        }
    }
}

EFI_STATUS
FindBootOption (
    IN EFI_MENU             *Menu,
    IN OUT LIST_ENTRY       **List,
    IN  EFI_DEVICE_PATH     *DevicePath,
    OUT BOOT_MENU_CONTEXT   **ReturnBootContext
    )
{
    MENU_OPTION         *MenuOption;
    BOOT_MENU_CONTEXT   *BootContext;

    *ReturnBootContext = NULL;
    while (*List != &Menu->Head) {
        MenuOption = CR(*List, MENU_OPTION, Link, MENU_OPTION_SIGNATURE);
        
        BootContext = (BOOT_MENU_CONTEXT *)MenuOption->Context;
        if (BootContext != NULL) {
            if (BootContext->FilePath) {
                if (MatchDevicePaths (DevicePath, BootContext->FilePath)) {
                    *ReturnBootContext = BootContext;
                    *List = (*List)->Flink;
                    return EFI_SUCCESS;
                }
            }
        }
        *List = (*List)->Flink;
    }
    return EFI_NOT_FOUND;
}

EFI_STATUS
BootFromFileContext (
    IN  FILE_MENU_CONTEXT   *Context
    )
{
    EFI_INPUT_KEY       Key;
    BOOT_MENU_CONTEXT   *BootOption;
    EFI_STATUS          Result;
    EFI_STATUS          Status;
    UINTN               ScreenSize, MaxColumn, EndRow;
    LIST_ENTRY          *List;

    ST->ConOut->ClearScreen (ST->ConOut);
    ST->ConOut->QueryMode (ST->ConOut, ST->ConOut->Mode->Mode, &MaxColumn, &ScreenSize);
    EndRow = ScreenSize - BootMenu.FooterHeight - 1;

    PrintEfiFileInfo (Context);
    List = BootMenu.Head.Flink;
    Result = FindBootOption (&BootMenu, &List, Context->DevicePath, &BootOption);
    if (!EFI_ERROR(Result)) {
        Print (L"    Boot%04x: %s\n\n", BootOption->OptionNumber, BootOption->FilePathString);
    }
    Status = BootTheOption (Context, BootOption);
    if (!EFI_ERROR(Status) || Status == EFI_ALREADY_STARTED) {
        return EFI_SUCCESS;
    } else {
        ST->ConOut->SetAttribute (ST->ConOut, BootMenu.ReverseScreenAttribute);
        PrintAt(BootMenu.Col,EndRow,L"Load failed [%r]. Press any key to continue..", Status);
        WaitForSingleEvent (ST->ConIn->WaitForKey, 0);
        ST->ConIn->ReadKeyStroke (ST->ConIn, &Key);
        ST->ConOut->SetAttribute (ST->ConOut, BootMenu.ScreenAttribute);
        return Status;
    }
}


EFI_STATUS
ConvertFileContextToBootOption (
    IN  FILE_MENU_CONTEXT   *Context
    )
{
    EFI_INPUT_KEY                  Key;
    SIMPLE_TEXT_OUTPUT_INTERFACE   *ConOut;
    SIMPLE_INPUT_INTERFACE         *ConIn;   
    EFI_STATUS                     Result;
    UINT8                          *RawOption;
    CHAR16                         *Str;
    EFI_DEVICE_PATH                *DevicePath;
    UINTN                          Size,ScreenSize, MaxColumn, EndRow;
    CHAR16                         InputString[MAX_CHAR];
    BOOT_MENU_CONTEXT              *BootOption;
    BOOT_MENU_CONTEXT              *NextBootOption;
    BOOLEAN                        Edit, Exit, Next;
    CHAR16                         LoadOptionStr[MAX_CHAR];
    UINTN                          LoadOptionSize;
    UINT8                          *LoadOptionPtr;
    CHAR16                         *LoadOption,*TempLoadOption;
    CHAR8                          *AsciiChar;
    UINTN                          SizeDevicePath;
    LIST_ENTRY                     *List;
    LIST_ENTRY                     *NextList;
    EFI_STATUS                     NextResult;

    ConOut = ST->ConOut;
    ConIn  = ST->ConIn;
    ConOut->ClearScreen (ST->ConOut);
    PrintEfiFileInfo (Context);

    List = BootMenu.Head.Flink;
    Edit = FALSE;
    Exit = FALSE;
    Next = FALSE;

    while (TRUE) {
      Result = FindBootOption ( &BootMenu, &List, Context->DevicePath, &BootOption);
      if (!EFI_ERROR(Result)) {

        Edit = FALSE;
        Exit = FALSE;
        Next = FALSE;

        NextList = List;
        NextResult = FindBootOption ( &BootMenu, &NextList, Context->DevicePath, &NextBootOption);
        if (!EFI_ERROR(NextResult)) {
          Next = TRUE;
        }

        ConOut->SetAttribute (ConOut, BootMenu.ScreenAttribute);
        ConOut->ClearScreen (ST->ConOut);
        PrintEfiFileInfo (Context);
        Print (L"    Boot%04x: %s\n", BootOption->OptionNumber, BootOption->FilePathString);
        while (TRUE) {
          BmntClearLine();
          ConOut->SetAttribute (ConOut, BootMenu.ReverseScreenAttribute);
          if (!Next) {
            Print(L" Edit this Boot Option or Create a new one? [E-Edit N-New]: ");
          } else {
            Print(L" Edit/Skip this Boot Option or Create a new one? [E-Edit S-Skip N-New]: ");
          }
          WaitForSingleEvent (ConIn->WaitForKey, 0);
          ConIn->ReadKeyStroke (ConIn, &Key);
         
          if (Key.UnicodeChar == 'E' || Key.UnicodeChar == 'e') {
            Edit = TRUE;
            Exit = TRUE;
            Print(L" Edit");
            break;
          }
            
          if (Key.UnicodeChar == 'N' || Key.UnicodeChar == 'n') {
            Exit = TRUE;
            Print(L" New");
            break;
          }

          if ( Next && (Key.UnicodeChar == 'S' || Key.UnicodeChar == 's')) {
            Exit = FALSE;
            Print(L"Skip");
            break;
          }
        }
        if (Exit) {
          break;
        }
      } else {
        break;
      }
    }
    
    //
    // Let's make a boot option
    //
    
    ConOut->SetAttribute (ConOut, BootMenu.ScreenAttribute);

    //
    // Update Description Field
    //
    if (Edit) {
        Print (L"\n\n    Current Description-->%s", BootOption->Description);
    }
    Print(L"\n");
    do {
        BmntClearLine();
        ConOut->SetAttribute (ConOut, BootMenu.ReverseScreenAttribute);
        Print (L"    Enter New Description: ");
        ConOut->SetAttribute (ConOut, BootMenu.ScreenAttribute);
        Print(L" ");
        do {
            Input (L"", InputString, sizeof(InputString));
        } while (StrLen(InputString) == 0);
    } while (InputString[0] == ' ');
    
    //
    // Update BootOption Field
    //
    LoadOption = NULL;
    if (Edit) {
        if (BootOption->MenuOption == BOOT_MENU_SELECTION) {
            if (BootOption->LoadOptionsSize)
                LoadOption = BootOption->LoadOptions;
        } 
   
        //
        // 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(BootOption->LoadOptionsSize * sizeof(CHAR16));
                ASSERT(LoadOption);
                TempLoadOption = LoadOption;
                AsciiChar = (UINT8 *)BootOption->LoadOptions;
                for ( ; *AsciiChar != '\0';AsciiChar++) {
                    *LoadOption = *AsciiChar;
                    LoadOption++;
                }
                *LoadOption = '\0';
                Print (L"\n\n    Current BootOption-->%-s", TempLoadOption);
                FreePool(TempLoadOption);
            } else {
                // unicode string
                Print (L"\n\n    Current BootOption-->%-s", LoadOption);
            }
        } 
    } 

    // Get the new load option
    LoadOptionSize = 0;
    UpdateLoadOption(LoadOptionStr, sizeof(LoadOptionStr), &LoadOptionSize, FALSE);
    
    
    //
    // save the changes
    //
    ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &MaxColumn, &ScreenSize);
    EndRow = ScreenSize - BootMenu.FooterHeight - 1;
    Exit = FALSE;
    while (!Exit) {
        ConOut->SetAttribute (ConOut, BootMenu.ReverseScreenAttribute);
        PrintAt(BootMenu.Col,EndRow,L"Save changes to NVRAM [Y-Yes N-No]: ");
        WaitForSingleEvent (ConIn->WaitForKey, 0);
        ConIn->ReadKeyStroke (ConIn, &Key);
        ConOut->SetAttribute (ConOut, BootMenu.ScreenAttribute);
        
        if (Key.UnicodeChar == 'Y' || Key.UnicodeChar == 'y') {
        
          //
          // Update BootOption Description
          //
          if (Edit) {
            FreePool (BootOption->Description);
            BootOption->Description = NULL;
            if(!StrLen(InputString)) {
              StrCpy(InputString, L"No Description");
            }
            BootOption->Description = AllocatePool (StrSize(InputString));
            StrCpy (BootOption->Description, InputString);
          }

          //
          // Update BootOption's Load Option
          //
          if (Edit) {
            FreePool (BootOption->LoadOptions);
            BootOption->LoadOptions = NULL;
            BootOption->LoadOptions = AllocateZeroPool(LoadOptionSize);
            CopyMem(BootOption->LoadOptions,LoadOptionStr,LoadOptionSize);
            BootOption->LoadOptionsSize = LoadOptionSize;
          }

          //
          // build a new menuoption or update the current one
          // allocate memory and copy all the options
          //
          SizeDevicePath = DevicePathSize (Context->DevicePath);
          Size = sizeof(UINT32) + sizeof(UINT16) + StrSize(InputString) + SizeDevicePath + LoadOptionSize;
          RawOption = AllocatePool (Size);
          *(UINT32 *)RawOption = LOAD_OPTION_ACTIVE;

          *(UINT16 *)(RawOption + sizeof(UINT32)) = (UINT16)SizeDevicePath;

          Str = (CHAR16 *)(RawOption + sizeof(UINT32) + sizeof(UINT16));
          StrCpy (Str, InputString);

          DevicePath = (EFI_DEVICE_PATH *)(Str + StrLen(Str) + 1);
          CopyMem (DevicePath, Context->DevicePath, DevicePathSize(Context->DevicePath));

          LoadOptionPtr = (UINT8 *) ((UINT8 *)(DevicePath) + DevicePathSize(Context->DevicePath));
          CopyMem(LoadOptionPtr,LoadOptionStr,LoadOptionSize);

          if(Edit) {
              FreePool(BootOption->RawOption);
              BootOption->RawOption = RawOption;
              BootOption->RawOptionSize = Size;
              BootOption->LoadOptionModified = TRUE;
          } else {
              // build the menu option
              BootOption = BuildBootMenuContext (RawOption, Size, NEWADDITION_OPTIONNUMBER, L"", FALSE, TRUE);
          }

          Result = SetNvramForBootMenu (&BootMenu);
            
          if (EFI_ERROR(Result)) {
              BmntClearLine();
              ConOut->SetAttribute (ConOut, BootMenu.ReverseScreenAttribute);
              PrintAt(BootMenu.Col,EndRow,L"NVRAM update failed. Press any key to continue.... ");
              WaitForSingleEvent (ConIn->WaitForKey, 0);
              ConIn->ReadKeyStroke (ConIn, &Key);
              ConOut->SetAttribute (ConOut, BootMenu.ScreenAttribute);
          }
          Exit = TRUE;
        }
        if (Key.UnicodeChar == 'N' || Key.UnicodeChar == 'n') {
            Exit = TRUE;
        }
    }

    return EFI_SUCCESS;
}

EFI_STATUS
UpdateLoadOption(
    IN  CHAR16  *LoadOptionStr, 
    IN  UINTN   SizeLoadOptionStr,
    OUT UINTN   *LoadOptionSize,
    IN  BOOLEAN EditMode)
{
    EFI_INPUT_KEY                   Key;
    SIMPLE_TEXT_OUTPUT_INTERFACE    *ConOut;
    SIMPLE_INPUT_INTERFACE          *ConIn;   
    BOOLEAN                         Ascii;
    CHAR16                          *TempStr,*TempStr1;
    CHAR8                           *AsciiChar;

    ConOut = ST->ConOut;
    ConIn  = ST->ConIn;
    

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?