838 lines
18 KiB
C
838 lines
18 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1998 Intel Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
bcfg.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Shell app "bcfg"
|
||
|
|
||
|
Boot time driver config
|
||
|
|
||
|
Revision History
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "shell.h"
|
||
|
|
||
|
#define MAX_ENV_SIZE 1024
|
||
|
|
||
|
|
||
|
#define BCFG_NONE 0
|
||
|
#define BCFG_DUMP 1
|
||
|
#define BCFG_MOVE 2
|
||
|
#define BCFG_REMOVE 3
|
||
|
#define BCFG_ADD 4
|
||
|
#define BCFG_USAGE 5
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
UINT32 Attributes;
|
||
|
CHAR16 *Description;
|
||
|
EFI_DEVICE_PATH *FilePath;
|
||
|
VOID *LoadOptions;
|
||
|
UINTN LoadOptionsSize;
|
||
|
CHAR16 *FilePathStr;
|
||
|
} BCFG_LOAD_OPTION;
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
EFI_STATUS
|
||
|
InitializeBCfg (
|
||
|
IN EFI_HANDLE ImageHandle,
|
||
|
IN EFI_SYSTEM_TABLE *SystemTable
|
||
|
);
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DumpFileInfo (
|
||
|
IN SHELL_FILE_ARG *Arg
|
||
|
);
|
||
|
|
||
|
|
||
|
VOID
|
||
|
BCfgDumpBootList (
|
||
|
IN CHAR16 *BootOrder,
|
||
|
IN CHAR16 *BootOption
|
||
|
);
|
||
|
|
||
|
BCFG_LOAD_OPTION *
|
||
|
BCfgParseLoadOption (
|
||
|
UINT8 *Data,
|
||
|
UINTN DataSize
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
BCfgFreeLoadOption (
|
||
|
BCFG_LOAD_OPTION *Option
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
BCfgSetOperation (
|
||
|
UINTN *OldOper,
|
||
|
UINTN NewOper
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
BCfgUsage (
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
BCfgRemove (
|
||
|
IN UINTN Position
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
BCfgMove (
|
||
|
IN UINTN Src,
|
||
|
IN UINTN Dest
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
BCfgAdd (
|
||
|
IN UINTN Position,
|
||
|
IN CHAR16 *File,
|
||
|
IN CHAR16 *Desc
|
||
|
);
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
BOOLEAN BCfgVerbose = FALSE;
|
||
|
|
||
|
/*
|
||
|
* Selected list
|
||
|
*/
|
||
|
|
||
|
CHAR16 *BCfgSelOrder;
|
||
|
CHAR16 *BCfgSelOption;
|
||
|
CHAR16 *BCfgSelName;
|
||
|
UINT32 BCfgAttributes;
|
||
|
|
||
|
/*
|
||
|
* Scratch memory
|
||
|
*/
|
||
|
|
||
|
UINTN BCfgOrderCount;
|
||
|
UINT16 *BCfgOrder;
|
||
|
UINT8 *BCfgData;
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
EFI_DRIVER_ENTRY_POINT(InitializeBCfg)
|
||
|
|
||
|
EFI_STATUS
|
||
|
InitializeBCfg (
|
||
|
IN EFI_HANDLE ImageHandle,
|
||
|
IN EFI_SYSTEM_TABLE *SystemTable
|
||
|
)
|
||
|
{
|
||
|
CHAR16 **Argv;
|
||
|
UINTN Argc;
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Index, BufferSize;
|
||
|
UINTN No1, No2;
|
||
|
CHAR16 *p, *File, *Desc;
|
||
|
UINTN Oper;
|
||
|
|
||
|
/*
|
||
|
* Check to see if the app is to install as a "internal command"
|
||
|
* to the shell
|
||
|
*/
|
||
|
|
||
|
InstallInternalShellCommand (
|
||
|
ImageHandle, SystemTable, InitializeBCfg,
|
||
|
L"bcfg", /* command */
|
||
|
L"bcfg -?", /* command syntax */
|
||
|
L"Configures boot driver & load options", /* 1 line descriptor */
|
||
|
NULL /* command help page */
|
||
|
);
|
||
|
|
||
|
/*
|
||
|
* We are not being installed as an internal command driver, initialize
|
||
|
* as an nshell app and run
|
||
|
*/
|
||
|
|
||
|
InitializeShellApplication (ImageHandle, SystemTable);
|
||
|
Argv = SI->Argv;
|
||
|
Argc = SI->Argc;
|
||
|
|
||
|
BCfgVerbose = FALSE;
|
||
|
BCfgSelName = NULL;
|
||
|
BCfgSelOrder = NULL;
|
||
|
BCfgOrderCount = 0;
|
||
|
|
||
|
No1 = 0;
|
||
|
No2 = 0;
|
||
|
File = NULL;
|
||
|
Desc = NULL;
|
||
|
|
||
|
BCfgOrder = AllocatePool(MAX_ENV_SIZE + 32);
|
||
|
BCfgData = AllocatePool(MAX_ENV_SIZE + 32);
|
||
|
|
||
|
/*
|
||
|
* Scan args for flags
|
||
|
*/
|
||
|
|
||
|
Oper = BCFG_NONE;
|
||
|
for (Index = 1; Index < Argc; Index += 1) {
|
||
|
p = Argv[Index];
|
||
|
if (StrCmp(p, L"?") == 0) {
|
||
|
BCfgSetOperation (&Oper, BCFG_USAGE);
|
||
|
} else if (StrCmp(p, L"driver") == 0) {
|
||
|
BCfgSelOrder = VarDriverOrder;
|
||
|
BCfgSelOption = VarDriverOption;
|
||
|
BCfgSelName = L"boot driver";
|
||
|
} else if (StrCmp(p, L"boot") == 0) {
|
||
|
BCfgSelOrder = VarBootOrder;
|
||
|
BCfgSelOption = VarBootOption;
|
||
|
BCfgSelName = L"boot option";
|
||
|
} else if (StrCmp(p, L"dump") == 0) {
|
||
|
BCfgSetOperation (&Oper, BCFG_DUMP);
|
||
|
} else if (StrCmp(p, L"v") == 0) {
|
||
|
BCfgVerbose = TRUE;
|
||
|
} else if (StrCmp(p, L"rm") == 0) {
|
||
|
Index += 1;
|
||
|
if (Index < Argc) {
|
||
|
No1 = Atoi(Argv[Index]);
|
||
|
}
|
||
|
|
||
|
BCfgSetOperation (&Oper, BCFG_REMOVE);
|
||
|
|
||
|
} else if (StrCmp(p, L"mv") == 0) {
|
||
|
Index += 1;
|
||
|
if (Index < Argc) {
|
||
|
No1 = Atoi(Argv[Index]);
|
||
|
}
|
||
|
|
||
|
Index += 1;
|
||
|
if (Index < Argc) {
|
||
|
No2 = Atoi(Argv[Index]);
|
||
|
}
|
||
|
|
||
|
BCfgSetOperation (&Oper, BCFG_MOVE);
|
||
|
|
||
|
} else if (StrCmp(p, L"add") == 0) {
|
||
|
Index += 1;
|
||
|
if (Index < Argc) {
|
||
|
No1 = Atoi(Argv[Index]);
|
||
|
}
|
||
|
Index += 1;
|
||
|
if (Index < Argc) {
|
||
|
File = Argv[Index];
|
||
|
}
|
||
|
Index += 1;
|
||
|
if (Index < Argc) {
|
||
|
Desc = Argv[Index];
|
||
|
}
|
||
|
|
||
|
BCfgSetOperation (&Oper, BCFG_ADD);
|
||
|
|
||
|
} else {
|
||
|
Print (L"bfg: unknown flag '%h'\n", p);
|
||
|
Oper = BCFG_USAGE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (BCfgSelOrder) {
|
||
|
/*
|
||
|
* Read the boot order var
|
||
|
*/
|
||
|
|
||
|
BufferSize = MAX_ENV_SIZE;
|
||
|
Status = RT->GetVariable (
|
||
|
BCfgSelOrder,
|
||
|
&EfiGlobalVariable,
|
||
|
&BCfgAttributes,
|
||
|
&BufferSize,
|
||
|
BCfgOrder
|
||
|
);
|
||
|
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
BufferSize = 0;
|
||
|
BCfgAttributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS;
|
||
|
if (BCfgSelOrder == VarBootOrder) {
|
||
|
BCfgAttributes = BCfgAttributes | EFI_VARIABLE_RUNTIME_ACCESS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BCfgOrderCount = BufferSize / sizeof(UINT16);
|
||
|
}
|
||
|
|
||
|
if (Oper == BCFG_NONE) {
|
||
|
Oper = BCFG_USAGE;
|
||
|
}
|
||
|
|
||
|
if (Oper != BCFG_USAGE && !BCfgSelName) {
|
||
|
Print (L"bcfg: must supply 'driver' or 'boot'\n");
|
||
|
Oper = BCFG_NONE;
|
||
|
}
|
||
|
|
||
|
switch (Oper) {
|
||
|
case BCFG_NONE:
|
||
|
break;
|
||
|
|
||
|
case BCFG_USAGE:
|
||
|
BCfgUsage();
|
||
|
break;
|
||
|
|
||
|
case BCFG_DUMP:
|
||
|
Print (L"The %s list is:\n", BCfgSelName);
|
||
|
BCfgDumpBootList (BCfgSelOrder, BCfgSelOption);
|
||
|
break;
|
||
|
|
||
|
case BCFG_ADD:
|
||
|
BCfgAdd (No1, File, Desc);
|
||
|
break;
|
||
|
|
||
|
case BCFG_MOVE:
|
||
|
BCfgMove (No1, No2);
|
||
|
break;
|
||
|
|
||
|
case BCFG_REMOVE:
|
||
|
BCfgRemove (No1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Done
|
||
|
*/
|
||
|
|
||
|
if (BCfgOrder) {
|
||
|
FreePool (BCfgOrder);
|
||
|
}
|
||
|
|
||
|
if (BCfgData) {
|
||
|
FreePool (BCfgData);
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BCfgSetOperation (
|
||
|
UINTN *OldOper,
|
||
|
UINTN NewOper
|
||
|
)
|
||
|
{
|
||
|
if (*OldOper != BCFG_NONE && *OldOper != BCFG_USAGE) {
|
||
|
Print (L"bcfg: only one operation may be specified at a time\n");
|
||
|
*OldOper = BCFG_USAGE;
|
||
|
}
|
||
|
|
||
|
*OldOper = NewOper;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
BCfgUsage (
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
|
||
|
Print (L"bcfg driver|boot [dump [-v]] [add # file \"desc\"] [rm #] [mv # #]\n");
|
||
|
Print (L" driver selects boot driver list\n");
|
||
|
Print (L" boot selects boot option list\n");
|
||
|
Print (L" dump dumps selected list\n");
|
||
|
Print (L" v dumps verbose (includes load options)\n");
|
||
|
Print (L" add add 'file' with 'desc' at position #\n");
|
||
|
Print (L" rm remove #\n");
|
||
|
Print (L" mv move # to #\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
BCfgAdd (
|
||
|
IN UINTN Position,
|
||
|
IN CHAR16 *File,
|
||
|
IN CHAR16 *Desc
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_DEVICE_PATH *DevicePath, *FilePath, *FileNode;
|
||
|
CHAR16 *Str, *p;
|
||
|
UINT8 *p8;
|
||
|
SHELL_FILE_ARG *Arg;
|
||
|
LIST_ENTRY FileList;
|
||
|
CHAR16 OptionStr[40];
|
||
|
UINTN DescSize, FilePathSize;
|
||
|
BOOLEAN Found;
|
||
|
UINTN Target, Index;
|
||
|
|
||
|
|
||
|
Str = NULL;
|
||
|
FilePath = NULL;
|
||
|
FileNode = NULL;
|
||
|
InitializeListHead (&FileList);
|
||
|
|
||
|
if (Position < 1) {
|
||
|
Position = 1;
|
||
|
}
|
||
|
|
||
|
Position = Position - 1;
|
||
|
|
||
|
if (Position > BCfgOrderCount) {
|
||
|
Position = BCfgOrderCount;
|
||
|
}
|
||
|
|
||
|
if (!File || !Desc) {
|
||
|
Print (L"bcfg: missing parameter for 'add' operation\n");
|
||
|
Print (L"cfg: driver|boot add # file \"desc\"\n");
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Get file info
|
||
|
*/
|
||
|
|
||
|
ShellFileMetaArg (File, &FileList);
|
||
|
|
||
|
/*
|
||
|
* If filename expadned to multiple names, fail
|
||
|
*/
|
||
|
|
||
|
if (FileList.Flink->Flink != &FileList) {
|
||
|
Print (L"bcfg: too many source files\n");
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
Arg = CR(FileList.Flink, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
|
||
|
Status = Arg->Status;
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
Print (L"bcfg: file %hs - %r\n", Arg->FileName, Status);
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Build FilePath to the filename
|
||
|
*/
|
||
|
|
||
|
/* split full name at device string */
|
||
|
for(p=Arg->FullName; *p && *p != ':'; p++) ;
|
||
|
|
||
|
if (!*p) {
|
||
|
Print (L"bcfg: unsupported file name '%hs'\n", Arg->FullName);
|
||
|
Status = EFI_UNSUPPORTED;
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* get the device path */
|
||
|
*p = 0;
|
||
|
DevicePath = (EFI_DEVICE_PATH *) ShellGetMap(Arg->FullName);
|
||
|
if (!DevicePath) {
|
||
|
Print (L"bcfg: no device path for %s\n", Arg->FullName);
|
||
|
Status = EFI_UNSUPPORTED;
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
/* append the file */
|
||
|
FileNode = FileDevicePath(NULL, p+1);
|
||
|
FilePath = AppendDevicePath(DevicePath, FileNode);
|
||
|
|
||
|
/*
|
||
|
* Find a free target # (bugbug: brute force implementation)
|
||
|
*/
|
||
|
|
||
|
Found = FALSE;
|
||
|
for (Target=1; Target < 0xFFFF; Target += 1) {
|
||
|
Found = TRUE;
|
||
|
for (Index=0; Index < BCfgOrderCount; Index += 1) {
|
||
|
if (BCfgOrder[Index] == Target) {
|
||
|
Found = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Found) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Target == 0xFFFF) {
|
||
|
Print (L"bcfg: Failed to find available variable name\n");
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
Print (L"Target = %d\n", Target);
|
||
|
|
||
|
/*
|
||
|
* Add the option
|
||
|
*/
|
||
|
|
||
|
|
||
|
DescSize = StrSize(Desc);
|
||
|
FilePathSize = DevicePathSize(FilePath);
|
||
|
|
||
|
p8 = BCfgData;
|
||
|
*((UINT32 *) p8) = 0; /* Attributes */
|
||
|
p8 += sizeof (UINT32);
|
||
|
CopyMem (p8, Desc, DescSize);
|
||
|
p8 += DescSize;
|
||
|
CopyMem (p8, FilePath, FilePathSize);
|
||
|
|
||
|
SPrint (OptionStr, sizeof(OptionStr), BCfgSelOption, Target);
|
||
|
Status = RT->SetVariable (
|
||
|
OptionStr,
|
||
|
&EfiGlobalVariable,
|
||
|
BCfgAttributes,
|
||
|
sizeof(UINT32) + DescSize + FilePathSize,
|
||
|
BCfgData
|
||
|
);
|
||
|
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
Print (L"bcfg: failed to add %hs - %hr\n", OptionStr, Status);
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Insert target into order list
|
||
|
*/
|
||
|
|
||
|
BCfgOrderCount += 1;
|
||
|
for (Index=BCfgOrderCount-1; Index > Position; Index -= 1) {
|
||
|
BCfgOrder[Index] = BCfgOrder[Index-1];
|
||
|
}
|
||
|
|
||
|
BCfgOrder[Position] = (UINT16) Target;
|
||
|
Status = RT->SetVariable (
|
||
|
BCfgSelOrder,
|
||
|
&EfiGlobalVariable,
|
||
|
BCfgAttributes,
|
||
|
BCfgOrderCount * sizeof(UINT16),
|
||
|
BCfgOrder
|
||
|
);
|
||
|
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
Print (L"bcfg: failed to update %hs - %hr\n", BCfgSelOrder, Status);
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Done
|
||
|
*/
|
||
|
|
||
|
Print (L"bcfg: %s added as %d\n", BCfgSelName, Position+1);
|
||
|
|
||
|
Done:
|
||
|
if (FileNode) {
|
||
|
FreePool (FileNode);
|
||
|
}
|
||
|
|
||
|
if (FilePath) {
|
||
|
FreePool (FilePath);
|
||
|
}
|
||
|
|
||
|
if (Str) {
|
||
|
FreePool(Str);
|
||
|
}
|
||
|
|
||
|
ShellFreeFileList (&FileList);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
BCfgRemove (
|
||
|
IN UINTN Position
|
||
|
)
|
||
|
{
|
||
|
CHAR16 OptionStr[40];
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Index;
|
||
|
UINT16 Target;
|
||
|
|
||
|
|
||
|
if (Position < 1 || Position > BCfgOrderCount) {
|
||
|
Print (L"bcfg: %hd not removed. Value is out of range\n", Position);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
Target = BCfgOrder[Position-1];
|
||
|
|
||
|
/*
|
||
|
* remove from order list
|
||
|
*/
|
||
|
|
||
|
BCfgOrderCount = BCfgOrderCount - 1;
|
||
|
for (Index=Position-1; Index < BCfgOrderCount; Index += 1) {
|
||
|
BCfgOrder[Index] = BCfgOrder[Index+1];
|
||
|
}
|
||
|
|
||
|
Status = RT->SetVariable (
|
||
|
BCfgSelOrder,
|
||
|
&EfiGlobalVariable,
|
||
|
BCfgAttributes,
|
||
|
BCfgOrderCount * sizeof(UINT16),
|
||
|
BCfgOrder
|
||
|
);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Remove the option
|
||
|
*/
|
||
|
|
||
|
SPrint (OptionStr, sizeof(OptionStr), BCfgSelOption, Target);
|
||
|
RT->SetVariable (OptionStr, &EfiGlobalVariable, BCfgAttributes, 0, NULL);
|
||
|
|
||
|
/*
|
||
|
* Done
|
||
|
*/
|
||
|
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
Print (L"bcfg: failed to remove - %hr\n", Status);
|
||
|
} else {
|
||
|
Print (L"bcfg: %s %d removed\n", BCfgSelName, Position);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BCfgMove (
|
||
|
IN UINTN Src,
|
||
|
IN UINTN Dest
|
||
|
)
|
||
|
{
|
||
|
UINT16 Target;
|
||
|
UINTN Index;
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
if (Src < 1 || Src > BCfgOrderCount) {
|
||
|
Print (L"bcfg: %hd not moved. Value is out of range\n", Src);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
if (Dest < 1) {
|
||
|
Dest = 1;
|
||
|
}
|
||
|
|
||
|
if (Dest > BCfgOrderCount) {
|
||
|
Dest = BCfgOrderCount;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
Src = Src - 1;
|
||
|
Dest = Dest - 1;
|
||
|
Target = BCfgOrder[Src];
|
||
|
|
||
|
/*
|
||
|
* Remove the item
|
||
|
*/
|
||
|
|
||
|
for (Index=Src; Index < BCfgOrderCount-1; Index += 1) {
|
||
|
BCfgOrder[Index] = BCfgOrder[Index+1];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Insert it
|
||
|
*/
|
||
|
|
||
|
for (Index=BCfgOrderCount-1; Index > Dest; Index -= 1) {
|
||
|
BCfgOrder[Index] = BCfgOrder[Index-1];
|
||
|
}
|
||
|
|
||
|
BCfgOrder[Dest] = Target;
|
||
|
|
||
|
/*
|
||
|
* Update the order
|
||
|
*/
|
||
|
|
||
|
Status = RT->SetVariable (
|
||
|
BCfgSelOrder,
|
||
|
&EfiGlobalVariable,
|
||
|
BCfgAttributes,
|
||
|
BCfgOrderCount * sizeof(UINT16),
|
||
|
BCfgOrder
|
||
|
);
|
||
|
|
||
|
/*
|
||
|
* Done
|
||
|
*/
|
||
|
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
Print (L"bcfg: failed to move option - %hr\n", Status);
|
||
|
} else {
|
||
|
Print (L"bcfg: %s %d moved to %d\n", BCfgSelName, Src+1, Dest+1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
BCfgDumpBootList (
|
||
|
IN CHAR16 *BootOrder,
|
||
|
IN CHAR16 *BootOption
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN DataSize;
|
||
|
UINT32 Attributes;
|
||
|
CHAR16 OptionStr[40];
|
||
|
BCFG_LOAD_OPTION *Option;
|
||
|
UINTN Index;
|
||
|
|
||
|
for (Index=0; Index < BCfgOrderCount; Index++) {
|
||
|
SPrint (OptionStr, sizeof(OptionStr), BootOption, BCfgOrder[Index]);
|
||
|
DataSize = MAX_ENV_SIZE;
|
||
|
Status = RT->GetVariable (
|
||
|
OptionStr,
|
||
|
&EfiGlobalVariable,
|
||
|
&Attributes,
|
||
|
&DataSize,
|
||
|
BCfgData
|
||
|
);
|
||
|
|
||
|
Print (L"%02x. ", Index+1);
|
||
|
if (!EFI_ERROR(Status)) {
|
||
|
|
||
|
Option = BCfgParseLoadOption ((UINT8 *) BCfgData, DataSize);
|
||
|
if (!Option) {
|
||
|
Print (L"%Hcould not parse option%N\n");
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Print (L"%s %H\"%ns\"%s%N\n",
|
||
|
Option->FilePathStr,
|
||
|
Option->Description,
|
||
|
Option->LoadOptionsSize ? L" OPT" : L""
|
||
|
);
|
||
|
|
||
|
BCfgFreeLoadOption (Option);
|
||
|
|
||
|
} else {
|
||
|
Print (L"%hr\n", Status);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BCFG_LOAD_OPTION *
|
||
|
BCfgParseLoadOption (
|
||
|
UINT8 *Data,
|
||
|
UINTN DataSize
|
||
|
)
|
||
|
{
|
||
|
BCFG_LOAD_OPTION *Option;
|
||
|
BOOLEAN Valid;
|
||
|
UINT8 *End;
|
||
|
EFI_DEVICE_PATH *DevicePathNode;
|
||
|
|
||
|
Valid = FALSE;
|
||
|
Option = AllocateZeroPool(sizeof(BCFG_LOAD_OPTION));
|
||
|
|
||
|
/*
|
||
|
* Parse the load option into the Option structure
|
||
|
*/
|
||
|
|
||
|
if (DataSize < 10) {
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* First 32 bits are the load option attributes
|
||
|
*/
|
||
|
|
||
|
CopyMem (&Option->Attributes, Data, sizeof(UINT32));
|
||
|
Data += sizeof(UINT32);
|
||
|
DataSize -= sizeof(UINT32);
|
||
|
|
||
|
/*
|
||
|
* Next is a null terminated string
|
||
|
*/
|
||
|
|
||
|
Option->Description = AllocatePool(DataSize);
|
||
|
CopyMem (Option->Description, Data, DataSize);
|
||
|
|
||
|
/* find the string terminator */
|
||
|
Data = (UINT8 *) Option->Description;
|
||
|
End = Data + DataSize;
|
||
|
while (*((CHAR16 *) Data)) {
|
||
|
if (Data > End - sizeof(CHAR16) - 1) {
|
||
|
goto Done;
|
||
|
}
|
||
|
Data += sizeof(UINT16);
|
||
|
}
|
||
|
Data += sizeof(UINT16);
|
||
|
DataSize = End - Data;
|
||
|
|
||
|
/*
|
||
|
* Next is the file path
|
||
|
*/
|
||
|
|
||
|
Option->FilePath = AllocatePool (DataSize);
|
||
|
CopyMem (Option->FilePath, Data, DataSize);
|
||
|
|
||
|
/* find the end of path terminator */
|
||
|
DevicePathNode = (EFI_DEVICE_PATH *) Data;
|
||
|
while (!IsDevicePathEnd (DevicePathNode)) {
|
||
|
DevicePathNode = NextDevicePathNode (DevicePathNode);
|
||
|
if ((UINT8 *) DevicePathNode > End - sizeof(EFI_DEVICE_PATH)) {
|
||
|
goto Done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Data = ((UINT8 *) DevicePathNode) + sizeof(EFI_DEVICE_PATH);
|
||
|
DataSize = End - Data;
|
||
|
|
||
|
/*
|
||
|
* Next is the load options
|
||
|
*/
|
||
|
|
||
|
if (DataSize) {
|
||
|
Option->LoadOptions = Data;
|
||
|
Option->LoadOptionsSize = DataSize;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Expand the FilePath to a string
|
||
|
*/
|
||
|
|
||
|
Option->FilePathStr = DevicePathToStr(Option->FilePath);
|
||
|
|
||
|
Valid = TRUE;
|
||
|
Done:
|
||
|
if (!Valid && Option) {
|
||
|
BCfgFreeLoadOption (Option);
|
||
|
Option = NULL;
|
||
|
}
|
||
|
|
||
|
return Option;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
BCfgFreeLoadOption (
|
||
|
BCFG_LOAD_OPTION *Option
|
||
|
)
|
||
|
{
|
||
|
if (Option->Description) {
|
||
|
FreePool (Option->Description);
|
||
|
}
|
||
|
|
||
|
if (Option->FilePath) {
|
||
|
FreePool (Option->FilePath);
|
||
|
}
|
||
|
|
||
|
if (Option->FilePathStr) {
|
||
|
FreePool (Option->FilePathStr);
|
||
|
}
|
||
|
|
||
|
FreePool (Option);
|
||
|
}
|