Add EDKII_VARIABLE_LOCK_PROTOCOL and the implementation in MdeModulePkg variable drivers.

Add code in BdsDxe driver to call the protocol to mark the read-only variables defined in the UEFI Spec.

Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Guo Dong <guo.dong@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@14372 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
niruiyu
2013-05-17 03:49:35 +00:00
parent efffd9c17e
commit ff8438477f
14 changed files with 487 additions and 30 deletions

View File

@@ -21,12 +21,28 @@ VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
///
/// Define a memory cache that improves the search performance for a variable.
///
VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
///
/// The memory entry used for variable statistics data.
///
VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
///
/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID
/// or EVT_GROUP_READY_TO_BOOT event.
///
LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);
///
/// The flag to indicate whether the platform has left the DXE phase of execution.
///
BOOLEAN mEndOfDxe = FALSE;
///
/// The flag to indicate whether the variable storage locking is enabled.
///
BOOLEAN mEnableLocking = TRUE;
/**
@@ -1918,6 +1934,58 @@ IsHwErrRecVariable (
return TRUE;
}
/**
Mark a variable that will become read-only after leaving the DXE phase of execution.
@param[in] This The VARIABLE_LOCK_PROTOCOL instance.
@param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
@param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
@retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
as pending to be read-only.
@retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
Or VariableName is an empty string.
@retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
already been signaled.
@retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
**/
EFI_STATUS
EFIAPI
VariableLockRequestToLock (
IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid
)
{
VARIABLE_ENTRY *Entry;
if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
return EFI_INVALID_PARAMETER;
}
if (mEndOfDxe) {
return EFI_ACCESS_DENIED;
}
Entry = AllocateRuntimePool (sizeof (*Entry) + StrSize (VariableName));
if (Entry == NULL) {
return EFI_OUT_OF_RESOURCES;
}
DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName));
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
Entry->Name = (CHAR16 *) (Entry + 1);
StrCpy (Entry->Name, VariableName);
CopyGuid (&Entry->Guid, VendorGuid);
InsertTailList (&mLockedVariableList, &Entry->Link);
ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
return EFI_SUCCESS;
}
/**
This code finds variable in storage blocks (Volatile or Non-Volatile).
@@ -2192,6 +2260,8 @@ VariableServiceSetVariable (
EFI_STATUS Status;
VARIABLE_HEADER *NextVariable;
EFI_PHYSICAL_ADDRESS Point;
LIST_ENTRY *Link;
VARIABLE_ENTRY *Entry;
//
// Check input parameters.
@@ -2247,16 +2317,6 @@ VariableServiceSetVariable (
}
}
if (AtRuntime ()) {
//
// HwErrRecSupport Global Variable identifies the level of hardware error record persistence
// support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.
//
if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {
return EFI_WRITE_PROTECTED;
}
}
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
//
@@ -2275,13 +2335,31 @@ VariableServiceSetVariable (
mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
}
if (mEndOfDxe && mEnableLocking) {
//
// Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.
//
for ( Link = GetFirstNode (&mLockedVariableList)
; !IsNull (&mLockedVariableList, Link)
; Link = GetNextNode (&mLockedVariableList, Link)
) {
Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);
if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Entry->Name, VariableName) == 0)) {
Status = EFI_WRITE_PROTECTED;
DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName));
goto Done;
}
}
}
//
// Check whether the input variable is already existed.
//
Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
if (!EFI_ERROR (Status)) {
if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
return EFI_WRITE_PROTECTED;
Status = EFI_WRITE_PROTECTED;
goto Done;
}
}
@@ -2292,6 +2370,7 @@ VariableServiceSetVariable (
Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
Done:
InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);