/** @file -- VariablePolicyHelperLib.c | |
This library contains helper functions for marshalling and registering | |
new policies with the VariablePolicy infrastructure. | |
This library is currently written against VariablePolicy revision 0x00010000. | |
Copyright (c) Microsoft Corporation. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Uefi.h> | |
#include <Library/BaseLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Protocol/VariablePolicy.h> | |
/** | |
This internal helper function populates the header structure, | |
all common fields, and takes care of fix-ups. | |
NOTE: Only use this internally. Assumes correctly-sized buffers. | |
@param[out] EntPtr Pointer to the buffer to be populated. | |
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. | |
@param[in] MinSize MinSize for the VariablePolicy. | |
@param[in] MaxSize MaxSize for the VariablePolicy. | |
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. | |
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. | |
@param[in] LockPolicyType LockPolicyType for the VariablePolicy. | |
**/ | |
STATIC | |
VOID | |
PopulateCommonData ( | |
OUT VARIABLE_POLICY_ENTRY *EntPtr, | |
IN CONST EFI_GUID *Namespace, | |
IN UINT32 MinSize, | |
IN UINT32 MaxSize, | |
IN UINT32 AttributesMustHave, | |
IN UINT32 AttributesCantHave, | |
IN UINT8 LockPolicyType | |
) | |
{ | |
EntPtr->Version = VARIABLE_POLICY_ENTRY_REVISION; | |
CopyGuid (&EntPtr->Namespace, Namespace); | |
EntPtr->MinSize = MinSize; | |
EntPtr->MaxSize = MaxSize; | |
EntPtr->AttributesMustHave = AttributesMustHave; | |
EntPtr->AttributesCantHave = AttributesCantHave; | |
EntPtr->LockPolicyType = LockPolicyType; | |
// NOTE: As a heler, fix up MaxSize for compatibility with the old model. | |
if (EntPtr->MaxSize == 0) { | |
EntPtr->MaxSize = VARIABLE_POLICY_NO_MAX_SIZE; | |
} | |
return; | |
} | |
/** | |
This helper function will allocate and populate a new VariablePolicy | |
structure for a policy that does not contain any sub-structures (such as | |
VARIABLE_LOCK_ON_VAR_STATE_POLICY). | |
NOTE: Caller will need to free structure once finished. | |
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. | |
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name. | |
Otherwise, will create a policy that targets an entire namespace. | |
@param[in] MinSize MinSize for the VariablePolicy. | |
@param[in] MaxSize MaxSize for the VariablePolicy. | |
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. | |
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. | |
@param[in] LockPolicyType LockPolicyType for the VariablePolicy. | |
@param[out] NewEntry If successful, will be set to a pointer to the allocated buffer containing the | |
new policy. | |
@retval EFI_SUCCESS Operation completed successfully and structure is populated. | |
@retval EFI_INVALID_PARAMETER Namespace is NULL. | |
@retval EFI_INVALID_PARAMETER LockPolicyType is invalid for a basic structure. | |
@retval EFI_BUFFER_TOO_SMALL Finished structure would not fit in UINT16 size. | |
@retval EFI_OUT_OF_RESOURCES Could not allocate sufficient space for structure. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CreateBasicVariablePolicy ( | |
IN CONST EFI_GUID *Namespace, | |
IN CONST CHAR16 *Name OPTIONAL, | |
IN UINT32 MinSize, | |
IN UINT32 MaxSize, | |
IN UINT32 AttributesMustHave, | |
IN UINT32 AttributesCantHave, | |
IN UINT8 LockPolicyType, | |
OUT VARIABLE_POLICY_ENTRY **NewEntry | |
) | |
{ | |
UINTN TotalSize; | |
UINTN NameSize; | |
VARIABLE_POLICY_ENTRY *EntPtr; | |
CHAR16 *CopyName; | |
// Check some initial invalid parameters for this function. | |
if ((Namespace == NULL) || (NewEntry == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if ((LockPolicyType != VARIABLE_POLICY_TYPE_NO_LOCK) && | |
(LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_NOW) && | |
(LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_CREATE)) | |
{ | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Set NameSize to suppress incorrect compiler/analyzer warnings | |
// | |
NameSize = 0; | |
// Now we've gotta determine the total size of the buffer required for | |
// the VariablePolicy structure. | |
TotalSize = sizeof (VARIABLE_POLICY_ENTRY); | |
if (Name != NULL) { | |
NameSize = StrnSizeS (Name, MAX_UINT16); | |
TotalSize += NameSize; | |
} | |
// Make sure the size fits within a VARIABLE_POLICY_ENTRY.Size. | |
ASSERT (TotalSize <= MAX_UINT16); | |
if (TotalSize > MAX_UINT16) { | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// Allocate a buffer to hold all the data. We're on the home stretch. | |
*NewEntry = AllocatePool (TotalSize); | |
if (*NewEntry == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// If we're still here, we're basically done. | |
// Copy the data and GET... OUT.... | |
EntPtr = *NewEntry; | |
PopulateCommonData ( | |
EntPtr, | |
Namespace, | |
MinSize, | |
MaxSize, | |
AttributesMustHave, | |
AttributesCantHave, | |
LockPolicyType | |
); | |
EntPtr->Size = (UINT16)TotalSize; // This is safe because we've already checked. | |
EntPtr->OffsetToName = sizeof (VARIABLE_POLICY_ENTRY); | |
if (Name != NULL) { | |
CopyName = (CHAR16 *)((UINT8 *)EntPtr + EntPtr->OffsetToName); | |
CopyMem (CopyName, Name, NameSize); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This helper function will allocate and populate a new VariablePolicy | |
structure for a policy with a lock type of VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE. | |
NOTE: Caller will need to free structure once finished. | |
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. | |
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name. | |
Otherwise, will create a policy that targets an entire namespace. | |
@param[in] MinSize MinSize for the VariablePolicy. | |
@param[in] MaxSize MaxSize for the VariablePolicy. | |
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. | |
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. | |
@param[in] VarStateNamespace Pointer to the EFI_GUID for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Namespace. | |
@param[in] VarStateValue Value for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Value. | |
@param[in] VarStateName Pointer to the CHAR16 array for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Name. | |
@param[out] NewEntry If successful, will be set to a pointer to the allocated buffer containing the | |
new policy. | |
@retval EFI_SUCCESS Operation completed successfully and structure is populated. | |
@retval EFI_INVALID_PARAMETER Namespace, VarStateNamespace, VarStateName is NULL. | |
@retval EFI_BUFFER_TOO_SMALL Finished structure would not fit in UINT16 size. | |
@retval EFI_OUT_OF_RESOURCES Could not allocate sufficient space for structure. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CreateVarStateVariablePolicy ( | |
IN CONST EFI_GUID *Namespace, | |
IN CONST CHAR16 *Name OPTIONAL, | |
IN UINT32 MinSize, | |
IN UINT32 MaxSize, | |
IN UINT32 AttributesMustHave, | |
IN UINT32 AttributesCantHave, | |
IN CONST EFI_GUID *VarStateNamespace, | |
IN UINT8 VarStateValue, | |
IN CONST CHAR16 *VarStateName, | |
OUT VARIABLE_POLICY_ENTRY **NewEntry | |
) | |
{ | |
UINTN TotalSize; | |
UINTN NameSize; | |
UINTN VarStateNameSize; | |
VARIABLE_POLICY_ENTRY *EntPtr; | |
CHAR16 *CopyName; | |
VARIABLE_LOCK_ON_VAR_STATE_POLICY *CopyPolicy; | |
// Check some initial invalid parameters for this function. | |
if ((Namespace == NULL) || (VarStateNamespace == NULL) || | |
(VarStateName == NULL) || (NewEntry == NULL)) | |
{ | |
return EFI_INVALID_PARAMETER; | |
} | |
// Now we've gotta determine the total size of the buffer required for | |
// the VariablePolicy structure. | |
VarStateNameSize = StrnSizeS (VarStateName, MAX_UINT16); | |
TotalSize = sizeof (VARIABLE_POLICY_ENTRY) + | |
sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY) + | |
VarStateNameSize; | |
if (Name != NULL) { | |
NameSize = StrnSizeS (Name, MAX_UINT16); | |
TotalSize += NameSize; | |
} | |
// Make sure the size fits within a VARIABLE_POLICY_ENTRY.Size. | |
ASSERT (TotalSize <= MAX_UINT16); | |
if (TotalSize > MAX_UINT16) { | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// Allocate a buffer to hold all the data. We're on the home stretch. | |
*NewEntry = AllocatePool (TotalSize); | |
if (*NewEntry == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// If we're still here, we're basically done. | |
// Copy the data and GET... OUT.... | |
EntPtr = *NewEntry; | |
PopulateCommonData ( | |
EntPtr, | |
Namespace, | |
MinSize, | |
MaxSize, | |
AttributesMustHave, | |
AttributesCantHave, | |
VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE | |
); | |
EntPtr->Size = (UINT16)TotalSize; // This is safe because we've already checked. | |
EntPtr->OffsetToName = sizeof (VARIABLE_POLICY_ENTRY) + | |
sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY) + | |
(UINT16)VarStateNameSize; | |
CopyPolicy = (VARIABLE_LOCK_ON_VAR_STATE_POLICY *)((UINT8 *)EntPtr + sizeof (VARIABLE_POLICY_ENTRY)); | |
CopyName = (CHAR16 *)((UINT8 *)CopyPolicy + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY)); | |
CopyGuid (&CopyPolicy->Namespace, VarStateNamespace); | |
CopyPolicy->Value = VarStateValue; | |
CopyMem (CopyName, VarStateName, VarStateNameSize); | |
if (Name != NULL) { | |
CopyName = (CHAR16 *)((UINT8 *)EntPtr + EntPtr->OffsetToName); | |
CopyMem (CopyName, Name, NameSize); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This helper function does everything that CreateBasicVariablePolicy() does, but also | |
uses the passed in protocol to register the policy with the infrastructure. | |
Does not return a buffer, does not require the caller to free anything. | |
@param[in] VariablePolicy Pointer to a valid instance of the VariablePolicy protocol. | |
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. | |
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name. | |
Otherwise, will create a policy that targets an entire namespace. | |
@param[in] MinSize MinSize for the VariablePolicy. | |
@param[in] MaxSize MaxSize for the VariablePolicy. | |
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. | |
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. | |
@param[in] LockPolicyType LockPolicyType for the VariablePolicy. | |
@retval EFI_INVALID_PARAMETER VariablePolicy pointer is NULL. | |
@retval EFI_STATUS Status returned by CreateBasicVariablePolicy() or RegisterVariablePolicy(). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RegisterBasicVariablePolicy ( | |
IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy, | |
IN CONST EFI_GUID *Namespace, | |
IN CONST CHAR16 *Name OPTIONAL, | |
IN UINT32 MinSize, | |
IN UINT32 MaxSize, | |
IN UINT32 AttributesMustHave, | |
IN UINT32 AttributesCantHave, | |
IN UINT8 LockPolicyType | |
) | |
{ | |
VARIABLE_POLICY_ENTRY *NewEntry; | |
EFI_STATUS Status; | |
// Check the simple things. | |
if (VariablePolicy == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// Create the new entry and make sure that everything worked. | |
NewEntry = NULL; | |
Status = CreateBasicVariablePolicy ( | |
Namespace, | |
Name, | |
MinSize, | |
MaxSize, | |
AttributesMustHave, | |
AttributesCantHave, | |
LockPolicyType, | |
&NewEntry | |
); | |
// If that was successful, attempt to register the new policy. | |
if (!EFI_ERROR (Status)) { | |
Status = VariablePolicy->RegisterVariablePolicy (NewEntry); | |
} | |
// If we allocated the buffer, free the buffer. | |
if (NewEntry != NULL) { | |
FreePool (NewEntry); | |
} | |
return Status; | |
} | |
/** | |
This helper function does everything that CreateBasicVariablePolicy() does, but also | |
uses the passed in protocol to register the policy with the infrastructure. | |
Does not return a buffer, does not require the caller to free anything. | |
@param[in] VariablePolicy Pointer to a valid instance of the VariablePolicy protocol. | |
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. | |
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name. | |
Otherwise, will create a policy that targets an entire namespace. | |
@param[in] MinSize MinSize for the VariablePolicy. | |
@param[in] MaxSize MaxSize for the VariablePolicy. | |
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. | |
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. | |
@param[in] VarStateNamespace Pointer to the EFI_GUID for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Namespace. | |
@param[in] VarStateName Pointer to the CHAR16 array for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Name. | |
@param[in] VarStateValue Value for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Value. | |
@retval EFI_INVALID_PARAMETER VariablePolicy pointer is NULL. | |
@retval EFI_STATUS Status returned by CreateBasicVariablePolicy() or RegisterVariablePolicy(). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
RegisterVarStateVariablePolicy ( | |
IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy, | |
IN CONST EFI_GUID *Namespace, | |
IN CONST CHAR16 *Name OPTIONAL, | |
IN UINT32 MinSize, | |
IN UINT32 MaxSize, | |
IN UINT32 AttributesMustHave, | |
IN UINT32 AttributesCantHave, | |
IN CONST EFI_GUID *VarStateNamespace, | |
IN CONST CHAR16 *VarStateName, | |
IN UINT8 VarStateValue | |
) | |
{ | |
VARIABLE_POLICY_ENTRY *NewEntry; | |
EFI_STATUS Status; | |
// Check the simple things. | |
if (VariablePolicy == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// Create the new entry and make sure that everything worked. | |
NewEntry = NULL; | |
Status = CreateVarStateVariablePolicy ( | |
Namespace, | |
Name, | |
MinSize, | |
MaxSize, | |
AttributesMustHave, | |
AttributesCantHave, | |
VarStateNamespace, | |
VarStateValue, | |
VarStateName, | |
&NewEntry | |
); | |
// If that was successful, attempt to register the new policy. | |
if (!EFI_ERROR (Status)) { | |
Status = VariablePolicy->RegisterVariablePolicy (NewEntry); | |
} | |
// If we allocated the buffer, free the buffer. | |
if (NewEntry != NULL) { | |
FreePool (NewEntry); | |
} | |
return Status; | |
} |