Skip to content

Commit

Permalink
Add EDKII_VARIABLE_LOCK_PROTOCOL and the implementation in MdeModuleP…
Browse files Browse the repository at this point in the history
…kg 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
  • Loading branch information
niruiyu committed May 17, 2013
1 parent efffd9c commit ff84384
Show file tree
Hide file tree
Showing 14 changed files with 487 additions and 30 deletions.
3 changes: 2 additions & 1 deletion IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @file
Head file for BDS Architectural Protocol implementation
Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
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
Expand Down Expand Up @@ -47,6 +47,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/SimpleTextInEx.h>
#include <Protocol/DriverHealth.h>
#include <Protocol/BootLogo.h>
#include <Protocol/VariableLock.h>

#include <Library/UefiDriverEntryPoint.h>
#include <Library/PrintLib.h>
Expand Down
3 changes: 2 additions & 1 deletion IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# BDSDxe also maintain the UI for "Boot Manager, Boot Maintaince Manager, Device Manager" which
# is used for user to configure boot option or maintain hardware device.
#
# Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>
# 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
Expand Down Expand Up @@ -160,6 +160,7 @@
gEfiDriverHealthProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES
gEfiPciIoProtocolGuid ## PROTOCOL CONSUMES
gEfiBootLogoProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES
gEdkiiVariableLockProtocolGuid ## PROTOCOL CONSUMES

[FeaturePcd]
gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate
Expand Down
37 changes: 31 additions & 6 deletions IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ EFI_BDS_ARCH_PROTOCOL gBds = {

UINT16 *mBootNext = NULL;

///
/// The read-only variables defined in UEFI Spec.
///
CHAR16 *mReadOnlyVariables[] = {
L"PlatformLangCodes",
L"LangCodes",
L"BootOptionSupport",
L"HwErrRecSupport",
L"OsIndicationsSupported"
};

/**
Install Boot Device Selection Protocol
Expand Down Expand Up @@ -459,6 +470,8 @@ BdsEntry (
CHAR16 *FirmwareVendor;
EFI_STATUS Status;
UINT16 BootTimeOut;
UINTN Index;
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;

//
// Insert the performance probe
Expand Down Expand Up @@ -496,6 +509,18 @@ BdsEntry (
//
BdsFormalizeEfiGlobalVariable();

//
// Mark the read-only variables if the Variable Lock protocol exists
//
Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));
if (!EFI_ERROR (Status)) {
for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {
Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);
ASSERT_EFI_ERROR (Status);
}
}

//
// Report Status Code to indicate connecting drivers will happen
//
Expand All @@ -504,12 +529,6 @@ BdsEntry (
(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)
);

//
// Do the platform init, can be customized by OEM/IBV
//
PERF_START (NULL, "PlatformBds", "BDS", 0);
PlatformBdsInit ();

InitializeHwErrRecSupport();

//
Expand Down Expand Up @@ -539,6 +558,12 @@ BdsEntry (
InitializeLanguage (TRUE);
InitializeFrontPage (TRUE);

//
// Do the platform init, can be customized by OEM/IBV
//
PERF_START (NULL, "PlatformBds", "BDS", 0);
PlatformBdsInit ();

//
// Set up the device list based on EFI 1.1 variables
// process Driver#### and Load the driver's in the
Expand Down
6 changes: 6 additions & 0 deletions MdeModulePkg/Include/Guid/SmmVariableCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ typedef struct {
// is gEfiSmmVariableProtocolGuid.
//
#define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7
//
// The payload for this function is SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
//
#define SMM_VARIABLE_FUNCTION_LOCK_VARIABLE 8

///
/// Size of SMM communicate header, without including the payload.
Expand Down Expand Up @@ -101,4 +105,6 @@ typedef struct {
UINT32 Attributes;
} SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO;

typedef SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE;

#endif // _SMM_VARIABLE_COMMON_H_
63 changes: 63 additions & 0 deletions MdeModulePkg/Include/Protocol/VariableLock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/** @file
Variable Lock Protocol is related to EDK II-specific implementation of variables
and intended for use as a means to mark a variable read-only after the event
EFI_END_OF_DXE_EVENT_GUID is signaled.
Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
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.
**/

#ifndef __VARIABLE_LOCK_H__
#define __VARIABLE_LOCK_H__

#define EDKII_VARIABLE_LOCK_PROTOCOL_GUID \
{ \
0xcd3d0a05, 0x9e24, 0x437c, { 0xa8, 0x91, 0x1e, 0xe0, 0x53, 0xdb, 0x76, 0x38 } \
}

typedef struct _EDKII_VARIABLE_LOCK_PROTOCOL EDKII_VARIABLE_LOCK_PROTOCOL;

/**
Mark a variable that will become read-only after leaving the DXE phase of execution.
Write request coming from SMM environment through EFI_SMM_VARIABLE_PROTOCOL is allowed.
@param[in] This The EDKII_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.
**/
typedef
EFI_STATUS
(EFIAPI * EDKII_VARIABLE_LOCK_PROTOCOL_REQUEST_TO_LOCK) (
IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid
);

///
/// Variable Lock Protocol is related to EDK II-specific implementation of variables
/// and intended for use as a means to mark a variable read-only after the event
/// EFI_END_OF_DXE_EVENT_GUID is signaled.
///
struct _EDKII_VARIABLE_LOCK_PROTOCOL {
EDKII_VARIABLE_LOCK_PROTOCOL_REQUEST_TO_LOCK RequestToLock;
};

extern EFI_GUID gEdkiiVariableLockProtocolGuid;

#endif

4 changes: 4 additions & 0 deletions MdeModulePkg/MdeModulePkg.dec
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@
# Include/Protocol/SmmVariableProtocol.h
gEfiSmmVariableProtocolGuid = { 0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 }}

## This protocol is intended for use as a means to mark a variable read-only after the event EFI_END_OF_DXE_EVENT_GUID is signaled.
# Include/Protocol/VariableLock.h
gEdkiiVariableLockProtocolGuid = { 0xcd3d0a05, 0x9e24, 0x437c, { 0xa8, 0x91, 0x1e, 0xe0, 0x53, 0xdb, 0x76, 0x38 }}

## This protocol is similar with DXE FVB protocol and used in the UEFI SMM evvironment.
# Include/Protocol/SmmFirmwareVolumeBlock.h
gEfiSmmFirmwareVolumeBlockProtocolGuid = { 0xd326d041, 0xbd31, 0x4c01, { 0xb5, 0xa8, 0x62, 0x8b, 0xe8, 0x7f, 0x6, 0x53 }}
Expand Down
105 changes: 92 additions & 13 deletions MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;


/**
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -2192,6 +2260,8 @@ VariableServiceSetVariable (
EFI_STATUS Status;
VARIABLE_HEADER *NextVariable;
EFI_PHYSICAL_ADDRESS Point;
LIST_ENTRY *Link;
VARIABLE_ENTRY *Entry;

//
// Check input parameters.
Expand Down Expand Up @@ -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);

//
Expand All @@ -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;
}
}

Expand All @@ -2292,6 +2370,7 @@ VariableServiceSetVariable (

Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);

Done:
InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);

Expand Down

0 comments on commit ff84384

Please sign in to comment.