var.c
来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 587 行
C
587 行
/*++
Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
Module Name:
var.c
Abstract:
EFI Boot Manager, variable manipulation
Revision History
--*/
#include "bm.h"
//
// Internal prototypes
//
VOID
BmVarCleanup (
IN OUT BM_VARIABLE *Var
);
BOOLEAN
BmParseBootOption (
IN CHAR16 *Name,
IN UINT8 *Data,
IN UINTN DataSize,
IN CHAR16 *OptionName,
IN LIST_ENTRY *OptionList
);
VOID
BmOrderOptions (
IN BM_VARIABLE *Order,
IN LIST_ENTRY *OptionList,
IN LIST_ENTRY *OrderList
);
//
//
//
VOID
BmReadVariables (
VOID
)
{
CHAR16 *Name;
VOID *Data;
UINTN BufferSize;
UINTN NameSize, DataSize;
EFI_GUID Id;
UINT32 Attributes;
EFI_STATUS Status;
BOOLEAN Parsed;
UINTN Index;
BM_VARIABLE *Var;
BOOLEAN FoundBootOption;
//
// Initialize the load option lists
//
InitializeListHead (&BmDriverOptions);
InitializeListHead (&BmBootOptions);
BmBootOrder.MaxIndex = 0;
BmDriverOrder.MaxIndex = 0;
BufferSize = 1024;
Name = AllocatePool (BufferSize);
Data = AllocatePool (BufferSize);
ASSERT (Name && Data);
//
// Read all variables in the system and collect ours
//
Name[0] = 0;
FoundBootOption = FALSE;
for (; ;) {
NameSize = BufferSize;
Status = RT->GetNextVariableName (&NameSize, Name, &Id);
if (EFI_ERROR(Status)) {
break;
}
// If this is not an EFI defined variable, skip it
if (CompareGuid(&Id, &EfiGlobalVariable)) {
continue;
}
//
// It's an EFI variable, read the data
//
DataSize = BufferSize;
Status = RT->GetVariable (Name, &Id, &Attributes, &DataSize, Data);
ASSERT (!EFI_ERROR(Status));
//
// See if it's a boot or driver option
//
Parsed = BmParseBootOption (Name, Data, DataSize, L"Boot", &BmBootOptions);
if (Parsed) {
FoundBootOption = TRUE;
continue;
}
Parsed = BmParseBootOption (Name, Data, DataSize, L"Driver", &BmDriverOptions);
if (Parsed) {
FoundBootOption = TRUE;
continue;
}
//
// Variable is not an driver or boot option, check for match
//
for (Index=0; BmVariables[Index]; Index++) {
Var = BmVariables[Index];
if (StrCmp(Name, Var->Name) == 0) {
BmSetVariable (Var, Data, DataSize);
if (Var->BootDefault) {
FoundBootOption = TRUE;
}
break;
}
}
}
//
// Writes now get shadowed NVRAM
//
BmUpdateVariables = TRUE;
if (!FoundBootOption) {
//
// Set Defaults based on OEM preference. The current policy is if no boot
// variables exist set defaults.
//
BmSetDefaultDriverOptions (&BmDriverOptions);
BmSetDefaultBootOptions (&BmBootOptions);
}
//
// Do some sanity checking. Check order list references with options
//
BmOrderOptions (&BmBootOrder, &BmBootOptions, &BmOrderedBootOptions);
BmOrderOptions (&BmDriverOrder, &BmDriverOptions, &BmOrderedDriverOptions);
FreePool (Name);
FreePool (Data);
}
VOID
BmRemoveVariable (
IN CHAR16 *Name
)
{
EFI_STATUS Status;
Status = RT->SetVariable (Name, &EfiGlobalVariable, 0, 0, NULL);
ASSERT (!EFI_ERROR(Status));
}
VOID
BmDeleteLoadOption (
IN BM_LOAD_OPTION *Option
)
{
BmRemoveVariable (Option->Name);
FreePool (Option->Name);
if (Option->Description) {
FreePool (Option->Description);
}
if (Option->FilePath) {
FreePool (Option->FilePath);
}
if (Option->Order.Flink) {
RemoveEntryList (&Option->Order);
}
ASSERT (!Option->All.Flink);
FreePool (Option);
}
VOID
BmDeleteAllLoadOptions (
IN BM_VARIABLE *Order,
IN LIST_ENTRY *OrderList
)
{
BM_LOAD_OPTION *Option;
while (!IsListEmpty(OrderList)) {
Option = CR(OrderList->Flink, BM_LOAD_OPTION, Order, BM_LOAD_OPTION_SIGNATURE);
BmDeleteLoadOption (Option);
}
BmUpdateOrder (Order, OrderList);
}
VOID
BmVarCleanup (
IN OUT BM_VARIABLE *Var
)
{
//
// Round to an even number of units
//
Var->DataSize = (Var->DataSize / Var->IntegralSize) * Var->IntegralSize;
//
// If this is not an array, make sure there's only 1 unit
//
if (!Var->Array && Var->DataSize > Var->IntegralSize) {
Var->DataSize = Var->IntegralSize;
}
//
// If the size is zero, free it
//
if (!Var->DataSize && Var->u.Data) {
BmRemoveVariable (Var->Name);
FreePool (Var->u.Data);
Var->u.Data = NULL;
Var->MaxIndex = 0;
}
}
VOID
BmSetVariable (
IN OUT BM_VARIABLE *Var,
IN VOID *Data,
IN UINTN DataSize
)
{
EFI_STATUS Status;
if (Var->DataSize) {
FreePool (Var->u.Data);
Var->DataSize = 0;
Var->u.Data = NULL;
}
Var->DataSize = DataSize;
Var->MaxIndex = DataSize / sizeof(UINT16);
Var->u.Data = AllocatePool(DataSize);
ASSERT (Var->u.Data);
CopyMem (Var->u.Data, Data, DataSize);
if (BmUpdateVariables) {
Status = RT->SetVariable (
Var->Name,
&EfiGlobalVariable,
(Var->NonVolatile ? EFI_VARIABLE_NON_VOLATILE : 0) |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
(Var->RuntimeAccess ? EFI_VARIABLE_RUNTIME_ACCESS : 0),
DataSize,
Data
);
ASSERT (!EFI_ERROR(Status));
}
BmVarCleanup (Var);
}
BOOLEAN
BmParseBootOption (
IN CHAR16 *Name,
IN UINT8 *Data,
IN UINTN DataSize,
IN CHAR16 *OptionName,
IN LIST_ENTRY *OptionList
)
{
UINTN Size;
UINTN Value;
CHAR16 *Digits;
BM_LOAD_OPTION *Option;
UINT8 *End;
EFI_DEVICE_PATH *DevicePathNode;
//
// If the name of the form NAMExxxx where XXXX is a non-zero value?
//
Size = StrSize(OptionName) - sizeof(CHAR16);
if (CompareMem(Name, OptionName, Size)) {
return FALSE;
}
Digits = Name + Size / sizeof(UINT16);
Value = xtoi(Digits);
if (!Value) {
//
// check for a special case 'Boot0000' or 'Driver0000' as xtoi would
// return '0' whether input is '0' or 'non-hex' characters found
//
if (CompareMem (Digits,L"0000",4*sizeof(UINT16))) {
return FALSE;
}
}
//
// Got a valid variable name
//
Option = AllocateZeroPool(sizeof(BM_LOAD_OPTION));
Option->Signature = BM_LOAD_OPTION_SIGNATURE;
Option->Name = StrDuplicate(Name);
Option->OptionNumber = Value;
InsertTailList (OptionList, &Option->All);
//
// If there's not at least 10 chars, then it's not a valid entry
//
if (DataSize < 10) {
goto Done;
}
//
// First 32bits are the load option attributes
//
CopyMem (&Option->Attributes, Data, sizeof (UINT32));
Data += sizeof(UINT32);
DataSize -= sizeof(UINT32);
//
// Next 16-bits are the load option FilePathListLength
//
CopyMem (&Option->FilePathListLength, Data, sizeof (UINT16));
Data += sizeof(UINT16);
DataSize -= sizeof(UINT16);
//
// 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 to check for errors
DevicePathNode = (EFI_DEVICE_PATH *) Data;
while (!IsDevicePathEnd (DevicePathNode)) {
DevicePathNode = NextDevicePathNode (DevicePathNode);
if ((UINT8 *) DevicePathNode > End - sizeof(EFI_DEVICE_PATH)) {
goto Done;
}
}
Data = ((UINT8 *) Data + Option->FilePathListLength);
if (Data > End) {
goto Done;
}
DataSize = End - Data;
//
// Next is the load options
//
if (DataSize) {
Option->LoadOptions = AllocatePool (DataSize);
CopyMem (Option->LoadOptions, Data, DataSize);
Option->LoadOptionsSize = DataSize;
}
//
// Valid
//
Option->Valid = TRUE;
Done:
return TRUE;
}
VOID
BmOrderOptions (
IN BM_VARIABLE *Order,
IN LIST_ENTRY *OptionList,
IN LIST_ENTRY *OrderList
)
{
BOOLEAN Remove;
LIST_ENTRY *Link;
UINTN Index;
UINTN OptionNumber;
BM_LOAD_OPTION *Option;
InitializeListHead (OrderList);
//
// Walk the ordering array and build a new list to the requested order
//
for (Index=0; Index < Order->MaxIndex; Index++) {
OptionNumber = Order->u.Value[Index];
//
// Find this load option
//
for (Link=OptionList->Flink; Link != OptionList; Link = Link->Flink) {
Option = CR(Link, BM_LOAD_OPTION, All, BM_LOAD_OPTION_SIGNATURE);
if (Option->OptionNumber == OptionNumber) {
//
// If it's not already found, add it to the end of the ordered list
//
if (!Option->Order.Flink) {
InsertTailList (OrderList, &Option->Order);
}
break;
}
}
}
//
// Remove any invalid, or any unreferenced options
//
while (!IsListEmpty(OptionList)) {
Option = CR(OptionList->Flink, BM_LOAD_OPTION, All, BM_LOAD_OPTION_SIGNATURE);
RemoveEntryList (&Option->All);
Option->All.Flink = NULL;
Remove = FALSE;
if (!Option->Valid) {
DEBUG ((D_BM | D_ERROR, "BmOrderOptions: Removing un-parsable load option: %s\n", Option->Name));
Remove = TRUE;
}
if (!Option->Order.Flink) {
DEBUG ((D_BM | D_ERROR, "BmOrderOptions: Removing un-referenced load option: %s\n", Option->Name));
Remove = TRUE;
}
if (Remove) {
BmDeleteLoadOption (Option);
}
}
//
// Update the ordered list if needed
//
BmUpdateOrder(Order, OrderList);
}
VOID
BmUpdateOrder (
IN BM_VARIABLE *Order,
IN LIST_ENTRY *OrderList
)
{
UINTN Index, Count;
LIST_ENTRY *Link;
BM_LOAD_OPTION *Option;
BOOLEAN UpdateOrder;
EFI_STATUS Status;
UpdateOrder = FALSE;
//
// Count the number of load options
//
Count = 0;
for (Link=OrderList->Flink; Link != OrderList; Link = Link->Flink) {
Count = Count + 1;
}
//
// If the order array is too small, allocate a new one
//
if (Order->MaxIndex < Count) {
if (Order->u.Data) {
FreePool (Order->u.Data);
}
Order->u.Data = AllocatePool(Count * sizeof(UINT16));
}
//
// Fill If the order array was not valid, update it
//
Index = 0;
for (Link=OrderList->Flink; Link != OrderList; Link = Link->Flink) {
Option = CR(Link, BM_LOAD_OPTION, Order, BM_LOAD_OPTION_SIGNATURE);
if (Order->u.Value[Index] != Option->OptionNumber) {
Order->u.Value[Index] = (UINT16) Option->OptionNumber;
UpdateOrder = TRUE;
}
Index += 1;
if (Index >= Count) {
break;
}
}
if (Index != Order->MaxIndex || UpdateOrder) {
DEBUG ((D_BM | D_ERROR, "BmUpdateOrder: Updating order list: %s\n", Order->Name));
Order->MaxIndex = Index;
Order->DataSize = Index * sizeof(UINT16);
Status = RT->SetVariable (
Order->Name,
&EfiGlobalVariable,
(OrderList == &BmOrderedBootOptions) ?
(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS) :
(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),
Order->DataSize,
Order->u.Data
);
ASSERT (!EFI_ERROR(Status));
}
}
VOID
BmSetBootCurrent(
BOOLEAN Set,
UINT16 Value
)
{
EFI_STATUS Status;
UINTN Size;
Size = sizeof(UINT16);
if (Set == FALSE) {
Size = 0;
}
Status = RT->SetVariable (
VarBootCurrent,
&EfiGlobalVariable,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
Size,
&Value
);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?