mirror of https://github.com/acidanthera/audk.git
1662 lines
47 KiB
C
1662 lines
47 KiB
C
/** @file
|
|
Provide boot option support for Application "BootMaint"
|
|
|
|
Include file system navigation, system handle selection
|
|
|
|
Boot option manipulation
|
|
|
|
Copyright (c) 2004 - 2008, Intel Corporation. <BR>
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "BootMaint.h"
|
|
#include "BBSsupport.h"
|
|
|
|
/**
|
|
Create a menu entry by given menu type.
|
|
|
|
@param MenuType The Menu type to be created.
|
|
|
|
@retval NULL If failed to create the menu.
|
|
@return the new menu entry.
|
|
|
|
**/
|
|
BM_MENU_ENTRY *
|
|
BOpt_CreateMenuEntry (
|
|
UINTN MenuType
|
|
)
|
|
{
|
|
BM_MENU_ENTRY *MenuEntry;
|
|
UINTN ContextSize;
|
|
|
|
//
|
|
// Get context size according to menu type
|
|
//
|
|
switch (MenuType) {
|
|
case BM_LOAD_CONTEXT_SELECT:
|
|
ContextSize = sizeof (BM_LOAD_CONTEXT);
|
|
break;
|
|
|
|
case BM_FILE_CONTEXT_SELECT:
|
|
ContextSize = sizeof (BM_FILE_CONTEXT);
|
|
break;
|
|
|
|
case BM_CONSOLE_CONTEXT_SELECT:
|
|
ContextSize = sizeof (BM_CONSOLE_CONTEXT);
|
|
break;
|
|
|
|
case BM_TERMINAL_CONTEXT_SELECT:
|
|
ContextSize = sizeof (BM_TERMINAL_CONTEXT);
|
|
break;
|
|
|
|
case BM_HANDLE_CONTEXT_SELECT:
|
|
ContextSize = sizeof (BM_HANDLE_CONTEXT);
|
|
break;
|
|
|
|
case BM_LEGACY_DEV_CONTEXT_SELECT:
|
|
ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT);
|
|
break;
|
|
|
|
default:
|
|
ContextSize = 0;
|
|
break;
|
|
}
|
|
|
|
if (ContextSize == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Create new menu entry
|
|
//
|
|
MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
|
|
if (MenuEntry == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
|
|
if (MenuEntry->VariableContext == NULL) {
|
|
FreePool (MenuEntry);
|
|
return NULL;
|
|
}
|
|
|
|
MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;
|
|
MenuEntry->ContextSelection = MenuType;
|
|
return MenuEntry;
|
|
}
|
|
|
|
/**
|
|
Free up all resource allocated for a BM_MENU_ENTRY.
|
|
|
|
@param MenuEntry A pointer to BM_MENU_ENTRY.
|
|
|
|
**/
|
|
VOID
|
|
BOpt_DestroyMenuEntry (
|
|
BM_MENU_ENTRY *MenuEntry
|
|
)
|
|
{
|
|
BM_LOAD_CONTEXT *LoadContext;
|
|
BM_FILE_CONTEXT *FileContext;
|
|
BM_CONSOLE_CONTEXT *ConsoleContext;
|
|
BM_TERMINAL_CONTEXT *TerminalContext;
|
|
BM_HANDLE_CONTEXT *HandleContext;
|
|
BM_LEGACY_DEVICE_CONTEXT *LegacyDevContext;
|
|
|
|
//
|
|
// Select by the type in Menu entry for current context type
|
|
//
|
|
switch (MenuEntry->ContextSelection) {
|
|
case BM_LOAD_CONTEXT_SELECT:
|
|
LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;
|
|
FreePool (LoadContext->FilePathList);
|
|
FreePool (LoadContext->LoadOption);
|
|
if (LoadContext->OptionalData != NULL) {
|
|
FreePool (LoadContext->OptionalData);
|
|
}
|
|
FreePool (LoadContext);
|
|
break;
|
|
|
|
case BM_FILE_CONTEXT_SELECT:
|
|
FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
|
|
|
|
if (!FileContext->IsRoot) {
|
|
FreePool (FileContext->DevicePath);
|
|
} else {
|
|
if (FileContext->FHandle != NULL) {
|
|
FileContext->FHandle->Close (FileContext->FHandle);
|
|
}
|
|
}
|
|
|
|
if (FileContext->FileName != NULL) {
|
|
FreePool (FileContext->FileName);
|
|
}
|
|
if (FileContext->Info != NULL) {
|
|
FreePool (FileContext->Info);
|
|
}
|
|
FreePool (FileContext);
|
|
break;
|
|
|
|
case BM_CONSOLE_CONTEXT_SELECT:
|
|
ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;
|
|
FreePool (ConsoleContext->DevicePath);
|
|
FreePool (ConsoleContext);
|
|
break;
|
|
|
|
case BM_TERMINAL_CONTEXT_SELECT:
|
|
TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;
|
|
FreePool (TerminalContext->DevicePath);
|
|
FreePool (TerminalContext);
|
|
break;
|
|
|
|
case BM_HANDLE_CONTEXT_SELECT:
|
|
HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;
|
|
FreePool (HandleContext);
|
|
break;
|
|
|
|
case BM_LEGACY_DEV_CONTEXT_SELECT:
|
|
LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;
|
|
FreePool (LegacyDevContext);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
FreePool (MenuEntry->DisplayString);
|
|
if (MenuEntry->HelpString != NULL) {
|
|
FreePool (MenuEntry->HelpString);
|
|
}
|
|
|
|
FreePool (MenuEntry);
|
|
}
|
|
|
|
/**
|
|
Get the Menu Entry from the list in Menu Entry List.
|
|
|
|
If MenuNumber is great or equal to the number of Menu
|
|
Entry in the list, then ASSERT.
|
|
|
|
@param MenuOption The Menu Entry List to read the menu entry.
|
|
@param MenuNumber The index of Menu Entry.
|
|
|
|
@return The Menu Entry.
|
|
|
|
**/
|
|
BM_MENU_ENTRY *
|
|
BOpt_GetMenuEntry (
|
|
BM_MENU_OPTION *MenuOption,
|
|
UINTN MenuNumber
|
|
)
|
|
{
|
|
BM_MENU_ENTRY *NewMenuEntry;
|
|
UINTN Index;
|
|
LIST_ENTRY *List;
|
|
|
|
ASSERT (MenuNumber < MenuOption->MenuNumber);
|
|
|
|
List = MenuOption->Head.ForwardLink;
|
|
for (Index = 0; Index < MenuNumber; Index++) {
|
|
List = List->ForwardLink;
|
|
}
|
|
|
|
NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
|
|
|
|
return NewMenuEntry;
|
|
}
|
|
|
|
/**
|
|
This function build the FsOptionMenu list which records all
|
|
available file system in the system. They includes all instances
|
|
of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
|
|
and all type of legacy boot device.
|
|
|
|
@param CallbackData BMM context data
|
|
|
|
@retval EFI_SUCCESS Success find the file system
|
|
@retval EFI_OUT_OF_RESOURCES Can not create menu entry
|
|
|
|
**/
|
|
EFI_STATUS
|
|
BOpt_FindFileSystem (
|
|
IN BMM_CALLBACK_DATA *CallbackData
|
|
)
|
|
{
|
|
UINTN NoBlkIoHandles;
|
|
UINTN NoSimpleFsHandles;
|
|
UINTN NoLoadFileHandles;
|
|
EFI_HANDLE *BlkIoHandle;
|
|
EFI_HANDLE *SimpleFsHandle;
|
|
EFI_HANDLE *LoadFileHandle;
|
|
UINT16 *VolumeLabel;
|
|
EFI_BLOCK_IO_PROTOCOL *BlkIo;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
BM_MENU_ENTRY *MenuEntry;
|
|
BM_FILE_CONTEXT *FileContext;
|
|
UINT16 *TempStr;
|
|
UINTN OptionNumber;
|
|
VOID *Buffer;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
UINT16 DeviceType;
|
|
BBS_BBS_DEVICE_PATH BbsDevicePathNode;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
BOOLEAN RemovableMedia;
|
|
|
|
|
|
NoSimpleFsHandles = 0;
|
|
NoLoadFileHandles = 0;
|
|
OptionNumber = 0;
|
|
InitializeListHead (&FsOptionMenu.Head);
|
|
|
|
//
|
|
// Locate Handles that support BlockIo protocol
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiBlockIoProtocolGuid,
|
|
NULL,
|
|
&NoBlkIoHandles,
|
|
&BlkIoHandle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
for (Index = 0; Index < NoBlkIoHandles; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
BlkIoHandle[Index],
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **) &BlkIo
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
|
|
//
|
|
if (BlkIo->Media->RemovableMedia) {
|
|
Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
|
|
if (NULL == Buffer) {
|
|
FreePool (BlkIoHandle);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
BlkIo->ReadBlocks (
|
|
BlkIo,
|
|
BlkIo->Media->MediaId,
|
|
0,
|
|
BlkIo->Media->BlockSize,
|
|
Buffer
|
|
);
|
|
FreePool (Buffer);
|
|
}
|
|
}
|
|
FreePool (BlkIoHandle);
|
|
}
|
|
|
|
//
|
|
// Locate Handles that support Simple File System protocol
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
&NoSimpleFsHandles,
|
|
&SimpleFsHandle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Find all the instances of the File System prototocol
|
|
//
|
|
for (Index = 0; Index < NoSimpleFsHandles; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
SimpleFsHandle[Index],
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **) &BlkIo
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// If no block IO exists assume it's NOT a removable media
|
|
//
|
|
RemovableMedia = FALSE;
|
|
} else {
|
|
//
|
|
// If block IO exists check to see if it's remobable media
|
|
//
|
|
RemovableMedia = BlkIo->Media->RemovableMedia;
|
|
}
|
|
|
|
//
|
|
// Allocate pool for this load option
|
|
//
|
|
MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
|
|
if (NULL == MenuEntry) {
|
|
FreePool (SimpleFsHandle);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
|
|
|
|
FileContext->Handle = SimpleFsHandle[Index];
|
|
MenuEntry->OptionNumber = Index;
|
|
FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle);
|
|
if (FileContext->FHandle == NULL) {
|
|
BOpt_DestroyMenuEntry (MenuEntry);
|
|
continue;
|
|
}
|
|
|
|
MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
|
|
FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);
|
|
FileContext->FileName = EfiStrDuplicate (L"\\");
|
|
FileContext->DevicePath = FileDevicePath (
|
|
FileContext->Handle,
|
|
FileContext->FileName
|
|
);
|
|
FileContext->IsDir = TRUE;
|
|
FileContext->IsRoot = TRUE;
|
|
FileContext->IsRemovableMedia = RemovableMedia;
|
|
FileContext->IsLoadFile = FALSE;
|
|
|
|
//
|
|
// Get current file system's Volume Label
|
|
//
|
|
if (FileContext->Info == NULL) {
|
|
VolumeLabel = L"NO FILE SYSTEM INFO";
|
|
} else {
|
|
if (FileContext->Info->VolumeLabel == NULL) {
|
|
VolumeLabel = L"NULL VOLUME LABEL";
|
|
} else {
|
|
VolumeLabel = FileContext->Info->VolumeLabel;
|
|
if (*VolumeLabel == 0x0000) {
|
|
VolumeLabel = L"NO VOLUME LABEL";
|
|
}
|
|
}
|
|
}
|
|
|
|
TempStr = MenuEntry->HelpString;
|
|
MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
|
|
ASSERT (MenuEntry->DisplayString != NULL);
|
|
UnicodeSPrint (
|
|
MenuEntry->DisplayString,
|
|
MAX_CHAR,
|
|
L"%s, [%s]",
|
|
VolumeLabel,
|
|
TempStr
|
|
);
|
|
OptionNumber++;
|
|
InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
|
|
}
|
|
}
|
|
|
|
if (NoSimpleFsHandles != 0) {
|
|
FreePool (SimpleFsHandle);
|
|
}
|
|
//
|
|
// Searching for handles that support Load File protocol
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiLoadFileProtocolGuid,
|
|
NULL,
|
|
&NoLoadFileHandles,
|
|
&LoadFileHandle
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
for (Index = 0; Index < NoLoadFileHandles; Index++) {
|
|
MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
|
|
if (NULL == MenuEntry) {
|
|
FreePool (LoadFileHandle);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
|
|
FileContext->IsRemovableMedia = FALSE;
|
|
FileContext->IsLoadFile = TRUE;
|
|
FileContext->Handle = LoadFileHandle[Index];
|
|
FileContext->IsRoot = TRUE;
|
|
|
|
FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);
|
|
|
|
MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
|
|
|
|
TempStr = MenuEntry->HelpString;
|
|
MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
|
|
ASSERT (MenuEntry->DisplayString != NULL);
|
|
UnicodeSPrint (
|
|
MenuEntry->DisplayString,
|
|
MAX_CHAR,
|
|
L"Load File [%s]",
|
|
TempStr
|
|
);
|
|
|
|
MenuEntry->OptionNumber = OptionNumber;
|
|
OptionNumber++;
|
|
InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
|
|
}
|
|
}
|
|
|
|
if (NoLoadFileHandles != 0) {
|
|
FreePool (LoadFileHandle);
|
|
}
|
|
|
|
//
|
|
// Add Legacy Boot Option Support Here
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiLegacyBiosProtocolGuid,
|
|
NULL,
|
|
(VOID **) &LegacyBios
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {
|
|
MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
|
|
if (NULL == MenuEntry) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
|
|
|
|
FileContext->IsRemovableMedia = FALSE;
|
|
FileContext->IsLoadFile = TRUE;
|
|
FileContext->IsBootLegacy = TRUE;
|
|
DeviceType = (UINT16) Index;
|
|
BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
|
|
BbsDevicePathNode.Header.SubType = BBS_BBS_DP;
|
|
SetDevicePathNodeLength (
|
|
&BbsDevicePathNode.Header,
|
|
sizeof (BBS_BBS_DEVICE_PATH)
|
|
);
|
|
BbsDevicePathNode.DeviceType = DeviceType;
|
|
BbsDevicePathNode.StatusFlag = 0;
|
|
BbsDevicePathNode.String[0] = 0;
|
|
DevicePath = AppendDevicePathNode (
|
|
EndDevicePath,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode
|
|
);
|
|
|
|
FileContext->DevicePath = DevicePath;
|
|
MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
|
|
|
|
TempStr = MenuEntry->HelpString;
|
|
MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
|
|
ASSERT (MenuEntry->DisplayString != NULL);
|
|
UnicodeSPrint (
|
|
MenuEntry->DisplayString,
|
|
MAX_CHAR,
|
|
L"Boot Legacy [%s]",
|
|
TempStr
|
|
);
|
|
MenuEntry->OptionNumber = OptionNumber;
|
|
OptionNumber++;
|
|
InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
|
|
}
|
|
}
|
|
//
|
|
// Remember how many file system options are here
|
|
//
|
|
FsOptionMenu.MenuNumber = OptionNumber;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Free resources allocated in Allocate Rountine.
|
|
|
|
@param FreeMenu Menu to be freed
|
|
**/
|
|
VOID
|
|
BOpt_FreeMenu (
|
|
BM_MENU_OPTION *FreeMenu
|
|
)
|
|
{
|
|
BM_MENU_ENTRY *MenuEntry;
|
|
while (!IsListEmpty (&FreeMenu->Head)) {
|
|
MenuEntry = CR (
|
|
FreeMenu->Head.ForwardLink,
|
|
BM_MENU_ENTRY,
|
|
Link,
|
|
BM_MENU_ENTRY_SIGNATURE
|
|
);
|
|
RemoveEntryList (&MenuEntry->Link);
|
|
BOpt_DestroyMenuEntry (MenuEntry);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Find files under current directory
|
|
All files and sub-directories in current directory
|
|
will be stored in DirectoryMenu for future use.
|
|
|
|
@param CallbackData The BMM context data.
|
|
@param MenuEntry The Menu Entry.
|
|
|
|
@retval EFI_SUCCESS Get files from current dir successfully.
|
|
@return Other value if can't get files from current dir.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
BOpt_FindFiles (
|
|
IN BMM_CALLBACK_DATA *CallbackData,
|
|
IN BM_MENU_ENTRY *MenuEntry
|
|
)
|
|
{
|
|
EFI_FILE_HANDLE NewDir;
|
|
EFI_FILE_HANDLE Dir;
|
|
EFI_FILE_INFO *DirInfo;
|
|
UINTN BufferSize;
|
|
UINTN DirBufferSize;
|
|
BM_MENU_ENTRY *NewMenuEntry;
|
|
BM_FILE_CONTEXT *FileContext;
|
|
BM_FILE_CONTEXT *NewFileContext;
|
|
UINTN Pass;
|
|
EFI_STATUS Status;
|
|
UINTN OptionNumber;
|
|
|
|
FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
|
|
Dir = FileContext->FHandle;
|
|
OptionNumber = 0;
|
|
//
|
|
// Open current directory to get files from it
|
|
//
|
|
Status = Dir->Open (
|
|
Dir,
|
|
&NewDir,
|
|
FileContext->FileName,
|
|
EFI_FILE_READ_ONLY,
|
|
0
|
|
);
|
|
if (!FileContext->IsRoot) {
|
|
Dir->Close (Dir);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
DirInfo = EfiLibFileInfo (NewDir);
|
|
if (DirInfo == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (!(DirInfo->Attribute & EFI_FILE_DIRECTORY)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
FileContext->DevicePath = FileDevicePath (
|
|
FileContext->Handle,
|
|
FileContext->FileName
|
|
);
|
|
|
|
DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
|
|
DirInfo = AllocateZeroPool (DirBufferSize);
|
|
if (DirInfo == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Get all files in current directory
|
|
// Pass 1 to get Directories
|
|
// Pass 2 to get files that are EFI images
|
|
//
|
|
for (Pass = 1; Pass <= 2; Pass++) {
|
|
NewDir->SetPosition (NewDir, 0);
|
|
for (;;) {
|
|
BufferSize = DirBufferSize;
|
|
Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
|
|
if (EFI_ERROR (Status) || BufferSize == 0) {
|
|
break;
|
|
}
|
|
|
|
if ((DirInfo->Attribute & EFI_FILE_DIRECTORY && Pass == 2) ||
|
|
(!(DirInfo->Attribute & EFI_FILE_DIRECTORY) && Pass == 1)
|
|
) {
|
|
//
|
|
// Pass 1 is for Directories
|
|
// Pass 2 is for file names
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (!(BOpt_IsEfiImageName (DirInfo->FileName) || DirInfo->Attribute & EFI_FILE_DIRECTORY)) {
|
|
//
|
|
// Slip file unless it is a directory entry or a .EFI file
|
|
//
|
|
continue;
|
|
}
|
|
|
|
NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
|
|
if (NULL == NewMenuEntry) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
|
|
NewFileContext->Handle = FileContext->Handle;
|
|
NewFileContext->FileName = BOpt_AppendFileName (
|
|
FileContext->FileName,
|
|
DirInfo->FileName
|
|
);
|
|
NewFileContext->FHandle = NewDir;
|
|
NewFileContext->DevicePath = FileDevicePath (
|
|
NewFileContext->Handle,
|
|
NewFileContext->FileName
|
|
);
|
|
NewMenuEntry->HelpString = NULL;
|
|
|
|
MenuEntry->DisplayStringToken = GetStringTokenFromDepository (
|
|
CallbackData,
|
|
FileOptionStrDepository
|
|
);
|
|
|
|
NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
|
|
|
|
if (NewFileContext->IsDir) {
|
|
BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
|
|
NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
|
|
|
|
UnicodeSPrint (
|
|
NewMenuEntry->DisplayString,
|
|
BufferSize,
|
|
L"<%s>",
|
|
DirInfo->FileName
|
|
);
|
|
|
|
} else {
|
|
NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);
|
|
}
|
|
|
|
NewFileContext->IsRoot = FALSE;
|
|
NewFileContext->IsLoadFile = FALSE;
|
|
NewFileContext->IsRemovableMedia = FALSE;
|
|
|
|
NewMenuEntry->OptionNumber = OptionNumber;
|
|
OptionNumber++;
|
|
InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
|
|
}
|
|
}
|
|
|
|
DirectoryMenu.MenuNumber = OptionNumber;
|
|
FreePool (DirInfo);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
|
|
|
|
@retval EFI_SUCCESS The function complete successfully.
|
|
@retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
BOpt_GetLegacyOptions (
|
|
VOID
|
|
)
|
|
{
|
|
BM_MENU_ENTRY *NewMenuEntry;
|
|
BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
UINT16 HddCount;
|
|
HDD_INFO *HddInfo;
|
|
UINT16 BbsCount;
|
|
BBS_TABLE *BbsTable;
|
|
UINTN Index;
|
|
CHAR16 DescString[100];
|
|
UINTN FDNum;
|
|
UINTN HDNum;
|
|
UINTN CDNum;
|
|
UINTN NETNum;
|
|
UINTN BEVNum;
|
|
|
|
NewMenuEntry = NULL;
|
|
HddInfo = NULL;
|
|
BbsTable = NULL;
|
|
BbsCount = 0;
|
|
|
|
//
|
|
// Initialize Bbs Table Context from BBS info data
|
|
//
|
|
InitializeListHead (&LegacyFDMenu.Head);
|
|
InitializeListHead (&LegacyHDMenu.Head);
|
|
InitializeListHead (&LegacyCDMenu.Head);
|
|
InitializeListHead (&LegacyNETMenu.Head);
|
|
InitializeListHead (&LegacyBEVMenu.Head);
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiLegacyBiosProtocolGuid,
|
|
NULL,
|
|
(VOID **) &LegacyBios
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = LegacyBios->GetBbsInfo (
|
|
LegacyBios,
|
|
&HddCount,
|
|
&HddInfo,
|
|
&BbsCount,
|
|
&BbsTable
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
FDNum = 0;
|
|
HDNum = 0;
|
|
CDNum = 0;
|
|
NETNum = 0;
|
|
BEVNum = 0;
|
|
|
|
for (Index = 0; Index < BbsCount; Index++) {
|
|
if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||
|
|
(BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority)
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);
|
|
if (NULL == NewMenuEntry) {
|
|
break;
|
|
}
|
|
|
|
NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
|
|
NewLegacyDevContext->BbsTable = &BbsTable[Index];
|
|
NewLegacyDevContext->Index = Index;
|
|
NewLegacyDevContext->BbsCount = BbsCount;
|
|
BdsBuildLegacyDevNameString (
|
|
&BbsTable[Index],
|
|
Index,
|
|
sizeof (DescString),
|
|
DescString
|
|
);
|
|
NewLegacyDevContext->Description = AllocateZeroPool (StrSize (DescString));
|
|
if (NULL == NewLegacyDevContext->Description) {
|
|
break;
|
|
}
|
|
|
|
CopyMem (NewLegacyDevContext->Description, DescString, StrSize (DescString));
|
|
NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
|
|
NewMenuEntry->HelpString = NULL;
|
|
|
|
switch (BbsTable[Index].DeviceType) {
|
|
case BBS_FLOPPY:
|
|
InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
|
|
FDNum++;
|
|
break;
|
|
|
|
case BBS_HARDDISK:
|
|
InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
|
|
HDNum++;
|
|
break;
|
|
|
|
case BBS_CDROM:
|
|
InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
|
|
CDNum++;
|
|
break;
|
|
|
|
case BBS_EMBED_NETWORK:
|
|
InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
|
|
NETNum++;
|
|
break;
|
|
|
|
case BBS_BEV_DEVICE:
|
|
InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
|
|
BEVNum++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index != BbsCount) {
|
|
BOpt_FreeLegacyOptions ();
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
LegacyFDMenu.MenuNumber = FDNum;
|
|
LegacyHDMenu.MenuNumber = HDNum;
|
|
LegacyCDMenu.MenuNumber = CDNum;
|
|
LegacyNETMenu.MenuNumber = NETNum;
|
|
LegacyBEVMenu.MenuNumber = BEVNum;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Free out resouce allocated from Legacy Boot Options.
|
|
|
|
**/
|
|
VOID
|
|
BOpt_FreeLegacyOptions (
|
|
VOID
|
|
)
|
|
{
|
|
BOpt_FreeMenu (&LegacyFDMenu);
|
|
BOpt_FreeMenu (&LegacyHDMenu);
|
|
BOpt_FreeMenu (&LegacyCDMenu);
|
|
BOpt_FreeMenu (&LegacyNETMenu);
|
|
BOpt_FreeMenu (&LegacyBEVMenu);
|
|
}
|
|
|
|
/**
|
|
|
|
Build the BootOptionMenu according to BootOrder Variable.
|
|
This Routine will access the Boot#### to get EFI_LOAD_OPTION.
|
|
|
|
@param CallbackData The BMM context data.
|
|
|
|
@return EFI_NOT_FOUND Fail to find "BootOrder" variable.
|
|
@return EFI_SUCESS Success build boot option menu.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
BOpt_GetBootOptions (
|
|
IN BMM_CALLBACK_DATA *CallbackData
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT16 BootString[10];
|
|
UINT8 *LoadOptionFromVar;
|
|
UINT8 *LoadOption;
|
|
UINTN BootOptionSize;
|
|
BOOLEAN BootNextFlag;
|
|
UINT16 *BootOrderList;
|
|
UINTN BootOrderListSize;
|
|
UINT16 *BootNext;
|
|
UINTN BootNextSize;
|
|
BM_MENU_ENTRY *NewMenuEntry;
|
|
BM_LOAD_CONTEXT *NewLoadContext;
|
|
UINT8 *LoadOptionPtr;
|
|
UINTN StringSize;
|
|
UINTN OptionalDataSize;
|
|
UINT8 *LoadOptionEnd;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
UINTN MenuCount;
|
|
UINT8 *Ptr;
|
|
|
|
MenuCount = 0;
|
|
BootOrderListSize = 0;
|
|
BootNextSize = 0;
|
|
BootOrderList = NULL;
|
|
BootNext = NULL;
|
|
LoadOptionFromVar = NULL;
|
|
BOpt_FreeMenu (&BootOptionMenu);
|
|
InitializeListHead (&BootOptionMenu.Head);
|
|
|
|
//
|
|
// Get the BootOrder from the Var
|
|
//
|
|
BootOrderList = BdsLibGetVariableAndSize (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
&BootOrderListSize
|
|
);
|
|
if (BootOrderList == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Get the BootNext from the Var
|
|
//
|
|
BootNext = BdsLibGetVariableAndSize (
|
|
L"BootNext",
|
|
&gEfiGlobalVariableGuid,
|
|
&BootNextSize
|
|
);
|
|
|
|
if (BootNext != NULL) {
|
|
if (BootNextSize != sizeof (UINT16)) {
|
|
FreePool (BootNext);
|
|
BootNext = NULL;
|
|
}
|
|
}
|
|
|
|
for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
|
|
UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
|
|
//
|
|
// Get all loadoptions from the VAR
|
|
//
|
|
LoadOptionFromVar = BdsLibGetVariableAndSize (
|
|
BootString,
|
|
&gEfiGlobalVariableGuid,
|
|
&BootOptionSize
|
|
);
|
|
if (LoadOptionFromVar == NULL) {
|
|
continue;
|
|
}
|
|
|
|
LoadOption = AllocateZeroPool (BootOptionSize);
|
|
if (LoadOption == NULL) {
|
|
continue;
|
|
}
|
|
|
|
CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);
|
|
FreePool (LoadOptionFromVar);
|
|
|
|
if (BootNext != NULL) {
|
|
BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
|
|
} else {
|
|
BootNextFlag = FALSE;
|
|
}
|
|
|
|
if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {
|
|
FreePool (LoadOption);
|
|
continue;
|
|
}
|
|
//
|
|
// BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.
|
|
// the buffer allocated already should be freed before returning.
|
|
//
|
|
NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
|
|
if (NULL == NewMenuEntry) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
|
|
|
|
LoadOptionPtr = LoadOption;
|
|
LoadOptionEnd = LoadOption + BootOptionSize;
|
|
|
|
NewMenuEntry->OptionNumber = BootOrderList[Index];
|
|
NewLoadContext->LoadOptionModified = FALSE;
|
|
NewLoadContext->Deleted = FALSE;
|
|
NewLoadContext->IsBootNext = BootNextFlag;
|
|
|
|
//
|
|
// Is a Legacy Device?
|
|
//
|
|
Ptr = (UINT8 *) LoadOption;
|
|
|
|
//
|
|
// Attribute = *(UINT32 *)Ptr;
|
|
//
|
|
Ptr += sizeof (UINT32);
|
|
|
|
//
|
|
// FilePathSize = *(UINT16 *)Ptr;
|
|
//
|
|
Ptr += sizeof (UINT16);
|
|
|
|
//
|
|
// Description = (CHAR16 *)Ptr;
|
|
//
|
|
Ptr += StrSize ((CHAR16 *) Ptr);
|
|
|
|
//
|
|
// Now Ptr point to Device Path
|
|
//
|
|
DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
|
|
if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
|
|
NewLoadContext->IsLegacy = TRUE;
|
|
} else {
|
|
NewLoadContext->IsLegacy = FALSE;
|
|
}
|
|
//
|
|
// LoadOption is a pointer type of UINT8
|
|
// for easy use with following LOAD_OPTION
|
|
// embedded in this struct
|
|
//
|
|
NewLoadContext->LoadOption = LoadOption;
|
|
NewLoadContext->LoadOptionSize = BootOptionSize;
|
|
|
|
NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
|
|
NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
|
|
|
|
NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
|
|
|
|
LoadOptionPtr += sizeof (UINT32);
|
|
|
|
NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
|
|
LoadOptionPtr += sizeof (UINT16);
|
|
|
|
StringSize = StrSize ((UINT16 *) LoadOptionPtr);
|
|
NewLoadContext->Description = AllocateZeroPool (StringSize);
|
|
ASSERT (NewLoadContext->Description != NULL);
|
|
CopyMem (
|
|
NewLoadContext->Description,
|
|
(UINT16 *) LoadOptionPtr,
|
|
StringSize
|
|
);
|
|
NewMenuEntry->DisplayString = NewLoadContext->Description;
|
|
|
|
LoadOptionPtr += StringSize;
|
|
|
|
NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
|
|
ASSERT (NewLoadContext->FilePathList != NULL);
|
|
CopyMem (
|
|
NewLoadContext->FilePathList,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
|
|
NewLoadContext->FilePathListLength
|
|
);
|
|
|
|
NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
|
|
NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
|
|
CallbackData,
|
|
BootOptionStrDepository
|
|
);
|
|
NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
|
|
CallbackData,
|
|
BootOptionHelpStrDepository
|
|
);
|
|
LoadOptionPtr += NewLoadContext->FilePathListLength;
|
|
|
|
if (LoadOptionPtr < LoadOptionEnd) {
|
|
OptionalDataSize = BootOptionSize -
|
|
sizeof (UINT32) -
|
|
sizeof (UINT16) -
|
|
StringSize -
|
|
NewLoadContext->FilePathListLength;
|
|
|
|
NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
|
|
ASSERT (NewLoadContext->OptionalData != NULL);
|
|
CopyMem (
|
|
NewLoadContext->OptionalData,
|
|
LoadOptionPtr,
|
|
OptionalDataSize
|
|
);
|
|
|
|
NewLoadContext->OptionalDataSize = OptionalDataSize;
|
|
}
|
|
|
|
InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
|
|
MenuCount++;
|
|
}
|
|
|
|
if (BootNext != NULL) {
|
|
FreePool (BootNext);
|
|
}
|
|
if (BootOrderList != NULL) {
|
|
FreePool (BootOrderList);
|
|
}
|
|
BootOptionMenu.MenuNumber = MenuCount;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Append file name to existing file name.
|
|
|
|
@param Str1 The existing file name
|
|
@param Str2 The file name to be appended
|
|
|
|
@return Allocate a new string to hold the appended result.
|
|
Caller is responsible to free the returned string.
|
|
|
|
**/
|
|
CHAR16 *
|
|
BOpt_AppendFileName (
|
|
IN CHAR16 *Str1,
|
|
IN CHAR16 *Str2
|
|
)
|
|
{
|
|
UINTN Size1;
|
|
UINTN Size2;
|
|
CHAR16 *Str;
|
|
CHAR16 *TmpStr;
|
|
CHAR16 *Ptr;
|
|
CHAR16 *LastSlash;
|
|
|
|
Size1 = StrSize (Str1);
|
|
Size2 = StrSize (Str2);
|
|
Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
|
|
ASSERT (Str != NULL);
|
|
|
|
TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
|
|
ASSERT (TmpStr != NULL);
|
|
|
|
StrCat (Str, Str1);
|
|
if (!((*Str == '\\') && (*(Str + 1) == 0))) {
|
|
StrCat (Str, L"\\");
|
|
}
|
|
|
|
StrCat (Str, Str2);
|
|
|
|
Ptr = Str;
|
|
LastSlash = Str;
|
|
while (*Ptr != 0) {
|
|
if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
|
|
//
|
|
// Convert "\Name\..\" to "\"
|
|
// DO NOT convert the .. if it is at the end of the string. This will
|
|
// break the .. behavior in changing directories.
|
|
//
|
|
|
|
//
|
|
// Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
|
|
// that overlap.
|
|
//
|
|
StrCpy (TmpStr, Ptr + 3);
|
|
StrCpy (LastSlash, TmpStr);
|
|
Ptr = LastSlash;
|
|
} else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
|
|
//
|
|
// Convert a "\.\" to a "\"
|
|
//
|
|
|
|
//
|
|
// Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
|
|
// that overlap.
|
|
//
|
|
StrCpy (TmpStr, Ptr + 2);
|
|
StrCpy (Ptr, TmpStr);
|
|
Ptr = LastSlash;
|
|
} else if (*Ptr == '\\') {
|
|
LastSlash = Ptr;
|
|
}
|
|
|
|
Ptr++;
|
|
}
|
|
|
|
FreePool (TmpStr);
|
|
|
|
return Str;
|
|
}
|
|
|
|
/**
|
|
|
|
Check whether current FileName point to a valid
|
|
Efi Image File.
|
|
|
|
@param FileName File need to be checked.
|
|
|
|
@retval TRUE Is Efi Image
|
|
@retval FALSE Not a valid Efi Image
|
|
|
|
**/
|
|
BOOLEAN
|
|
BOpt_IsEfiImageName (
|
|
IN UINT16 *FileName
|
|
)
|
|
{
|
|
//
|
|
// Search for ".efi" extension
|
|
//
|
|
while (*FileName != L'\0') {
|
|
if (FileName[0] == '.') {
|
|
if (FileName[1] == 'e' || FileName[1] == 'E') {
|
|
if (FileName[2] == 'f' || FileName[2] == 'F') {
|
|
if (FileName[3] == 'i' || FileName[3] == 'I') {
|
|
return TRUE;
|
|
} else if (FileName[3] == 0x0000) {
|
|
return FALSE;
|
|
}
|
|
} else if (FileName[2] == 0x0000) {
|
|
return FALSE;
|
|
}
|
|
} else if (FileName[1] == 0x0000) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
FileName += 1;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
|
|
Check whether current FileName point to a valid Efi Application
|
|
|
|
@param Dir Pointer to current Directory
|
|
@param FileName Pointer to current File name.
|
|
|
|
@retval TRUE Is a valid Efi Application
|
|
@retval FALSE not a valid Efi Application
|
|
|
|
**/
|
|
BOOLEAN
|
|
BOpt_IsEfiApp (
|
|
IN EFI_FILE_HANDLE Dir,
|
|
IN UINT16 *FileName
|
|
)
|
|
{
|
|
UINTN BufferSize;
|
|
EFI_IMAGE_DOS_HEADER DosHdr;
|
|
UINT16 Subsystem;
|
|
EFI_FILE_HANDLE File;
|
|
EFI_STATUS Status;
|
|
EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
|
|
|
|
Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
|
|
File->Read (File, &BufferSize, &DosHdr);
|
|
if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
|
|
File->Close (File);
|
|
return FALSE;
|
|
}
|
|
|
|
File->SetPosition (File, DosHdr.e_lfanew);
|
|
BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
|
|
File->Read (File, &BufferSize, &PeHdr);
|
|
if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
|
|
File->Close (File);
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Determine PE type and read subsytem
|
|
//
|
|
if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;
|
|
} else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
|
Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
|
|
File->Close (File);
|
|
return TRUE;
|
|
} else {
|
|
File->Close (File);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Find drivers that will be added as Driver#### variables from handles
|
|
in current system environment
|
|
All valid handles in the system except those consume SimpleFs, LoadFile
|
|
are stored in DriverMenu for future use.
|
|
|
|
@retval EFI_SUCCESS The function complets successfully.
|
|
@return Other value if failed to build the DriverMenu.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
BOpt_FindDrivers (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN NoDevicePathHandles;
|
|
EFI_HANDLE *DevicePathHandle;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
BM_MENU_ENTRY *NewMenuEntry;
|
|
BM_HANDLE_CONTEXT *NewHandleContext;
|
|
EFI_HANDLE CurHandle;
|
|
UINTN OptionNumber;
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
|
|
EFI_LOAD_FILE_PROTOCOL *LoadFile;
|
|
|
|
SimpleFs = NULL;
|
|
LoadFile = NULL;
|
|
|
|
InitializeListHead (&DriverMenu.Head);
|
|
|
|
//
|
|
// At first, get all handles that support Device Path
|
|
// protocol which is the basic requirement for
|
|
// Driver####
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiDevicePathProtocolGuid,
|
|
NULL,
|
|
&NoDevicePathHandles,
|
|
&DevicePathHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
OptionNumber = 0;
|
|
for (Index = 0; Index < NoDevicePathHandles; Index++) {
|
|
CurHandle = DevicePathHandle[Index];
|
|
|
|
Status = gBS->HandleProtocol (
|
|
CurHandle,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
(VOID **) &SimpleFs
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
CurHandle,
|
|
&gEfiLoadFileProtocolGuid,
|
|
(VOID **) &LoadFile
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
|
|
if (NULL == NewMenuEntry) {
|
|
FreePool (DevicePathHandle);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
|
|
NewHandleContext->Handle = CurHandle;
|
|
NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
|
|
NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);
|
|
NewMenuEntry->HelpString = NULL;
|
|
NewMenuEntry->OptionNumber = OptionNumber;
|
|
OptionNumber++;
|
|
InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
|
|
|
|
}
|
|
|
|
if (DevicePathHandle != NULL) {
|
|
FreePool (DevicePathHandle);
|
|
}
|
|
|
|
DriverMenu.MenuNumber = OptionNumber;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Get the Option Number that has not been allocated for use.
|
|
|
|
@return The available Option Number.
|
|
|
|
**/
|
|
UINT16
|
|
BOpt_GetBootOptionNumber (
|
|
VOID
|
|
)
|
|
{
|
|
BM_MENU_ENTRY *NewMenuEntry;
|
|
UINT16 *BootOrderList;
|
|
UINTN BootOrderListSize;
|
|
UINT16 Number;
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
BOOLEAN Found;
|
|
CHAR16 StrTemp[100];
|
|
UINT16 *OptionBuffer;
|
|
UINTN OptionSize;
|
|
|
|
BootOrderListSize = 0;
|
|
BootOrderList = NULL;
|
|
|
|
BootOrderList = BdsLibGetVariableAndSize (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
&BootOrderListSize
|
|
);
|
|
if (BootOrderList != NULL) {
|
|
//
|
|
// already have Boot####
|
|
//
|
|
// AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);
|
|
//
|
|
for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
|
|
Found = TRUE;
|
|
for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) {
|
|
NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2);
|
|
if (Index == NewMenuEntry->OptionNumber) {
|
|
Found = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Found) {
|
|
UnicodeSPrint (StrTemp, 100, L"Boot%04x", Index);
|
|
DEBUG((DEBUG_ERROR,"INdex= %s\n", StrTemp));
|
|
OptionBuffer = BdsLibGetVariableAndSize (
|
|
StrTemp,
|
|
&gEfiGlobalVariableGuid,
|
|
&OptionSize
|
|
);
|
|
if (NULL == OptionBuffer) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// end for Index
|
|
//
|
|
Number = (UINT16) Index;
|
|
} else {
|
|
//
|
|
// No Boot####
|
|
//
|
|
Number = 0;
|
|
}
|
|
|
|
return Number;
|
|
}
|
|
|
|
/**
|
|
|
|
Get the Option Number that is not in use.
|
|
|
|
@return The unused Option Number.
|
|
|
|
**/
|
|
UINT16
|
|
BOpt_GetDriverOptionNumber (
|
|
VOID
|
|
)
|
|
{
|
|
BM_MENU_ENTRY *NewMenuEntry;
|
|
UINT16 *DriverOrderList;
|
|
UINTN DriverOrderListSize;
|
|
UINT16 Number;
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
BOOLEAN Found;
|
|
|
|
DriverOrderListSize = 0;
|
|
DriverOrderList = NULL;
|
|
|
|
DriverOrderList = BdsLibGetVariableAndSize (
|
|
L"DriverOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
&DriverOrderListSize
|
|
);
|
|
if (DriverOrderList != NULL) {
|
|
//
|
|
// already have Driver####
|
|
//
|
|
// AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);
|
|
//
|
|
for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
|
|
Found = TRUE;
|
|
for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) {
|
|
NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2);
|
|
if (Index == NewMenuEntry->OptionNumber) {
|
|
Found = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Found) {
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// end for Index
|
|
//
|
|
Number = (UINT16) Index;
|
|
} else {
|
|
//
|
|
// No Driver####
|
|
//
|
|
Number = 0;
|
|
}
|
|
|
|
return Number;
|
|
}
|
|
|
|
/**
|
|
|
|
Build up all DriverOptionMenu
|
|
|
|
@param CallbackData The BMM context data.
|
|
|
|
@retval EFI_SUCESS The functin completes successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
|
|
@retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
BOpt_GetDriverOptions (
|
|
IN BMM_CALLBACK_DATA *CallbackData
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT16 DriverString[12];
|
|
UINT8 *LoadOptionFromVar;
|
|
UINT8 *LoadOption;
|
|
UINTN DriverOptionSize;
|
|
|
|
UINT16 *DriverOrderList;
|
|
UINTN DriverOrderListSize;
|
|
BM_MENU_ENTRY *NewMenuEntry;
|
|
BM_LOAD_CONTEXT *NewLoadContext;
|
|
UINT8 *LoadOptionPtr;
|
|
UINTN StringSize;
|
|
UINTN OptionalDataSize;
|
|
UINT8 *LoadOptionEnd;
|
|
|
|
DriverOrderListSize = 0;
|
|
DriverOrderList = NULL;
|
|
DriverOptionSize = 0;
|
|
LoadOptionFromVar = NULL;
|
|
BOpt_FreeMenu (&DriverOptionMenu);
|
|
InitializeListHead (&DriverOptionMenu.Head);
|
|
//
|
|
// Get the DriverOrder from the Var
|
|
//
|
|
DriverOrderList = BdsLibGetVariableAndSize (
|
|
L"DriverOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
&DriverOrderListSize
|
|
);
|
|
if (DriverOrderList == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
|
|
UnicodeSPrint (
|
|
DriverString,
|
|
sizeof (DriverString),
|
|
L"Driver%04x",
|
|
DriverOrderList[Index]
|
|
);
|
|
//
|
|
// Get all loadoptions from the VAR
|
|
//
|
|
LoadOptionFromVar = BdsLibGetVariableAndSize (
|
|
DriverString,
|
|
&gEfiGlobalVariableGuid,
|
|
&DriverOptionSize
|
|
);
|
|
if (LoadOptionFromVar == NULL) {
|
|
continue;
|
|
}
|
|
|
|
LoadOption = AllocateZeroPool (DriverOptionSize);
|
|
if (LoadOption == NULL) {
|
|
continue;
|
|
}
|
|
|
|
CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
|
|
FreePool (LoadOptionFromVar);
|
|
|
|
NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
|
|
if (NULL == NewMenuEntry) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
|
|
LoadOptionPtr = LoadOption;
|
|
LoadOptionEnd = LoadOption + DriverOptionSize;
|
|
NewMenuEntry->OptionNumber = DriverOrderList[Index];
|
|
NewLoadContext->LoadOptionModified = FALSE;
|
|
NewLoadContext->Deleted = FALSE;
|
|
NewLoadContext->IsLegacy = FALSE;
|
|
|
|
//
|
|
// LoadOption is a pointer type of UINT8
|
|
// for easy use with following LOAD_OPTION
|
|
// embedded in this struct
|
|
//
|
|
NewLoadContext->LoadOption = LoadOption;
|
|
NewLoadContext->LoadOptionSize = DriverOptionSize;
|
|
|
|
NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
|
|
NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
|
|
|
|
NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
|
|
|
|
LoadOptionPtr += sizeof (UINT32);
|
|
|
|
NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
|
|
LoadOptionPtr += sizeof (UINT16);
|
|
|
|
StringSize = StrSize ((UINT16 *) LoadOptionPtr);
|
|
NewLoadContext->Description = AllocateZeroPool (StringSize);
|
|
ASSERT (NewLoadContext->Description != NULL);
|
|
CopyMem (
|
|
NewLoadContext->Description,
|
|
(UINT16 *) LoadOptionPtr,
|
|
StringSize
|
|
);
|
|
NewMenuEntry->DisplayString = NewLoadContext->Description;
|
|
|
|
LoadOptionPtr += StringSize;
|
|
|
|
NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
|
|
ASSERT (NewLoadContext->FilePathList != NULL);
|
|
CopyMem (
|
|
NewLoadContext->FilePathList,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
|
|
NewLoadContext->FilePathListLength
|
|
);
|
|
|
|
NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
|
|
NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
|
|
CallbackData,
|
|
DriverOptionStrDepository
|
|
);
|
|
NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
|
|
CallbackData,
|
|
DriverOptionHelpStrDepository
|
|
);
|
|
LoadOptionPtr += NewLoadContext->FilePathListLength;
|
|
|
|
if (LoadOptionPtr < LoadOptionEnd) {
|
|
OptionalDataSize = DriverOptionSize -
|
|
sizeof (UINT32) -
|
|
sizeof (UINT16) -
|
|
StringSize -
|
|
NewLoadContext->FilePathListLength;
|
|
|
|
NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
|
|
ASSERT (NewLoadContext->OptionalData != NULL);
|
|
CopyMem (
|
|
NewLoadContext->OptionalData,
|
|
LoadOptionPtr,
|
|
OptionalDataSize
|
|
);
|
|
|
|
NewLoadContext->OptionalDataSize = OptionalDataSize;
|
|
}
|
|
|
|
InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
|
|
|
|
}
|
|
|
|
if (DriverOrderList != NULL) {
|
|
FreePool (DriverOrderList);
|
|
}
|
|
DriverOptionMenu.MenuNumber = Index;
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|