Date   

Re: [EXTERNAL] [edk2-devel] [PATCH v5 03/14] MdeModulePkg: Define the VariablePolicyHelperLib

Bret Barkelew
 

Bump. This specific patch needs Reviews.

- Bret


From: devel@edk2.groups.io <devel@edk2.groups.io> on behalf of Bret Barkelew via groups.io <bret@...>
Sent: Tuesday, June 2, 2020 11:57 PM
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Jian J Wang <jian.j.wang@...>; Hao A Wu <hao.a.wu@...>; liming.gao <liming.gao@...>
Subject: [EXTERNAL] [edk2-devel] [PATCH v5 03/14] MdeModulePkg: Define the VariablePolicyHelperLib
 
https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2522&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7Cf4de67d242ec4517ab1c08d807a3dc74%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747648232766&amp;sdata=ErqHXizN7Q6ghP%2BPuivvQuQnhfYKMEMwWgitRbYMCmE%3D&amp;reserved=0

VariablePolicy is an updated interface to
replace VarLock and VarCheckProtocol.

Add the VariablePolicyHelperLib library, containing
several functions to help with the repetitive process
of creating a correctly structured and packed
VariablePolicy entry.

Cc: Jian J Wang <jian.j.wang@...>
Cc: Hao A Wu <hao.a.wu@...>
Cc: Liming Gao <liming.gao@...>
Cc: Bret Barkelew <brbarkel@...>
Signed-off-by: Bret Barkelew <brbarkel@...>
---
 MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.c   | 396 ++++++++++++++++++++
 MdeModulePkg/Include/Library/VariablePolicyHelperLib.h                   | 164 ++++++++
 MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf |  35 ++
 MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.uni |  12 +
 MdeModulePkg/MdeModulePkg.dec                                            |   5 +
 MdeModulePkg/MdeModulePkg.dsc                                            |   2 +
 6 files changed, 614 insertions(+)

diff --git a/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.c b/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.c
new file mode 100644
index 000000000000..0c9299c8b0e1
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.c
@@ -0,0 +1,396 @@
+/** @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;

+  }

+

+  // 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;

+}

diff --git a/MdeModulePkg/Include/Library/VariablePolicyHelperLib.h b/MdeModulePkg/Include/Library/VariablePolicyHelperLib.h
new file mode 100644
index 000000000000..3b75e9786094
--- /dev/null
+++ b/MdeModulePkg/Include/Library/VariablePolicyHelperLib.h
@@ -0,0 +1,164 @@
+/** @file -- VariablePolicyHelperLib.h

+This library contains helper functions for marshalling and registering

+new policies with the VariablePolicy infrastructure.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#ifndef _EDKII_VARIABLE_POLICY_HELPER_LIB_H_

+#define _EDKII_VARIABLE_POLICY_HELPER_LIB_H_

+

+#include <Protocol/VariablePolicy.h>

+

+/**

+  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

+  );

+

+

+/**

+  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

+  );

+

+

+/**

+  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

+  );

+

+

+/**

+  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

+  );

+

+#endif // _EDKII_VARIABLE_POLICY_HELPER_LIB_H_

diff --git a/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf b/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
new file mode 100644
index 000000000000..506abf580e94
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
@@ -0,0 +1,35 @@
+## @file VariablePolicyHelperLib.inf

+# 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

+##

+

+

+[Defines]

+  INF_VERSION         = 0x00010017

+  BASE_NAME           = VariablePolicyHelperLib

+  # MODULE_UNI_FILE   = VariablePolicyHelperLib.uni

+  FILE_GUID           = B3C2206B-FDD1-4AED-8352-FC5EC34C5630

+  VERSION_STRING      = 1.0

+  MODULE_TYPE         = BASE

+  LIBRARY_CLASS       = VariablePolicyHelperLib

+

+

+[Sources]

+  VariablePolicyHelperLib.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+

+[LibraryClasses]

+  BaseLib

+  DebugLib

+  MemoryAllocationLib

+  BaseMemoryLib

diff --git a/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.uni b/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.uni
new file mode 100644
index 000000000000..39cbf11a4ce9
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.uni
@@ -0,0 +1,12 @@
+// /** @file

+// VariablePolicyHelperLib.uni

+//

+// Copyright (c) Microsoft Corporation.

+// SPDX-License-Identifier: BSD-2-Clause-Patent

+//

+// **/

+

+

+#string STR_MODULE_ABSTRACT             #language en-US "Library containing helper functions for marshalling and registering new policies with the VariablePolicy infrastructure"

+

+#string STR_MODULE_DESCRIPTION          #language en-US "Library containing helper functions for marshalling and registering new policies with the VariablePolicy infrastructure"

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 31339741b840..2db37bd8ea9e 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -149,6 +149,11 @@ [LibraryClasses]
   #

   DisplayUpdateProgressLib|Include/Library/DisplayUpdateProgressLib.h

 

+  ##  @libraryclass  This library contains helper functions for marshalling and

+  #   registering new policies with the VariablePolicy infrastructure.

+  #

+  VariablePolicyHelperLib|Include/Library/VariablePolicyHelperLib.h

+

 [Guids]

   ## MdeModule package token space guid

   # Include/Guid/MdeModulePkgTokenSpace.h

diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 14b6ed536962..37795b9e4f58 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -99,6 +99,7 @@ [LibraryClasses]
   BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf

   SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf

   DisplayUpdateProgressLib|MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf

+  VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf

 

 [LibraryClasses.EBC.PEIM]

   IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf

@@ -225,6 +226,7 @@ [Components]
   MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf

   MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf

   MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.inf

+  MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf

 

   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf

   MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf

--
2.26.2.windows.1.8.g01c50adf56.20200515075929


-=-=-=-=-=-=
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#60645): https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Fmessage%2F60645&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7Cf4de67d242ec4517ab1c08d807a3dc74%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747648232766&amp;sdata=lTgPFRVTGwLnCIehU8h2owdPPBpbaxJwHJK9URkZCGM%3D&amp;reserved=0
Mute This Topic: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgroups.io%2Fmt%2F74646434%2F1822150&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7Cf4de67d242ec4517ab1c08d807a3dc74%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747648232766&amp;sdata=Gi2MEVRsoldxW%2FABl7CTfV2s07wj5MvzCKVWbGR5fo0%3D&amp;reserved=0
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Funsub&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7Cf4de67d242ec4517ab1c08d807a3dc74%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747648232766&amp;sdata=%2Bl6%2FLC0fMi3t5yz7KdUafNt1m1NcTXl0FNVjwYzRru0%3D&amp;reserved=0  [brbarkel@...]
-=-=-=-=-=-=


Re: [EXTERNAL] [edk2-devel] [PATCH v5 02/14] MdeModulePkg: Define the VariablePolicyLib

Bret Barkelew
 

Bump. This specific patch needs Reviews.

- Bret


From: devel@edk2.groups.io <devel@edk2.groups.io> on behalf of Bret Barkelew via groups.io <bret@...>
Sent: Tuesday, June 2, 2020 11:57 PM
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Jian J Wang <jian.j.wang@...>; Hao A Wu <hao.a.wu@...>; liming.gao <liming.gao@...>
Subject: [EXTERNAL] [edk2-devel] [PATCH v5 02/14] MdeModulePkg: Define the VariablePolicyLib
 
https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2522&amp;data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622305708&amp;sdata=V3OQlMW5ifVdpn5BJiGAmc8HsjXplYCm%2FdANjL9xbdI%3D&amp;reserved=0

VariablePolicy is an updated interface to
replace VarLock and VarCheckProtocol.

Add the VariablePolicyLib library that implements
the portable business logic for the VariablePolicy
engine.

Also add host-based CI test cases for the lib.

Cc: Jian J Wang <jian.j.wang@...>
Cc: Hao A Wu <hao.a.wu@...>
Cc: Liming Gao <liming.gao@...>
Cc: Bret Barkelew <brbarkel@...>
Signed-off-by: Bret Barkelew <brbarkel@...>
---
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c                     |   46 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c               |   85 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c                               |  813 +++++++
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.c   | 2436 ++++++++++++++++++++
 MdeModulePkg/Include/Library/VariablePolicyLib.h                                         |  207 ++
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf                             |   44 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni                             |   12 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf                   |   51 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf |   40 +
 MdeModulePkg/MdeModulePkg.dec                                                            |    3 +
 MdeModulePkg/MdeModulePkg.dsc                                                            |    5 +
 MdeModulePkg/Test/MdeModulePkgHostTest.dsc                                               |   11 +
 12 files changed, 3753 insertions(+)

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c
new file mode 100644
index 000000000000..ad2ee0b2fb8f
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c
@@ -0,0 +1,46 @@
+/** @file -- VariablePolicyExtraInitNull.c

+This file contains extra init and deinit routines that don't do anything

+extra.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#include <Library/UefiRuntimeServicesTableLib.h>

+

+

+/**

+  An extra init hook that enables the RuntimeDxe library instance to

+  register VirtualAddress change callbacks. Among other things.

+

+  @retval     EFI_SUCCESS   Everything is good. Continue with init.

+  @retval     Others        Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  )

+{

+  // NULL implementation.

+  return EFI_SUCCESS;

+}

+

+

+/**

+  An extra deinit hook that enables the RuntimeDxe library instance to

+  register VirtualAddress change callbacks. Among other things.

+

+  @retval     EFI_SUCCESS   Everything is good. Continue with deinit.

+  @retval     Others        Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraDeinit (

+  VOID

+  )

+{

+  // NULL implementation.

+  return EFI_SUCCESS;

+}

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c
new file mode 100644
index 000000000000..3ca87048b14b
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c
@@ -0,0 +1,85 @@
+/** @file -- VariablePolicyExtraInitRuntimeDxe.c

+This file contains extra init and deinit routines that register and unregister

+VariableAddressChange callbacks.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiRuntimeServicesTableLib.h>

+

+extern EFI_GET_VARIABLE   mGetVariableHelper;

+extern UINT8              *mPolicyTable;

+STATIC BOOLEAN            mIsVirtualAddrConverted;

+STATIC EFI_EVENT          mVariablePolicyLibVirtualAddressChangeEvent  = NULL;

+

+/**

+  For the RuntimeDxe version of this lib, convert internal pointer addresses to virtual addresses.

+

+  @param[in] Event      Event whose notification function is being invoked.

+  @param[in] Context    The pointer to the notification function's context, which

+                        is implementation-dependent.

+**/

+STATIC

+VOID

+EFIAPI

+VariablePolicyLibVirtualAddressCallback (

+  IN  EFI_EVENT   Event,

+  IN  VOID        *Context

+  )

+{

+  gRT->ConvertPointer (0, (VOID **)&mPolicyTable);

+  gRT->ConvertPointer (0, (VOID **)&mGetVariableHelper);

+  mIsVirtualAddrConverted = TRUE;

+}

+

+

+/**

+  An extra init hook that enables the RuntimeDxe library instance to

+  register VirtualAddress change callbacks. Among other things.

+

+  @retval     EFI_SUCCESS   Everything is good. Continue with init.

+  @retval     Others        Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  )

+{

+  return gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,

+                              TPL_NOTIFY,

+                              VariablePolicyLibVirtualAddressCallback,

+                              NULL,

+                              &gEfiEventVirtualAddressChangeGuid,

+                              &mVariablePolicyLibVirtualAddressChangeEvent);

+}

+

+

+/**

+  An extra deinit hook that enables the RuntimeDxe library instance to

+  register VirtualAddress change callbacks. Among other things.

+

+  @retval     EFI_SUCCESS   Everything is good. Continue with deinit.

+  @retval     Others        Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraDeinit (

+  VOID

+  )

+{

+  EFI_STATUS  Status;

+

+  Status = EFI_SUCCESS;

+  if (mIsVirtualAddrConverted) {

+    Status = gBS->CloseEvent (mVariablePolicyLibVirtualAddressChangeEvent);

+  }

+  else {

+    Status = EFI_SUCCESS;

+  }

+

+  return Status;

+}

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c
new file mode 100644
index 000000000000..c63807ef8531
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c
@@ -0,0 +1,813 @@
+/** @file -- VariablePolicyLib.c

+Business logic for Variable Policy enforcement.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#include <Uefi.h>

+

+#include <Library/SafeIntLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/PcdLib.h>

+

+#include <Protocol/VariablePolicy.h>

+#include <Library/VariablePolicyLib.h>

+

+

+// IMPORTANT NOTE: This library is currently rife with multiple return statements

+//                 for error handling. A refactor should remove these at some point.

+

+//

+// This library was designed with advanced unit-test features.

+// This define handles the configuration.

+#ifdef INTERNAL_UNIT_TEST

+#undef STATIC

+#define STATIC    // Nothing...

+#endif

+

+// An abstracted GetVariable interface that enables configuration regardless of the environment.

+EFI_GET_VARIABLE            mGetVariableHelper = NULL;

+

+// Master switch to lock this entire interface. Does not stop enforcement,

+// just prevents the configuration from being changed for the rest of the boot.

+STATIC  BOOLEAN             mInterfaceLocked = FALSE;

+

+// Master switch to disable the entire interface for a single boot.

+// This will disable all policy enforcement for the duration of the boot.

+STATIC  BOOLEAN             mProtectionDisabled = FALSE;

+

+// Table to hold all the current policies.

+UINT8                       *mPolicyTable = NULL;

+STATIC  UINT32              mCurrentTableSize = 0;

+STATIC  UINT32              mCurrentTableUsage = 0;

+STATIC  UINT32              mCurrentTableCount = 0;

+

+#define POLICY_TABLE_STEP_SIZE        0x1000

+

+// NOTE: DO NOT USE THESE MACROS on any structure that has not been validated.

+//       Current table data has already been sanitized.

+#define GET_NEXT_POLICY(CurPolicy)    (VARIABLE_POLICY_ENTRY*)((UINT8*)CurPolicy + CurPolicy->Size)

+#define GET_POLICY_NAME(CurPolicy)    (CHAR16*)((UINTN)CurPolicy + CurPolicy->OffsetToName)

+

+#define MATCH_PRIORITY_EXACT    0

+#define MATCH_PRIORITY_MAX      MATCH_PRIORITY_EXACT

+#define MATCH_PRIORITY_MIN      MAX_UINT8

+

+// ExtraInit/ExtraDeinit functions allow RuntimeDxe to register VirtualAddress callbacks.

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  );

+

+EFI_STATUS

+VariablePolicyExtraDeinit (

+  VOID

+  );

+

+

+/**

+  This helper function determines whether the structure of an incoming policy

+  is valid and internally consistent.

+

+  @param[in]  NewPolicy     Pointer to the incoming policy structure.

+

+  @retval     TRUE

+  @retval     FALSE   Pointer is NULL, size is wrong, strings are empty, or

+                      substructures overlap.

+

+**/

+STATIC

+BOOLEAN

+IsValidVariablePolicyStructure (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  )

+{

+  EFI_STATUS    Status;

+  UINTN         EntryEnd;

+  CHAR16        *CheckChar;

+  UINTN         WildcardCount;

+

+  // Sanitize some quick values.

+  if (NewPolicy == NULL || NewPolicy->Size == 0 ||

+      // Structure size should be at least as long as the minumum structure and a NULL string.

+      NewPolicy->Size < sizeof(VARIABLE_POLICY_ENTRY) ||

+      // Check for the known revision.

+      NewPolicy->Version != VARIABLE_POLICY_ENTRY_REVISION) {

+    return FALSE;

+  }

+

+  // Calculate the theoretical end of the structure and make sure

+  // that the structure can fit in memory.

+  Status = SafeUintnAdd( (UINTN)NewPolicy, NewPolicy->Size, &EntryEnd );

+  if (EFI_ERROR( Status )) {

+    return FALSE;

+  }

+

+  // Check for a valid Max Size.

+  if (NewPolicy->MaxSize == 0) {

+    return FALSE;

+  }

+

+  // Check for the valid list of lock policies.

+  if (NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_NO_LOCK &&

+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_NOW &&

+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_CREATE &&

+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE)

+  {

+    return FALSE;

+  }

+

+  // If the policy type is VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE, make sure that the matching state variable Name

+  // terminates before the OffsetToName for the matching policy variable Name.

+  if (NewPolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {

+    // Adjust CheckChar to the offset of the LockPolicy->Name.

+    Status = SafeUintnAdd( (UINTN)NewPolicy + sizeof(VARIABLE_POLICY_ENTRY),

+                            sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY),

+                            (UINTN*)&CheckChar );

+    if (EFI_ERROR( Status ) || EntryEnd <= (UINTN)CheckChar) {

+      return FALSE;

+    }

+    while (*CheckChar != CHAR_NULL) {

+      if (EntryEnd <= (UINTN)CheckChar) {

+        return FALSE;

+      }

+      CheckChar++;

+    }

+    // At this point we should have either exeeded the structure or be pointing at the last char in LockPolicy->Name.

+    // We should check to make sure that the policy Name comes immediately after this charcter.

+    if ((UINTN)++CheckChar != (UINTN)NewPolicy + NewPolicy->OffsetToName) {

+      return FALSE;

+    }

+  }

+  // If the policy type is any other value, make sure that the LockPolicy structure has a zero length.

+  else {

+    if (NewPolicy->OffsetToName != sizeof(VARIABLE_POLICY_ENTRY)) {

+      return FALSE;

+    }

+  }

+

+  // Check to make sure that the name has a terminating character

+  // before the end of the structure.

+  // We've already checked that the name is within the bounds of the structure.

+  if (NewPolicy->Size != NewPolicy->OffsetToName) {

+    CheckChar = (CHAR16*)((UINTN)NewPolicy + NewPolicy->OffsetToName);

+    WildcardCount = 0;

+    while (*CheckChar != CHAR_NULL) {

+      // Make sure there aren't excessive wildcards.

+      if (*CheckChar == '#') {

+        WildcardCount++;

+        if (WildcardCount > MATCH_PRIORITY_MIN) {

+          return FALSE;

+        }

+      }

+      // Make sure you're still within the bounds of the policy structure.

+      if (EntryEnd <= (UINTN)CheckChar) {

+        return FALSE;

+      }

+      CheckChar++;

+    }

+

+    // Finally, we should be pointed at the very last character in Name, so we should be right

+    // up against the end of the structure.

+    if ((UINTN)++CheckChar != EntryEnd) {

+      return FALSE;

+    }

+  }

+

+  return TRUE;

+}

+

+

+/**

+  This helper function evaluates a policy and determines whether it matches the target

+  variable. If matched, will also return a value corresponding to the priority of the match.

+

+  The rules for "best match" are listed in the Variable Policy Spec.

+  Perfect name matches will return 0.

+  Single wildcard characters will return the number of wildcard characters.

+  Full namespaces will return MAX_UINT8.

+

+  @param[in]  EvalEntry         Pointer to the policy entry being evaluated.

+  @param[in]  VariableName      Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid        Same as EFI_SET_VARIABLE.

+  @param[out] MatchPriority     [Optional] On finding a match, this value contains the priority of the match.

+                                Lower number == higher priority. Only valid if a match found.

+

+  @retval     TRUE          Current entry matches the target variable.

+  @retval     FALSE         Current entry does not match at all.

+

+**/

+STATIC

+BOOLEAN

+EvaluatePolicyMatch (

+  IN CONST  VARIABLE_POLICY_ENTRY   *EvalEntry,

+  IN CONST  CHAR16                  *VariableName,

+  IN CONST  EFI_GUID                *VendorGuid,

+  OUT       UINT8                   *MatchPriority    OPTIONAL

+  )

+{

+  BOOLEAN     Result;

+  CHAR16      *PolicyName;

+  UINT8       CalculatedPriority;

+  UINTN       Index;

+

+  Result = FALSE;

+  CalculatedPriority = MATCH_PRIORITY_EXACT;

+

+  // Step 1: If the GUID doesn't match, we're done. No need to evaluate anything else.

+  if (!CompareGuid( &EvalEntry->Namespace, VendorGuid )) {

+    goto Exit;

+  }

+

+  // If the GUID matches, check to see whether there is a Name associated

+  // with the policy. If not, this policy matches the entire namespace.

+  // Missing Name is indicated by size being equal to name.

+  if (EvalEntry->Size == EvalEntry->OffsetToName) {

+    CalculatedPriority = MATCH_PRIORITY_MIN;

+    Result = TRUE;

+    goto Exit;

+  }

+

+  // Now that we know the name exists, get it.

+  PolicyName = GET_POLICY_NAME( EvalEntry );

+

+  // Evaluate the name against the policy name and check for a match.

+  // Account for any wildcards.

+  Index = 0;

+  Result = TRUE;

+  // Keep going until the end of both strings.

+  while (PolicyName[Index] != CHAR_NULL || VariableName[Index] != CHAR_NULL) {

+    // If we don't have a match...

+    if (PolicyName[Index] != VariableName[Index] || PolicyName[Index] == '#') {

+      // If this is a numerical wildcard, we can consider

+      // it a match if we alter the priority.

+      if (PolicyName[Index] == L'#' &&

+          (L'0' <= VariableName[Index] && VariableName[Index] <= L'9')) {

+        if (CalculatedPriority < MATCH_PRIORITY_MIN) {

+          CalculatedPriority++;

+        }

+      }

+      // Otherwise, not a match.

+      else {

+        Result = FALSE;

+        goto Exit;

+      }

+    }

+    Index++;

+  }

+

+Exit:

+  if (Result && MatchPriority != NULL) {

+    *MatchPriority = CalculatedPriority;

+  }

+  return Result;

+}

+

+

+/**

+  This helper function walks the current policy table and returns a pointer

+  to the best match, if any are found. Leverages EvaluatePolicyMatch() to

+  determine "best".

+

+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.

+  @param[out] ReturnPriority     [Optional] If pointer is provided, return the

+                                 priority of the match. Same as EvaluatePolicyMatch().

+                                 Only valid if a match is returned.

+

+  @retval     VARIABLE_POLICY_ENTRY*    Best match that was found.

+  @retval     NULL                      No match was found.

+

+**/

+STATIC

+VARIABLE_POLICY_ENTRY*

+GetBestPolicyMatch (

+  IN CONST  CHAR16            *VariableName,

+  IN CONST  EFI_GUID          *VendorGuid,

+  OUT       UINT8             *ReturnPriority  OPTIONAL

+  )

+{

+  VARIABLE_POLICY_ENTRY   *BestResult;

+  VARIABLE_POLICY_ENTRY   *CurrentEntry;

+  UINT8                   MatchPriority;

+  UINT8                   CurrentPriority;

+  UINTN                   Index;

+

+  BestResult = NULL;

+

+  // Walk all entries in the table, looking for matches.

+  CurrentEntry = (VARIABLE_POLICY_ENTRY*)mPolicyTable;

+  for (Index = 0; Index < mCurrentTableCount; Index++) {

+    // Check for a match.

+    if (EvaluatePolicyMatch( CurrentEntry, VariableName, VendorGuid, &CurrentPriority )) {

+      // If match is better, take it.

+      if (BestResult == NULL || CurrentPriority < MatchPriority) {

+        BestResult = CurrentEntry;

+        MatchPriority = CurrentPriority;

+      }

+

+      // If you've hit the highest-priority match, can exit now.

+      if (MatchPriority == 0) {

+        break;

+      }

+    }

+

+    // If we're still in the loop, move to the next entry.

+    CurrentEntry = GET_NEXT_POLICY( CurrentEntry );

+  }

+

+  // If a return priority was requested, return it.

+  if (ReturnPriority != NULL) {

+    *ReturnPriority = MatchPriority;

+  }

+

+  return BestResult;

+}

+

+

+/**

+  This API function validates and registers a new policy with

+  the policy enforcement engine.

+

+  @param[in]  NewPolicy     Pointer to the incoming policy structure.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally inconsistent.

+  @retval     EFI_ALREADY_STARTED     An identical matching policy already exists.

+  @retval     EFI_WRITE_PROTECTED     The interface has been locked until the next reboot.

+  @retval     EFI_UNSUPPORTED         Policy enforcement has been disabled. No reason to add more policies.

+  @retval     EFI_ABORTED             A calculation error has prevented this function from completing.

+  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any more policies.

+  @retval     EFI_NOT_READY           Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+RegisterVariablePolicy (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  )

+{

+  EFI_STATUS                Status;

+  VARIABLE_POLICY_ENTRY     *MatchPolicy;

+  UINT8                     MatchPriority;

+  UINT32                    NewSize;

+  UINT8                     *NewTable;

+

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+  if (mInterfaceLocked) {

+    return EFI_WRITE_PROTECTED;

+  }

+

+  if (!IsValidVariablePolicyStructure( NewPolicy )) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  // Check to see whether an exact matching policy already exists.

+  MatchPolicy = GetBestPolicyMatch( GET_POLICY_NAME( NewPolicy ),

+                                    &NewPolicy->Namespace,

+                                    &MatchPriority );

+  if (MatchPolicy != NULL && MatchPriority == MATCH_PRIORITY_EXACT) {

+    return EFI_ALREADY_STARTED;

+  }

+

+  // If none exists, create it.

+  // If we need more space, allocate that now.

+  Status = SafeUint32Add( mCurrentTableUsage, NewPolicy->Size, &NewSize );

+  if (EFI_ERROR( Status )) {

+    return EFI_ABORTED;

+  }

+  if (NewSize > mCurrentTableSize) {

+    // Use NewSize to calculate the new table size in units of POLICY_TABLE_STEP_SIZE.

+    NewSize = (NewSize % POLICY_TABLE_STEP_SIZE) > 0 ?

+                (NewSize / POLICY_TABLE_STEP_SIZE) + 1 :

+                (NewSize / POLICY_TABLE_STEP_SIZE);

+    // Calculate the new table size in absolute bytes.

+    Status = SafeUint32Mult( NewSize, POLICY_TABLE_STEP_SIZE, &NewSize );

+    if (EFI_ERROR( Status )) {

+      return EFI_ABORTED;

+    }

+

+    // Reallocate and copy the table.

+    NewTable = AllocatePool( NewSize );

+    if (NewTable == NULL) {

+      return EFI_OUT_OF_RESOURCES;

+    }

+    CopyMem( NewTable, mPolicyTable, mCurrentTableUsage );

+    mCurrentTableSize = NewSize;

+    if (mPolicyTable != NULL) {

+      FreePool( mPolicyTable );

+    }

+    mPolicyTable = NewTable;

+  }

+  // Copy the policy into the table.

+  CopyMem( mPolicyTable + mCurrentTableUsage, NewPolicy, NewPolicy->Size );

+  mCurrentTableUsage += NewPolicy->Size;

+  mCurrentTableCount += 1;

+

+  // We're done here.

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  This API function checks to see whether the parameters to SetVariable would

+  be allowed according to the current variable policies.

+

+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.

+  @param[in]  Attributes         Same as EFI_SET_VARIABLE.

+  @param[in]  DataSize           Same as EFI_SET_VARIABLE.

+  @param[in]  Data               Same as EFI_SET_VARIABLE.

+

+  @retval     EFI_SUCCESS             A matching policy allows this update.

+  @retval     EFI_SUCCESS             There are currently no policies that restrict this update.

+  @retval     EFI_SUCCESS             The protections have been disable until the next reboot.

+  @retval     EFI_WRITE_PROTECTED     Variable is currently locked.

+  @retval     EFI_INVALID_PARAMETER   Attributes or size are invalid.

+  @retval     EFI_ABORTED             A lock policy exists, but an error prevented evaluation.

+  @retval     EFI_NOT_READY           Library has not been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+ValidateSetVariable (

+  IN  CHAR16                       *VariableName,

+  IN  EFI_GUID                     *VendorGuid,

+  IN  UINT32                       Attributes,

+  IN  UINTN                        DataSize,

+  IN  VOID                         *Data

+  )

+{

+  BOOLEAN                             IsDel;

+  VARIABLE_POLICY_ENTRY               *ActivePolicy;

+  EFI_STATUS                          Status;

+  EFI_STATUS                          ReturnStatus;

+  VARIABLE_LOCK_ON_VAR_STATE_POLICY   *StateVarPolicy;

+  CHAR16                              *StateVarName;

+  UINTN                               StateVarSize;

+  UINT8                               StateVar;

+

+  ReturnStatus = EFI_SUCCESS;

+

+  if (!IsVariablePolicyLibInitialized()) {

+    ReturnStatus = EFI_NOT_READY;

+    goto Exit;

+  }

+

+  // Bail if the protections are currently disabled.

+  if (mProtectionDisabled) {

+    ReturnStatus = EFI_SUCCESS;

+    goto Exit;

+  }

+

+  // Determine whether this is a delete operation.

+  // If so, it will affect which tests are applied.

+  if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {

+    IsDel = TRUE;

+  }

+  else {

+    IsDel = FALSE;

+  }

+

+  // Find an active policy if one exists.

+  ActivePolicy = GetBestPolicyMatch( VariableName, VendorGuid, NULL );

+

+  // If we have an active policy, check it against the incoming data.

+  if (ActivePolicy != NULL) {

+    //

+    // Only enforce size and attribute constraints when updating data, not deleting.

+    if (!IsDel) {

+      // Check for size constraints.

+      if ((ActivePolicy->MinSize > 0 && DataSize < ActivePolicy->MinSize) ||

+          (ActivePolicy->MaxSize > 0 && DataSize > ActivePolicy->MaxSize)) {

+        ReturnStatus = EFI_INVALID_PARAMETER;

+        DEBUG(( DEBUG_VERBOSE, "%a - Bad Size. 0x%X <> 0x%X-0x%X\n", __FUNCTION__,

+                DataSize, ActivePolicy->MinSize, ActivePolicy->MaxSize ));

+        goto Exit;

+      }

+

+      // Check for attribute constraints.

+      if ((ActivePolicy->AttributesMustHave & Attributes) != ActivePolicy->AttributesMustHave ||

+          (ActivePolicy->AttributesCantHave & Attributes) != 0) {

+        ReturnStatus = EFI_INVALID_PARAMETER;

+        DEBUG(( DEBUG_VERBOSE, "%a - Bad Attributes. 0x%X <> 0x%X:0x%X\n", __FUNCTION__,

+                Attributes, ActivePolicy->AttributesMustHave, ActivePolicy->AttributesCantHave ));

+        goto Exit;

+      }

+    }

+

+    //

+    // Lock policy check.

+    //

+    // Check for immediate lock.

+    if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_NOW) {

+      ReturnStatus = EFI_WRITE_PROTECTED;

+      goto Exit;

+    }

+    // Check for lock on create.

+    else if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_CREATE) {

+      StateVarSize = 0;

+      Status = mGetVariableHelper( VariableName,

+                                   VendorGuid,

+                                   NULL,

+                                   &StateVarSize,

+                                   NULL );

+      if (Status == EFI_BUFFER_TOO_SMALL) {

+        ReturnStatus = EFI_WRITE_PROTECTED;

+        goto Exit;

+      }

+    }

+    // Check for lock on state variable.

+    else if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {

+      StateVarPolicy = (VARIABLE_LOCK_ON_VAR_STATE_POLICY*)((UINT8*)ActivePolicy + sizeof(VARIABLE_POLICY_ENTRY));

+      StateVarName = (CHAR16*)((UINT8*)StateVarPolicy + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY));

+      StateVarSize = sizeof(StateVar);

+      Status = mGetVariableHelper( StateVarName,

+                                   &StateVarPolicy->Namespace,

+                                   NULL,

+                                   &StateVarSize,

+                                   &StateVar );

+

+      // If the variable was found, check the state. If matched, this variable is locked.

+      if (!EFI_ERROR( Status )) {

+        if (StateVar == StateVarPolicy->Value) {

+          ReturnStatus = EFI_WRITE_PROTECTED;

+          goto Exit;

+        }

+      }

+      // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMALL indicate that the state doesn't match.

+      else if (Status != EFI_NOT_FOUND && Status != EFI_BUFFER_TOO_SMALL) {

+        // We don't know what happened, but it isn't good.

+        ReturnStatus = EFI_ABORTED;

+        goto Exit;

+      }

+    }

+  }

+

+Exit:

+  DEBUG(( DEBUG_VERBOSE, "%a - Variable (%g:%s) returning %r.\n", __FUNCTION__, VendorGuid, VariableName, ReturnStatus ));

+  return ReturnStatus;

+}

+

+

+/**

+  This API function disables the variable policy enforcement. If it's

+  already been called once, will return EFI_ALREADY_STARTED.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.

+  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.

+  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform PCD.

+  @retval     EFI_NOT_READY         Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DisableVariablePolicy (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+  if (mProtectionDisabled) {

+    return EFI_ALREADY_STARTED;

+  }

+  if (mInterfaceLocked) {

+    return EFI_WRITE_PROTECTED;

+  }

+  if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {

+    return EFI_WRITE_PROTECTED;

+  }

+  mProtectionDisabled = TRUE;

+  return EFI_SUCCESS;

+}

+

+

+/**

+  This API function will dump the entire contents of the variable policy table.

+

+  Similar to GetVariable, the first call can be made with a 0 size and it will return

+  the size of the buffer required to hold the entire table.

+

+  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size is 0.

+  @param[in,out]  Size    On input, the size of the output buffer. On output, the size

+                          of the data returned.

+

+  @retval     EFI_SUCCESS             Policy data is in the output buffer and Size has been updated.

+  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and Policy is NULL.

+  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. Size updated with required size.

+  @retval     EFI_NOT_READY           Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DumpVariablePolicy (

+  OUT     UINT8         *Policy,

+  IN OUT  UINT32        *Size

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+

+  // Check the parameters.

+  if (Size == NULL || (*Size > 0 && Policy == NULL)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  // Make sure the size is sufficient to hold the policy table.

+  if (*Size < mCurrentTableUsage) {

+    *Size = mCurrentTableUsage;

+    return EFI_BUFFER_TOO_SMALL;

+  }

+

+  // If we're still here, copy the table and bounce.

+  CopyMem( Policy, mPolicyTable, mCurrentTableUsage );

+  *Size = mCurrentTableUsage;

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  This API function returns whether or not the policy engine is

+  currently being enforced.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE         Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyEnabled (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return FALSE;

+  }

+  return !mProtectionDisabled;

+}

+

+

+/**

+  This API function locks the interface so that no more policy updates

+  can be performed or changes made to the enforcement until the next boot.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY   Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+LockVariablePolicy (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+  if (mInterfaceLocked) {

+    return EFI_WRITE_PROTECTED;

+  }

+  mInterfaceLocked = TRUE;

+  return EFI_SUCCESS;

+}

+

+

+/**

+  This API function returns whether or not the policy interface is locked

+  for the remainder of the boot.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE         Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyInterfaceLocked (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return FALSE;

+  }

+  return mInterfaceLocked;

+}

+

+

+/**

+  This helper function initializes the library and sets

+  up any required internal structures or handlers.

+

+  Also registers the internal pointer for the GetVariable helper.

+

+  @param[in]  GetVariableHelper A function pointer matching the EFI_GET_VARIABLE prototype that will be used to

+                  check policy criteria that involve the existence of other variables.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   The initialize function has been called more than once without a call to

+                                    deinitialize.

+

+**/

+EFI_STATUS

+EFIAPI

+InitVariablePolicyLib (

+  IN  EFI_GET_VARIABLE    GetVariableHelper

+  )

+{

+  EFI_STATUS    Status;

+

+  if (mGetVariableHelper != NULL) {

+    Status = EFI_ALREADY_STARTED;

+  }

+

+  if (!EFI_ERROR( Status )) {

+    Status = VariablePolicyExtraInit();

+  }

+

+  if (!EFI_ERROR( Status )) {

+    // Save an internal pointer to the GetVariableHelper.

+    mGetVariableHelper = GetVariableHelper;

+

+    // Initialize the global state.

+    mInterfaceLocked = FALSE;

+    mProtectionDisabled = FALSE;

+    mPolicyTable = NULL;

+    mCurrentTableSize = 0;

+    mCurrentTableUsage = 0;

+    mCurrentTableCount = 0;

+  }

+

+  return Status;

+}

+

+

+/**

+  This helper function returns whether or not the library is currently initialized.

+

+  @retval     TRUE

+  @retval     FALSE

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyLibInitialized (

+  VOID

+  )

+{

+  return (mGetVariableHelper != NULL);

+}

+

+

+/**

+  This helper function tears down  the library.

+

+  Should generally only be used for test harnesses.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY     Deinitialize was called without first calling initialize.

+

+**/

+EFI_STATUS

+EFIAPI

+DeinitVariablePolicyLib (

+  VOID

+  )

+{

+  EFI_STATUS    Status;

+

+  if (mGetVariableHelper == NULL) {

+    Status = EFI_NOT_READY;

+  }

+

+  if (!EFI_ERROR( Status )) {

+    Status = VariablePolicyExtraDeinit();

+  }

+

+  if (!EFI_ERROR( Status )) {

+    mGetVariableHelper = NULL;

+    mInterfaceLocked = FALSE;

+    mProtectionDisabled = FALSE;

+    mCurrentTableSize = 0;

+    mCurrentTableUsage = 0;

+    mCurrentTableCount = 0;

+

+    if (mPolicyTable != NULL) {

+      FreePool( mPolicyTable );

+      mPolicyTable = NULL;

+    }

+  }

+

+  return Status;

+}

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.c
new file mode 100644
index 000000000000..f133f2f30e36
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.c
@@ -0,0 +1,2436 @@
+/** @file -- VariablePolicyUnitTest.c

+UnitTest for...

+Business logic for Variable Policy enforcement.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#include <stdio.h>

+#include <string.h>

+#include <stdarg.h>

+#include <stddef.h>

+#include <setjmp.h>

+#include <cmocka.h>

+

+#include <Uefi.h>

+#include <Library/PrintLib.h>

+#include <Library/DebugLib.h>

+#include <Library/UnitTestLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/BaseLib.h>

+

+#include <Guid/VariableFormat.h>

+

+#include <Protocol/VariablePolicy.h>

+#include <Library/VariablePolicyLib.h>

+

+// MU_CHANGE - Turn this off for now. Try to turn it back on with extra build options.

+// #ifndef INTERNAL_UNIT_TEST

+// #error Make sure to build thie with INTERNAL_UNIT_TEST enabled! Otherwise, some important tests may be skipped!

+// #endif

+

+

+#define UNIT_TEST_NAME        "UEFI Variable Policy UnitTest"

+#define UNIT_TEST_VERSION     "0.5"

+

+///=== TEST DATA ==================================================================================

+

+#pragma pack(push, 1)

+typedef struct _SIMPLE_VARIABLE_POLICY_ENTRY {

+  VARIABLE_POLICY_ENTRY     Header;

+  CHAR16                    Name[];

+} SIMPLE_VARIABLE_POLICY_ENTRY;

+#define EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH  1001    // 1000 characters + terminator.

+#define EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE    (EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH * sizeof(CHAR16))

+typedef struct _EXPANDED_VARIABLE_POLICY_ENTRY {

+  VARIABLE_POLICY_ENTRY               Header;

+  VARIABLE_LOCK_ON_VAR_STATE_POLICY   StatePolicy;

+  CHAR16                              StateName[EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH];

+  CHAR16                              Name[EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH];

+} EXPANDED_VARIABLE_POLICY_ENTRY;

+#pragma pack(pop)

+

+// {F955BA2D-4A2C-480C-BFD1-3CC522610592}

+#define TEST_GUID_1 { 0xf955ba2d, 0x4a2c, 0x480c, { 0xbf, 0xd1, 0x3c, 0xc5, 0x22, 0x61, 0x5, 0x92 } }

+EFI_GUID    mTestGuid1 = TEST_GUID_1;

+// {2DEA799E-5E73-43B9-870E-C945CE82AF3A}

+#define TEST_GUID_2 { 0x2dea799e, 0x5e73, 0x43b9, { 0x87, 0xe, 0xc9, 0x45, 0xce, 0x82, 0xaf, 0x3a } }

+EFI_GUID    mTestGuid2 = TEST_GUID_2;

+// {698A2BFD-A616-482D-B88C-7100BD6682A9}

+#define TEST_GUID_3 { 0x698a2bfd, 0xa616, 0x482d, { 0xb8, 0x8c, 0x71, 0x0, 0xbd, 0x66, 0x82, 0xa9 } }

+EFI_GUID    mTestGuid3 = TEST_GUID_3;

+

+#define   TEST_VAR_1_NAME                 L"TestVar1"

+#define   TEST_VAR_2_NAME                 L"TestVar2"

+#define   TEST_VAR_3_NAME                 L"TestVar3"

+

+#define   TEST_POLICY_ATTRIBUTES_NULL     0

+#define   TEST_POLICY_MIN_SIZE_NULL       0

+#define   TEST_POLICY_MAX_SIZE_NULL       MAX_UINT32

+

+#define   TEST_POLICY_MIN_SIZE_10         10

+#define   TEST_POLICY_MAX_SIZE_200        200

+

+#define TEST_300_HASHES_STRING      L"##################################################"\

+                                      "##################################################"\

+                                      "##################################################"\

+                                      "##################################################"\

+                                      "##################################################"\

+                                      "##################################################"

+

+

+///=== HELPER FUNCTIONS ===========================================================================

+

+/**

+  Helper function to initialize a VARIABLE_POLICY_ENTRY structure with a Name and StateName.

+

+  Takes care of all the messy packing.

+

+  @param[in,out]  Entry

+  @param[in]      Name        [Optional]

+  @param[in]      StateName   [Optional]

+

+  @retval     TRUE

+  @retval     FALSE

+

+**/

+STATIC

+BOOLEAN

+InitExpVarPolicyStrings (

+  EXPANDED_VARIABLE_POLICY_ENTRY      *Entry,

+  CHAR16                              *Name,      OPTIONAL

+  CHAR16                              *StateName  OPTIONAL

+  )

+{

+  UINTN     NameSize;

+  UINTN     StateNameSize;

+

+  NameSize = Name == NULL ? 0 : StrSize( Name );

+  StateNameSize = StateName == NULL ? 0 : StrSize( StateName );

+

+  if (NameSize > EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE || NameSize > MAX_UINT16 ||

+      StateNameSize > EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE || StateNameSize > MAX_UINT16) {

+    return FALSE;

+  }

+

+  Entry->Header.OffsetToName = sizeof(VARIABLE_POLICY_ENTRY);

+  if (StateName != NULL) {

+    Entry->Header.OffsetToName += (UINT16)sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY) + (UINT16)StateNameSize;

+  }

+  Entry->Header.Size = Entry->Header.OffsetToName + (UINT16)NameSize;

+

+  CopyMem( (UINT8*)Entry + Entry->Header.OffsetToName, Name, NameSize );

+  if (StateName != NULL) {

+    CopyMem( (UINT8*)Entry + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY), StateName, StateNameSize );

+  }

+

+  return TRUE;

+}

+

+/**

+  Mocked version of GetVariable, for testing.

+**/

+EFI_STATUS

+EFIAPI

+StubGetVariableNull (

+  IN     CHAR16                      *VariableName,

+  IN     EFI_GUID                    *VendorGuid,

+  OUT    UINT32                      *Attributes,    OPTIONAL

+  IN OUT UINTN                       *DataSize,

+  OUT    VOID                        *Data           OPTIONAL

+  )

+{

+  UINT32      MockedAttr;

+  UINTN       MockedDataSize;

+  VOID        *MockedData;

+  EFI_STATUS  MockedReturn;

+

+  check_expected_ptr( VariableName );

+  check_expected_ptr( VendorGuid );

+  check_expected_ptr( DataSize );

+

+  MockedAttr = (UINT32)mock();

+  MockedDataSize = (UINTN)mock();

+  MockedData = (VOID*)mock();

+  MockedReturn = (EFI_STATUS)mock();

+

+  if (Attributes != NULL) {

+    *Attributes = MockedAttr;

+  }

+  if (Data != NULL && !EFI_ERROR(MockedReturn)) {

+    CopyMem( Data, MockedData, MockedDataSize );

+  }

+

+  *DataSize = MockedDataSize;

+

+  return MockedReturn;

+}

+

+//

+// Anything you think might be helpful that isn't a test itself.

+//

+

+/**

+  This is a common setup function that will ensure the library is always initialized

+  with the stubbed GetVariable.

+

+  Not used by all test cases, but by most.

+**/

+STATIC

+UNIT_TEST_STATUS

+LibInitMocked (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  return EFI_ERROR(InitVariablePolicyLib( StubGetVariableNull )) ? UNIT_TEST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED;

+}

+

+/**

+  Common cleanup function to make sure that the library is always de-initialized prior

+  to the next test case.

+*/

+STATIC

+VOID

+LibCleanup (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  DeinitVariablePolicyLib();

+}

+

+

+///=== TEST CASES =================================================================================

+

+///===== ARCHITECTURAL SUITE ==================================================

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToInitAndDeinitTheLibrary (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EFI_STATUS    Status;

+  Status = InitVariablePolicyLib( StubGetVariableNull );

+  UT_ASSERT_NOT_EFI_ERROR( Status );

+

+  UT_ASSERT_TRUE( IsVariablePolicyLibInitialized() );

+

+  Status = DeinitVariablePolicyLib();

+  UT_ASSERT_NOT_EFI_ERROR( Status );

+

+  UT_ASSERT_FALSE( IsVariablePolicyLibInitialized() );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldNotBeAbleToInitializeTheLibraryTwice (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EFI_STATUS    Status;

+  Status = InitVariablePolicyLib( StubGetVariableNull );

+  UT_ASSERT_NOT_EFI_ERROR( Status );

+  Status = InitVariablePolicyLib( StubGetVariableNull );

+  UT_ASSERT_TRUE( EFI_ERROR( Status ) );

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldFailDeinitWithoutInit (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EFI_STATUS    Status;

+  Status = DeinitVariablePolicyLib();

+  UT_ASSERT_TRUE( EFI_ERROR( Status ) );

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ApiCommandsShouldNotRespondIfLibIsUninitialized (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  UINT8     DummyData[8];

+  UINT32    DummyDataSize = sizeof(DummyData);

+

+  // This test should not start with an initialized library.

+

+  // Verify that all API commands fail.

+  UT_ASSERT_TRUE( EFI_ERROR( LockVariablePolicy() ) );

+  UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );

+  UT_ASSERT_TRUE( EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) ) );

+  UT_ASSERT_TRUE( EFI_ERROR( DumpVariablePolicy( DummyData, &DummyDataSize ) ) );

+  UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );

+  UT_ASSERT_FALSE( IsVariablePolicyEnabled() );

+  UT_ASSERT_TRUE( EFI_ERROR( ValidateSetVariable( TEST_VAR_1_NAME,

+                                                 &mTestGuid1,

+                                                 VARIABLE_ATTRIBUTE_NV_BS,

+                                                 sizeof(DummyData),

+                                                 DummyData ) ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+

+///===== INTERNAL FUNCTION SUITE ==============================================

+

+#ifdef INTERNAL_UNIT_TEST

+

+BOOLEAN

+EvaluatePolicyMatch (

+  IN CONST  VARIABLE_POLICY_ENTRY   *EvalEntry,

+  IN CONST  CHAR16                  *VariableName,

+  IN CONST  EFI_GUID                *VendorGuid,

+  OUT       UINT8                   *MatchPriority    OPTIONAL

+  );

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+PoliciesShouldMatchByNameAndGuid (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  CHAR16        *CheckVar1Name = TEST_VAR_1_NAME;

+  CHAR16        *CheckVar2Name = TEST_VAR_2_NAME;

+

+  // Make sure that a different name does not match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar2Name, &mTestGuid1, NULL ) );

+

+  // Make sure that a different GUID does not match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid2, NULL ) );

+

+  // Make sure that the same name and GUID match.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, NULL ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+WildcardPoliciesShouldMatchDigits (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wildcard#VarName##"),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    L"Wildcard#VarName##"

+  };

+  CHAR16        *CheckVar1Name = L"Wildcard1VarName12";

+  CHAR16        *CheckVar2Name = L"Wildcard2VarName34";

+  CHAR16        *CheckVarBName = L"WildcardBVarName56";

+  CHAR16        *CheckVarHName = L"Wildcard#VarName56";

+

+  // Make sure that two different sets of wildcard numbers match.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar2Name, &mTestGuid1, NULL ) );

+

+  // Make sure that the non-number charaters don't match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVarBName, &mTestGuid1, NULL ) );

+

+  // Make sure that '#' signs don't match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVarHName, &mTestGuid1, NULL ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+WildcardPoliciesShouldMatchDigitsAdvanced (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_300_HASHES_STRING),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_300_HASHES_STRING

+  };

+  CHAR16        *CheckShorterString = L"01234567890123456789012345678901234567890123456789";

+  CHAR16        *CheckValidString = L"01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789";

+  CHAR16        *CheckLongerString = L"01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789";

+  UINT8         MatchPriority;

+

+  // Make sure that the shorter and the longer do not match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckShorterString, &mTestGuid1, NULL ) );

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckLongerString, &mTestGuid1, NULL ) );

+

+  // Make sure that the valid one matches and has the expected priority.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckValidString, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, MAX_UINT8 );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+WildcardPoliciesShouldMatchNamespaces (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    VARIABLE_POLICY_ENTRY_REVISION,

+    sizeof(VARIABLE_POLICY_ENTRY),

+    sizeof(VARIABLE_POLICY_ENTRY),

+    TEST_GUID_1,

+    TEST_POLICY_MIN_SIZE_NULL,

+    TEST_POLICY_MAX_SIZE_NULL,

+    TEST_POLICY_ATTRIBUTES_NULL,

+    TEST_POLICY_ATTRIBUTES_NULL,

+    VARIABLE_POLICY_TYPE_NO_LOCK

+  };

+  CHAR16        *CheckVar1Name = L"Wildcard1VarName12";

+  CHAR16        *CheckVar2Name = L"Wildcard2VarName34";

+  CHAR16        *CheckVarBName = L"WildcardBVarName56";

+  CHAR16        *CheckVarHName = L"Wildcard#VarName56";

+

+  // Make sure that all names in the same namespace match.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar1Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar2Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVarBName, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVarHName, &mTestGuid1, NULL ) );

+

+  // Make sure that different namespace doesn't match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar1Name, &mTestGuid2, NULL ) );

+

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+MatchPrioritiesShouldFollowRules (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wildcard1VarName12"),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    L"Wildcard1VarName12"

+  };

+  CHAR16        CheckVar1Name[] = L"Wildcard1VarName12";

+  CHAR16        MatchVar1Name[] = L"Wildcard1VarName12";

+  CHAR16        MatchVar2Name[] = L"Wildcard#VarName12";

+  CHAR16        MatchVar3Name[] = L"Wildcard#VarName#2";

+  CHAR16        MatchVar4Name[] = L"Wildcard#VarName##";

+  UINT8         MatchPriority;

+

+  // Check with a perfect match.

+  CopyMem( &MatchCheckPolicy.Name, MatchVar1Name, sizeof(MatchVar1Name) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 0 );

+

+  // Check with progressively lower priority matches.

+  CopyMem( &MatchCheckPolicy.Name, MatchVar2Name, sizeof(MatchVar2Name) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 1 );

+  CopyMem( &MatchCheckPolicy.Name, MatchVar3Name, sizeof(MatchVar3Name) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 2 );

+  CopyMem( &MatchCheckPolicy.Name, MatchVar4Name, sizeof(MatchVar4Name) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 3 );

+

+  // Check against the entire namespace.

+  MatchCheckPolicy.Header.Size = sizeof(VARIABLE_POLICY_ENTRY);

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, MAX_UINT8 );

+

+  return UNIT_TEST_PASSED;

+}

+

+#endif // INTERNAL_UNIT_TEST

+

+

+///=== POLICY MANIPULATION SUITE ==============================================

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldAllowNamespaceWildcards (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    L""

+  };

+

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldAllowStateVarsForNamespaces (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, NULL, TEST_VAR_2_NAME ) );

+

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectNullPointers (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( NULL ), EFI_INVALID_PARAMETER );

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectBadRevisions (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  ValidationPolicy.Header.Version = MAX_UINT32;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectBadSizes (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  ValidationPolicy.Header.Size = sizeof(VARIABLE_POLICY_ENTRY) - 2;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectBadOffsets (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Check for an offset outside the size bounds.

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.Size + 1;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Check for an offset inside the policy header.

+  ValidationPolicy.Header.OffsetToName = sizeof(VARIABLE_POLICY_ENTRY) - 2;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Check for an offset inside the state policy header.

+  ValidationPolicy.Header.OffsetToName = sizeof(VARIABLE_POLICY_ENTRY) + 2;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Check for a ridiculous offset.

+  ValidationPolicy.Header.OffsetToName = MAX_UINT16;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectMissingStateStrings (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Remove the state string and copy the Name into it's place.

+  // Also adjust the offset.

+  ValidationPolicy.Header.Size          = sizeof(VARIABLE_POLICY_ENTRY) + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY) + sizeof(TEST_VAR_1_NAME);

+  ValidationPolicy.Header.OffsetToName  = sizeof(VARIABLE_POLICY_ENTRY) + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+

+  // Make sure that this structure fails.

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectStringsMissingNull (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Removing the NULL from the Name should fail.

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.Size - sizeof(CHAR16);

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Removing the NULL from the State Name is a little trickier.

+  // Copy the Name up one byte.

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.OffsetToName - sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectMalformedStrings (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Bisecting the NULL from the Name should fail.

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.Size - 1;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Bisecting the NULL from the State Name is a little trickier.

+  // Copy the Name up one byte.

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.OffsetToName - 1;

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectUnpackedPolicies (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Increase the size and move the Name out a bit.

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.Size + sizeof(CHAR16);

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.OffsetToName + sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Reintialize without the state policy and try the same test.

+  ValidationPolicy.Header.LockPolicyType = VARIABLE_POLICY_TYPE_NO_LOCK;

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, NULL ) );

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.Size + sizeof(CHAR16);

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.OffsetToName + sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectInvalidNameCharacters (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  // EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+  //   {

+  //     VARIABLE_POLICY_ENTRY_REVISION,

+  //     0,    // Will be populated by init helper.

+  //     0,    // Will be populated by init helper.

+  //     TEST_GUID_1,

+  //     TEST_POLICY_MIN_SIZE_NULL,

+  //     TEST_POLICY_MAX_SIZE_NULL,

+  //     TEST_POLICY_ATTRIBUTES_NULL,

+  //     TEST_POLICY_ATTRIBUTES_NULL,

+  //     VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+  //   },

+  //   {

+  //     TEST_GUID_2,

+  //     1,            // Value

+  //     0             // Padding

+  //   },

+  //   L"",

+  //   L""

+  // };

+

+  // Currently, there are no known invalid characters.

+  // '#' in LockPolicy->Name are taken as literal.

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectBadPolicyConstraints (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  // Make sure that invalid MAXes are rejected.

+  ValidationPolicy.Header.MaxSize = 0;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectUnknownLockPolicies (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  ValidationPolicy.Header.LockPolicyType = VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + 1;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+  ValidationPolicy.Header.LockPolicyType = VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + 1;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectPolicesWithTooManyWildcards (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_300_HASHES_STRING),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_300_HASHES_STRING

+  };

+

+  // 300 Hashes is currently larger than the possible maximum match priority.

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectDuplicatePolicies (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  UT_ASSERT_STATUS_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_ALREADY_STARTED );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+MinAndMaxSizePoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[TEST_POLICY_MAX_SIZE_200+1];

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MAX_SIZE_200+1,

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // With a policy, make sure that sizes outsize the target range fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MAX_SIZE_200+1,

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that sizes outsize the target range fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MIN_SIZE_10-1,

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure a valid variable is still valid.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MIN_SIZE_10+1,

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+AttributeMustPoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      VARIABLE_ATTRIBUTE_NV_BS_RT,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    TEST_POLICY_ATTRIBUTES_NULL,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // With a policy, make sure that no attributes fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    TEST_POLICY_ATTRIBUTES_NULL,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that some -- but not all -- attributes fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that all attributes pass.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS_RT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that all attributes -- plus some -- pass.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+AttributeCantPoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // With a policy, make sure that forbidden attributes fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that a mixture of attributes -- including the forbidden -- fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that attributes without the forbidden pass.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS_RT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+VariablesShouldBeDeletableRegardlessOfSize (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[TEST_POLICY_MAX_SIZE_200+1];

+

+  // Create a policy enforcing a minimum variable size.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Make sure that a normal set would fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MIN_SIZE_10-1,

+                                    DummyData );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_INVALID_PARAMETER );

+

+  // Now make sure that a delete would succeed.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    0,

+                                    NULL );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockNowPoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_NOW

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // With a policy, make sure that writes immediately fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockOnCreatePoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_CREATE

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UINTN       ExpectedDataSize;

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking for.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME), 2 );

+  expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid1, sizeof(mTestGuid1), 2 );

+  ExpectedDataSize = 0;

+  expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, sizeof(ExpectedDataSize), 2 );

+

+  // With a policy, make sure that writes still work, since the variable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a call with an "existing" variable fails.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 10 );                             // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL );           // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockOnStatePoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      20,           // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UINT8       ValidationStateVar;

+  UINTN       ExpectedDataSize;

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking for.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_2_NAME, sizeof(TEST_VAR_2_NAME), 5 );

+  expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid2, sizeof(mTestGuid2), 5 );

+  ExpectedDataSize = 1;

+  expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, sizeof(ExpectedDataSize), 5 );

+

+  // With a policy, make sure that writes still work, since the variable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a state variable that's too large doesn't lock the variable.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 10 );                             // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL );           // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, check a state variable with the wrong value.

+  ValidationStateVar = 0;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, check a state variable with another wrong value.

+  ValidationStateVar = 10;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a call with a correct state variable fails.

+  ValidationStateVar = 20;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockOnStatePoliciesShouldApplyToNamespaces (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      20,           // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UINT8       ValidationStateVar;

+  UINTN       ExpectedDataSize;

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, NULL, TEST_VAR_2_NAME ) );

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+  PolicyCheck = ValidateSetVariable( TEST_VAR_3_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking for.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_2_NAME, sizeof(TEST_VAR_2_NAME), 4 );

+  expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid2, sizeof(mTestGuid2), 4 );

+  ExpectedDataSize = 1;

+  expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, sizeof(ExpectedDataSize), 4 );

+

+  // With a policy, make sure that writes still work, since the variable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_3_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a call with a correct state variable fails.

+  ValidationStateVar = 20;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_3_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockOnStateShouldHandleErrorsGracefully (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      20,           // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Configure the stub to not care about parameters. We're testing errors.

+  expect_any_always( StubGetVariableNull, VariableName );

+  expect_any_always( StubGetVariableNull, VendorGuid );

+  expect_any_always( StubGetVariableNull, DataSize );

+

+  // With a policy, make sure that writes still work, since the variable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Verify that state variables that are the wrong size won't lock the variable.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL );           // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Verify that unexpected errors default to locked.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_UNSUPPORTED );                // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_READY );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+BestMatchPriorityShouldBeObeyed (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wild12Card34Placeholder"),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    L"Wild12Card34Placeholder"

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[70];

+  CHAR16      *PolicyName = (CHAR16*)((UINT8*)&ValidationPolicy + sizeof(VARIABLE_POLICY_ENTRY));

+  UINTN       PolicyNameSize = sizeof(L"Wild12Card34Placeholder");

+  CHAR16      *FourWildcards = L"Wild##Card##Placeholder";

+  CHAR16      *ThreeWildcards = L"Wild##Card#4Placeholder";

+  CHAR16      *TwoWildcards = L"Wild##Card34Placeholder";

+  CHAR16      *OneWildcard = L"Wild#2Card34Placeholder";

+  CHAR16      *NoWildcards = L"Wild12Card34Placeholder";

+

+  // Create all of the policies from least restrictive to most restrictive.

+  // NoWildcards should be the most restrictive.

+  ValidationPolicy.Header.MaxSize = 60;

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.OffsetToName;

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.Size += (UINT16)PolicyNameSize;

+  ValidationPolicy.Header.MaxSize = 50;

+  CopyMem( PolicyName, FourWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize = 40;

+  CopyMem( PolicyName, ThreeWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize = 30;

+  CopyMem( PolicyName, TwoWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize = 20;

+  CopyMem( PolicyName, OneWildcard, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize = 10;

+  CopyMem( PolicyName, NoWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Verify that variables only matching the namespace have the most flexible policy.

+  PolicyCheck = ValidateSetVariable( L"ArbitraryName",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     65,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"ArbitraryName",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     55,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Verify that variables matching increasing characters get increasing policy restrictions.

+  PolicyCheck = ValidateSetVariable( L"Wild77Card77Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     55,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild77Card77Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     45,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck = ValidateSetVariable( L"Wild77Card74Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     45,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild77Card74Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     35,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck = ValidateSetVariable( L"Wild77Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     35,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild77Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     25,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck = ValidateSetVariable( L"Wild72Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     25,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild72Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     15,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck = ValidateSetVariable( L"Wild12Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     15,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild12Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     5,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+

+///=== POLICY UTILITY SUITE ===================================================

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToLockInterface (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  // Make sure it's not already locked.

+  UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );

+  // Lock it.

+  UT_ASSERT_NOT_EFI_ERROR( LockVariablePolicy() );

+  // Verify that it's locked.

+  UT_ASSERT_TRUE( IsVariablePolicyInterfaceLocked() );

+

+  // Verify that all state-changing commands fail.

+  UT_ASSERT_TRUE( EFI_ERROR( LockVariablePolicy() ) );

+  UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );

+  UT_ASSERT_TRUE( EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToDisablePolicyEnforcement (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[TEST_POLICY_MIN_SIZE_10-1];

+

+  // Make sure that the policy enforcement is currently enabled.

+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Add a policy before it's disabled.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+  // Make sure that the policy enforcement is currently disabled.

+  UT_ASSERT_FALSE( IsVariablePolicyEnabled() );

+

+  // Check to make sure that a policy violation still passes.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldNotBeAbleToDisablePoliciesTwice (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  // Make sure that the policy enforcement is currently enabled.

+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+  // Make sure that the policy enforcement is currently disabled.

+  UT_ASSERT_FALSE( IsVariablePolicyEnabled() );

+  // Try to disable again and verify failure.

+  UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToAddNewPoliciesAfterDisabled (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+

+  // Make sure that the policy enforcement is currently enabled.

+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+

+  // Make sure that new policy creation still works, it just won't be enforced.

+  PolicyCheck = RegisterVariablePolicy( &TestPolicy.Header );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToLockAfterDisabled (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  // Make sure that the policy enforcement is currently enabled.

+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+

+  // Make sure that we can lock in this state.

+  UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );

+  UT_ASSERT_NOT_EFI_ERROR( LockVariablePolicy() );

+  UT_ASSERT_TRUE( IsVariablePolicyInterfaceLocked() );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToDumpThePolicyTable (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT32      DumpSize;

+  UINT32      BufferSize;

+  VOID        *DumpBuffer;

+

+  // For good measure, test some parameter validation.

+  UT_ASSERT_STATUS_EQUAL( DumpVariablePolicy( NULL, NULL ), EFI_INVALID_PARAMETER );

+  DumpSize = 10;

+  UT_ASSERT_STATUS_EQUAL( DumpVariablePolicy( NULL, &DumpSize ), EFI_INVALID_PARAMETER );

+

+  // Now for the actual test case.

+

+  // Allocate a buffer to hold the output.

+  BufferSize = sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME);

+  DumpBuffer = AllocatePool( BufferSize );

+  UT_ASSERT_NOT_EQUAL( DumpBuffer, NULL );

+

+  // Verify that the current table size is 0.

+  DumpSize = BufferSize;

+  UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );

+  UT_ASSERT_EQUAL( DumpSize, 0 );

+

+  // Now, set a new policy.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );

+

+  // Make sure that the new return is non-zero and fails as expected.

+  DumpSize = 0;

+  PolicyCheck = DumpVariablePolicy( NULL, &DumpSize );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );

+  UT_ASSERT_EQUAL( DumpSize, BufferSize );

+

+  // Now verify that we can fetch the dump.

+  DumpSize = BufferSize;

+  UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );

+  UT_ASSERT_EQUAL( DumpSize, BufferSize );

+  UT_ASSERT_MEM_EQUAL( &TestPolicy, DumpBuffer, BufferSize );

+

+  // Always put away your toys.

+  FreePool( DumpBuffer );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToDumpThePolicyTableAfterDisabled (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy2 = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_2_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_2,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_2_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT32      DumpSize;

+  VOID        *DumpBuffer;

+

+  DumpBuffer = NULL;

+  DumpSize = 0;

+

+  // Register a new policy.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );

+  // Make sure that we can dump the policy.

+  PolicyCheck = DumpVariablePolicy( DumpBuffer, &DumpSize );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );

+  DumpBuffer = AllocatePool( DumpSize );

+  UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );

+  UT_ASSERT_MEM_EQUAL( DumpBuffer, &TestPolicy, DumpSize );

+

+  // Clean up from this step.

+  FreePool( DumpBuffer );

+  DumpBuffer = NULL;

+  DumpSize = 0;

+

+  // Now disable the engine.

+  DisableVariablePolicy();

+

+  // Now register a new policy and make sure that both can be dumped.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy2.Header ) );

+  // Make sure that we can dump the policy.

+  PolicyCheck = DumpVariablePolicy( DumpBuffer, &DumpSize );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );

+  DumpBuffer = AllocatePool( DumpSize );

+  UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );

+

+  // Finally, make sure that both policies are in the dump.

+  UT_ASSERT_MEM_EQUAL( DumpBuffer, &TestPolicy, TestPolicy.Header.Size );

+  UT_ASSERT_MEM_EQUAL( (UINT8*)DumpBuffer + TestPolicy.Header.Size,

+                        &TestPolicy2,

+                        TestPolicy2.Header.Size );

+

+  // Always put away your toys.

+  FreePool( DumpBuffer );

+

+  return UNIT_TEST_PASSED;

+}

+

+

+///=== TEST ENGINE ================================================================================

+

+/**

+  SampleUnitTestApp

+

+  @param[in] ImageHandle  The firmware allocated handle for the EFI image.

+  @param[in] SystemTable  A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS     The entry point executed successfully.

+  @retval other           Some error occured when executing this entry point.

+

+**/

+int

+main (

+  )

+{

+  EFI_STATUS                  Status;

+  UNIT_TEST_FRAMEWORK_HANDLE  Framework = NULL;

+  UNIT_TEST_SUITE_HANDLE      ArchTests;

+  UNIT_TEST_SUITE_HANDLE      PolicyTests;

+  UNIT_TEST_SUITE_HANDLE      UtilityTests;

+#ifdef INTERNAL_UNIT_TEST

+  UNIT_TEST_SUITE_HANDLE      InternalTests;

+#endif // INTERNAL_UNIT_TEST

+

+  DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION ));

+

+  //

+  // Start setting up the test framework for running the tests.

+  //

+  Status = InitUnitTestFramework( &Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));

+    goto EXIT;

+  }

+

+

+  //

+  // Add all test suites and tests.

+  //

+  Status = CreateUnitTestSuite( &ArchTests, Framework, "Variable Policy Architectural Tests", "VarPolicy.Arch", NULL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ArchTests\n"));

+    Status = EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( ArchTests,

+                "Deinitialization should fail if not previously initialized", "VarPolicy.Arch.OnlyDeinit",

+                ShouldFailDeinitWithoutInit, NULL, NULL, NULL );

+  AddTestCase( ArchTests,

+                "Initialization followed by deinitialization should succeed", "VarPolicy.Arch.InitDeinit",

+                ShouldBeAbleToInitAndDeinitTheLibrary, NULL, NULL, NULL );

+  AddTestCase( ArchTests,

+                "The initialization function fail if called twice without a deinit", "VarPolicy.Arch.InitTwice",

+                ShouldNotBeAbleToInitializeTheLibraryTwice, NULL, LibCleanup, NULL );

+  AddTestCase( ArchTests,

+                "API functions should be unavailable until library is initialized", "VarPolicy.Arch.UninitApiOff",

+                ApiCommandsShouldNotRespondIfLibIsUninitialized, NULL, LibCleanup, NULL );

+

+#ifdef INTERNAL_UNIT_TEST

+  Status = CreateUnitTestSuite( &InternalTests, Framework, "Variable Policy Internal Tests", "VarPolicy.Internal", NULL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for InternalTests\n"));

+    Status = EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( InternalTests,

+                "Policy matching should use name and GUID", "VarPolicy.Internal.NameGuid",

+                PoliciesShouldMatchByNameAndGuid, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+                "# sign wildcards should match digits", "VarPolicy.Internal.WildDigits",

+                WildcardPoliciesShouldMatchDigits, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+                "Digit wildcards should check edge cases", "VarPolicy.Internal.WildDigitsAdvanced",

+                WildcardPoliciesShouldMatchDigitsAdvanced, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+                "Empty names should match an entire namespace", "VarPolicy.Internal.WildNamespace",

+                WildcardPoliciesShouldMatchNamespaces, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+                "Match priority should weight correctly based on wildcards", "VarPolicy.Internal.Priorities",

+                MatchPrioritiesShouldFollowRules, LibInitMocked, LibCleanup, NULL );

+#endif // INTERNAL_UNIT_TEST

+

+  Status = CreateUnitTestSuite( &PolicyTests, Framework, "Variable Policy Manipulation Tests", "VarPolicy.Policy", NULL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for PolicyTests\n"));

+    Status = EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( PolicyTests,

+                "RegisterShouldAllowNamespaceWildcards", "VarPolicy.Policy.AllowNamespace",

+                RegisterShouldAllowNamespaceWildcards, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldAllowStateVarsForNamespaces", "VarPolicy.Policy.AllowStateNamespace",

+                RegisterShouldAllowStateVarsForNamespaces, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectNullPointers", "VarPolicy.Policy.NullPointers",

+                RegisterShouldRejectNullPointers, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectBadRevisions", "VarPolicy.Policy.BadRevisions",

+                RegisterShouldRejectBadRevisions, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectBadSizes", "VarPolicy.Policy.BadSizes",

+                RegisterShouldRejectBadSizes, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectBadOffsets", "VarPolicy.Policy.BadOffsets",

+                RegisterShouldRejectBadOffsets, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectMissingStateStrings", "VarPolicy.Policy.MissingStateString",

+                RegisterShouldRejectMissingStateStrings, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectStringsMissingNull", "VarPolicy.Policy.MissingNull",

+                RegisterShouldRejectStringsMissingNull, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectMalformedStrings", "VarPolicy.Policy.MalformedStrings",

+                RegisterShouldRejectMalformedStrings, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectUnpackedPolicies", "VarPolicy.Policy.PolicyPacking",

+                RegisterShouldRejectUnpackedPolicies, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectInvalidNameCharacters", "VarPolicy.Policy.InvalidCharacters",

+                RegisterShouldRejectInvalidNameCharacters, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectBadPolicyConstraints", "VarPolicy.Policy.BadConstraints",

+                RegisterShouldRejectBadPolicyConstraints, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectUnknownLockPolicies", "VarPolicy.Policy.BadLocks",

+                RegisterShouldRejectUnknownLockPolicies, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectPolicesWithTooManyWildcards", "VarPolicy.Policy.TooManyWildcards",

+                RegisterShouldRejectPolicesWithTooManyWildcards, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectDuplicatePolicies", "VarPolicy.Policy.DuplicatePolicies",

+                RegisterShouldRejectDuplicatePolicies, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "Variables that exceed min or max sizes should be rejected", "VarPolicy.Policy.MinMax",

+                MinAndMaxSizePoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "AttributeMustPoliciesShouldBeHonored", "VarPolicy.Policy.AttrMust",

+                AttributeMustPoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "AttributeCantPoliciesShouldBeHonored", "VarPolicy.Policy.AttrCant",

+                AttributeCantPoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "VariablesShouldBeDeletableRegardlessOfSize", "VarPolicy.Policy.DeleteIgnoreSize",

+                VariablesShouldBeDeletableRegardlessOfSize, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockNowPoliciesShouldBeHonored", "VarPolicy.Policy.VARIABLE_POLICY_TYPE_LOCK_NOW",

+                LockNowPoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockOnCreatePoliciesShouldBeHonored", "VarPolicy.Policy.VARIABLE_POLICY_TYPE_LOCK_ON_CREATE",

+                LockOnCreatePoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockOnStatePoliciesShouldBeHonored", "VarPolicy.Policy.LockState",

+                LockOnStatePoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockOnStatePoliciesShouldApplyToNamespaces", "VarPolicy.Policy.NamespaceLockState",

+                LockOnStatePoliciesShouldApplyToNamespaces, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockOnStateShouldHandleErrorsGracefully", "VarPolicy.Policy.LockStateErrors",

+                LockOnStateShouldHandleErrorsGracefully, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "BestMatchPriorityShouldBeObeyed", "VarPolicy.Policy.BestMatch",

+                BestMatchPriorityShouldBeObeyed, LibInitMocked, LibCleanup, NULL );

+

+  Status = CreateUnitTestSuite( &UtilityTests, Framework, "Variable Policy Utility Tests", "VarPolicy.Utility", NULL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for UtilityTests\n"));

+    Status = EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( UtilityTests,

+                "API commands that change state should not respond after interface is locked", "VarPolicy.Utility.InterfaceLock",

+                ShouldBeAbleToLockInterface, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "All policies should pass once enforcement is disabled", "VarPolicy.Utility.DisableEnforcement",

+                ShouldBeAbleToDisablePolicyEnforcement, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "Disabling enforcement twice should produce an error", "VarPolicy.Utility.DisableEnforcementTwice",

+                ShouldNotBeAbleToDisablePoliciesTwice, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "ShouldBeAbleToAddNewPoliciesAfterDisabled", "VarPolicy.Utility.AddAfterDisable",

+                ShouldBeAbleToAddNewPoliciesAfterDisabled, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "ShouldBeAbleToLockAfterDisabled", "VarPolicy.Utility.LockAfterDisable",

+                ShouldBeAbleToLockAfterDisabled, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "Should be able to dump the policy table", "VarPolicy.Utility.DumpTable",

+                ShouldBeAbleToDumpThePolicyTable, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "ShouldBeAbleToDumpThePolicyTableAfterDisabled", "VarPolicy.Utility.DumpTableAfterDisable",

+                ShouldBeAbleToDumpThePolicyTableAfterDisabled, LibInitMocked, LibCleanup, NULL );

+

+

+  //

+  // Execute the tests.

+  //

+  Status = RunAllTestSuites( Framework );

+

+EXIT:

+  if (Framework != NULL)

+  {

+    FreeUnitTestFramework( Framework );

+  }

+

+  return Status;

+}

diff --git a/MdeModulePkg/Include/Library/VariablePolicyLib.h b/MdeModulePkg/Include/Library/VariablePolicyLib.h
new file mode 100644
index 000000000000..efd1840112ec
--- /dev/null
+++ b/MdeModulePkg/Include/Library/VariablePolicyLib.h
@@ -0,0 +1,207 @@
+/** @file -- VariablePolicyLib.h

+Business logic for Variable Policy enforcement.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#ifndef _VARIABLE_POLICY_LIB_H_

+#define _VARIABLE_POLICY_LIB_H_

+

+#include <Protocol/VariablePolicy.h>

+

+/**

+  This API function validates and registers a new policy with

+  the policy enforcement engine.

+

+  @param[in]  NewPolicy     Pointer to the incoming policy structure.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally inconsistent.

+  @retval     EFI_ALREADY_STARTED     An identical matching policy already exists.

+  @retval     EFI_WRITE_PROTECTED     The interface has been locked until the next reboot.

+  @retval     EFI_UNSUPPORTED         Policy enforcement has been disabled. No reason to add more policies.

+  @retval     EFI_ABORTED             A calculation error has prevented this function from completing.

+  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any more policies.

+  @retval     EFI_NOT_READY           Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+RegisterVariablePolicy (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  );

+

+

+/**

+  This API function checks to see whether the parameters to SetVariable would

+  be allowed according to the current variable policies.

+

+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.

+  @param[in]  Attributes         Same as EFI_SET_VARIABLE.

+  @param[in]  DataSize           Same as EFI_SET_VARIABLE.

+  @param[in]  Data               Same as EFI_SET_VARIABLE.

+

+  @retval     EFI_SUCCESS             A matching policy allows this update.

+  @retval     EFI_SUCCESS             There are currently no policies that restrict this update.

+  @retval     EFI_SUCCESS             The protections have been disable until the next reboot.

+  @retval     EFI_WRITE_PROTECTED     Variable is currently locked.

+  @retval     EFI_INVALID_PARAMETER   Attributes or size are invalid.

+  @retval     EFI_ABORTED             A lock policy exists, but an error prevented evaluation.

+  @retval     EFI_NOT_READY           Library has not been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+ValidateSetVariable (

+  IN  CHAR16                       *VariableName,

+  IN  EFI_GUID                     *VendorGuid,

+  IN  UINT32                       Attributes,

+  IN  UINTN                        DataSize,

+  IN  VOID                         *Data

+  );

+

+

+/**

+  This API function disables the variable policy enforcement. If it's

+  already been called once, will return EFI_ALREADY_STARTED.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.

+  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.

+  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform PCD.

+  @retval     EFI_NOT_READY   Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DisableVariablePolicy (

+  VOID

+  );

+

+

+/**

+  This API function will dump the entire contents of the variable policy table.

+

+  Similar to GetVariable, the first call can be made with a 0 size and it will return

+  the size of the buffer required to hold the entire table.

+

+  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size is 0.

+  @param[in,out]  Size    On input, the size of the output buffer. On output, the size

+                          of the data returned.

+

+  @retval     EFI_SUCCESS             Policy data is in the output buffer and Size has been updated.

+  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and Policy is NULL.

+  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. Size updated with required size.

+  @retval     EFI_NOT_READY           Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DumpVariablePolicy (

+  OUT     UINT8         *Policy,

+  IN OUT  UINT32        *Size

+  );

+

+

+/**

+  This API function returns whether or not the policy engine is

+  currently being enforced.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE         Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyEnabled (

+  VOID

+  );

+

+

+/**

+  This API function locks the interface so that no more policy updates

+  can be performed or changes made to the enforcement until the next boot.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY   Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+LockVariablePolicy (

+  VOID

+  );

+

+

+/**

+  This API function returns whether or not the policy interface is locked

+  for the remainder of the boot.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE         Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyInterfaceLocked (

+  VOID

+  );

+

+

+/**

+  This helper function initializes the library and sets

+  up any required internal structures or handlers.

+

+  Also registers the internal pointer for the GetVariable helper.

+

+  @param[in]  GetVariableHelper A function pointer matching the EFI_GET_VARIABLE prototype that will be used to

+                  check policy criteria that involve the existence of other variables.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   The initialize function has been called more than once without a call to

+                                    deinitialize.

+

+**/

+EFI_STATUS

+EFIAPI

+InitVariablePolicyLib (

+  IN  EFI_GET_VARIABLE    GetVariableHelper

+  );

+

+

+/**

+  This helper function returns whether or not the library is currently initialized.

+

+  @retval     TRUE

+  @retval     FALSE

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyLibInitialized (

+  VOID

+  );

+

+

+/**

+  This helper function tears down  the library.

+

+  Should generally only be used for test harnesses.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY     Deinitialize was called without first calling initialize.

+

+**/

+EFI_STATUS

+EFIAPI

+DeinitVariablePolicyLib (

+  VOID

+  );

+

+

+#endif // _VARIABLE_POLICY_LIB_H_

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
new file mode 100644
index 000000000000..f4a879d5382f
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
@@ -0,0 +1,44 @@
+## @file VariablePolicyLib.inf

+# Business logic for Variable Policy enforcement.

+#

+##

+# Copyright (c) Microsoft Corporation.

+# SPDX-License-Identifier: BSD-2-Clause-Patent

+##

+

+

+[Defines]

+  INF_VERSION         = 0x00010017

+  BASE_NAME           = VariablePolicyLib

+  FILE_GUID           = E9ECD342-159A-4F24-9FDF-65724027C594

+  VERSION_STRING      = 1.0

+  MODULE_TYPE         = DXE_DRIVER

+  LIBRARY_CLASS       = VariablePolicyLib|DXE_DRIVER DXE_SMM_DRIVER MM_STANDALONE

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = ANY

+#

+

+

+[Sources]

+  VariablePolicyLib.c

+  VariablePolicyExtraInitNull.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+

+[LibraryClasses]

+  DebugLib

+  BaseMemoryLib

+  MemoryAllocationLib

+  SafeIntLib

+  PcdLib

+

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable     ## CONSUMES

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni
new file mode 100644
index 000000000000..2227ec427828
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni
@@ -0,0 +1,12 @@
+// /** @file

+// VariablePolicyLib.uni

+//

+// Copyright (c) Microsoft Corporation.

+// SPDX-License-Identifier: BSD-2-Clause-Patent

+//

+// **/

+

+

+#string STR_MODULE_ABSTRACT             #language en-US "Library containing the business logic for the VariablePolicy engine"

+

+#string STR_MODULE_DESCRIPTION          #language en-US "Library containing the business logic for the VariablePolicy engine"

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
new file mode 100644
index 000000000000..8b8365741864
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
@@ -0,0 +1,51 @@
+## @file VariablePolicyLibRuntimeDxe.inf

+# Business logic for Variable Policy enforcement.

+# This instance is specifically for RuntimeDxe and contains

+# extra routines to register for VirtualAddressChangeEvents.

+#

+# Copyright (c) Microsoft Corporation.

+# SPDX-License-Identifier: BSD-2-Clause-Patent

+##

+

+

+[Defines]

+  INF_VERSION         = 0x00010017

+  BASE_NAME           = VariablePolicyLibRuntimeDxe

+  FILE_GUID           = 205F7F0E-8EAC-4914-8390-1B90DD7E2A27

+  VERSION_STRING      = 1.0

+  MODULE_TYPE         = DXE_RUNTIME_DRIVER

+  LIBRARY_CLASS       = VariablePolicyLib|DXE_RUNTIME_DRIVER

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = ANY

+#

+

+

+[Sources]

+  VariablePolicyLib.c

+  VariablePolicyExtraInitRuntimeDxe.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+

+[LibraryClasses]

+  DebugLib

+  BaseMemoryLib

+  MemoryAllocationLib

+  SafeIntLib

+  UefiBootServicesTableLib

+  UefiRuntimeServicesTableLib

+  PcdLib

+

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable     ## CONSUMES

+

+

+[Guids]

+  gEfiEventVirtualAddressChangeGuid

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf
new file mode 100644
index 000000000000..ccc04bb600d6
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf
@@ -0,0 +1,40 @@
+## @file VariablePolicyUnitTest.inf

+# UnitTest for...

+# Business logic for Variable Policy enforcement.

+#

+# Copyright (c) Microsoft Corporation.

+# SPDX-License-Identifier: BSD-2-Clause-Patent

+##

+

+

+[Defines]

+  INF_VERSION                    = 0x00010006

+  BASE_NAME                      = VariablePolicyUnitTest

+  FILE_GUID                      = 1200A2E4-D756-418C-9768-528C2D181A98

+  MODULE_TYPE                    = HOST_APPLICATION

+  VERSION_STRING                 = 1.0

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64

+#

+

+[Sources]

+  VariablePolicyUnitTest.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec

+

+

+[LibraryClasses]

+  BaseLib

+  DebugLib

+  UnitTestLib

+  PrintLib

+  VariablePolicyLib

+  BaseMemoryLib

+  MemoryAllocationLib

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 2e0461b87c32..31339741b840 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -31,6 +31,9 @@ [LibraryClasses]
   ##  @libraryclass  Defines a set of methods to reset whole system.

   ResetSystemLib|Include/Library/ResetSystemLib.h

 

+  ##  @libraryclass  Business logic for storing and testing variable policies

+  VariablePolicyLib|Include/Library/VariablePolicyLib.h

+

   ##  @libraryclass  Defines a set of helper functions for resetting the system.

   ResetUtilityLib|Include/Library/ResetUtilityLib.h

 

diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 25aea3e2a481..14b6ed536962 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -3,6 +3,7 @@
 #

 # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>

 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) Microsoft Corporation.

 #

 #    SPDX-License-Identifier: BSD-2-Clause-Patent

 #

@@ -58,6 +59,7 @@ [LibraryClasses]
   DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf

   DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf

   UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf

+  VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf

   #

   # Generic Modules

   #

@@ -129,6 +131,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
   DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf

   CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf

+  VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf

 

 [LibraryClasses.common.SMM_CORE]

   HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf

@@ -306,6 +309,8 @@ [Components]
   MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf

   MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf

   MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf

+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf

+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf

   MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf

   MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf

   MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf

diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
index 72a119db4568..095e613f1be1 100644
--- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
+++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
@@ -19,12 +19,23 @@ [Defines]
 

 !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc

 

+[LibraryClasses]

+  SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf

+

 [Components]

   MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf

 

   #

   # Build MdeModulePkg HOST_APPLICATION Tests

   #

+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf {

+    <LibraryClasses>

+      VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf

+

+    <PcdsFixedAtBuild>

+      gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable|TRUE

+  }

+

   MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf {

     <LibraryClasses>

       ResetSystemLib|MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf

--
2.26.2.windows.1.8.g01c50adf56.20200515075929


-=-=-=-=-=-=
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#60643): https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Fmessage%2F60643&amp;data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&amp;sdata=NShPJaGWqn%2F4krAZWL9B1QUdajPc1uWC3%2BZPd3wcz4E%3D&amp;reserved=0
Mute This Topic: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgroups.io%2Fmt%2F74646432%2F1852292&amp;data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&amp;sdata=aq1LOygDYZbMpRGiibZCOCfMPffZtEFQLR8K4LKmUYk%3D&amp;reserved=0
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Funsub&amp;data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&amp;sdata=CGyCvVr0DX3Z%2F%2BKh43OWSObWZZG58YFT6f94FhOY1LA%3D&amp;reserved=0  [bret.barkelew@...]
-=-=-=-=-=-=


Re: [EXTERNAL] [edk2-devel] [PATCH v5 01/14] MdeModulePkg: Define the VariablePolicy protocol interface

Bret Barkelew
 

Bump. This specific patch needs Reviews.

- Bret


From: devel@edk2.groups.io <devel@edk2.groups.io> on behalf of Bret Barkelew via groups.io <bret@...>
Sent: Tuesday, June 2, 2020 11:57 PM
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Jian J Wang <jian.j.wang@...>; Hao A Wu <hao.a.wu@...>; liming.gao <liming.gao@...>
Subject: [EXTERNAL] [edk2-devel] [PATCH v5 01/14] MdeModulePkg: Define the VariablePolicy protocol interface
 
https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2522&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7Ccaae5a1fbb05498c984f08d807a3dae0%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747624441639&amp;sdata=zb9OOX6YpaObdlezhQmsj5zCSd1JS6ay6DVhGkiJRdU%3D&amp;reserved=0

VariablePolicy is an updated interface to
replace VarLock and VarCheckProtocol.

Add the VariablePolicy protocol interface
header and add to the MdeModulePkg.dec file.

Cc: Jian J Wang <jian.j.wang@...>
Cc: Hao A Wu <hao.a.wu@...>
Cc: Liming Gao <liming.gao@...>
Cc: Bret Barkelew <brbarkel@...>
Signed-off-by: Bret Barkelew <brbarkel@...>
---
 MdeModulePkg/Include/Protocol/VariablePolicy.h | 157 ++++++++++++++++++++
 MdeModulePkg/MdeModulePkg.dec                  |  14 +-
 MdeModulePkg/MdeModulePkg.uni                  |   7 +
 3 files changed, 177 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/Include/Protocol/VariablePolicy.h b/MdeModulePkg/Include/Protocol/VariablePolicy.h
new file mode 100644
index 000000000000..8226c187a77b
--- /dev/null
+++ b/MdeModulePkg/Include/Protocol/VariablePolicy.h
@@ -0,0 +1,157 @@
+/** @file -- VariablePolicy.h

+

+This protocol allows communication with Variable Policy Engine.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+**/

+

+#ifndef __EDKII_VARIABLE_POLICY_PROTOCOL__

+#define __EDKII_VARIABLE_POLICY_PROTOCOL__

+

+#define EDKII_VARIABLE_POLICY_PROTOCOL_REVISION   0x0000000000010000

+

+#define EDKII_VARIABLE_POLICY_PROTOCOL_GUID \

+  { \

+    0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } \

+  }

+

+#define VARIABLE_POLICY_ENTRY_REVISION      0x00010000

+

+#pragma pack(push, 1)

+typedef struct {

+  UINT32   Version;

+  UINT16   Size;

+  UINT16   OffsetToName;

+  EFI_GUID Namespace;

+  UINT32   MinSize;

+  UINT32   MaxSize;

+  UINT32   AttributesMustHave;

+  UINT32   AttributesCantHave;

+  UINT8    LockPolicyType;

+  UINT8    Padding[3];

+  // UINT8    LockPolicy[];     // Variable Length Field

+  // CHAR16   Name[]            // Variable Length Field

+} VARIABLE_POLICY_ENTRY;

+

+#define     VARIABLE_POLICY_NO_MIN_SIZE             0

+#define     VARIABLE_POLICY_NO_MAX_SIZE             MAX_UINT32

+#define     VARIABLE_POLICY_NO_MUST_ATTR            0

+#define     VARIABLE_POLICY_NO_CANT_ATTR            0

+

+#define     VARIABLE_POLICY_TYPE_NO_LOCK            0

+#define     VARIABLE_POLICY_TYPE_LOCK_NOW           1

+#define     VARIABLE_POLICY_TYPE_LOCK_ON_CREATE     2

+#define     VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE  3

+

+typedef struct {

+  EFI_GUID Namespace;

+  UINT8    Value;

+  UINT8    Padding;

+  // CHAR16   Name[];           // Variable Length Field

+} VARIABLE_LOCK_ON_VAR_STATE_POLICY;

+#pragma pack(pop)

+

+/**

+  This API function disables the variable policy enforcement. If it's

+  already been called once, will return EFI_ALREADY_STARTED.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.

+  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.

+  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform PCD.

+

+**/

+typedef

+EFI_STATUS

+(EFIAPI *DISABLE_VARIABLE_POLICY)(

+  VOID

+  );

+

+/**

+  This API function returns whether or not the policy engine is

+  currently being enforced.

+

+  @param[out]   State       Pointer to a return value for whether the policy enforcement

+                            is currently enabled.

+

+  @retval     EFI_SUCCESS

+  @retval     Others        An error has prevented this command from completing.

+

+**/

+typedef

+EFI_STATUS

+(EFIAPI *IS_VARIABLE_POLICY_ENABLED)(

+  OUT BOOLEAN *State

+  );

+

+/**

+  This API function validates and registers a new policy with

+  the policy enforcement engine.

+

+  @param[in]  NewPolicy     Pointer to the incoming policy structure.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally inconsistent.

+  @retval     EFI_ALREADY_STARTED     An identical matching policy already exists.

+  @retval     EFI_WRITE_PROTECTED     The interface has been locked until the next reboot.

+  @retval     EFI_ABORTED             A calculation error has prevented this function from completing.

+  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any more policies.

+

+**/

+typedef

+EFI_STATUS

+(EFIAPI *REGISTER_VARIABLE_POLICY)(

+  IN CONST VARIABLE_POLICY_ENTRY  *PolicyEntry

+  );

+

+/**

+  This API function will dump the entire contents of the variable policy table.

+

+  Similar to GetVariable, the first call can be made with a 0 size and it will return

+  the size of the buffer required to hold the entire table.

+

+  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size is 0.

+  @param[in,out]  Size    On input, the size of the output buffer. On output, the size

+                          of the data returned.

+

+  @retval     EFI_SUCCESS             Policy data is in the output buffer and Size has been updated.

+  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and Policy is NULL.

+  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. Size updated with required size.

+

+**/

+typedef

+EFI_STATUS

+(EFIAPI *DUMP_VARIABLE_POLICY)(

+  IN OUT UINT8  *Policy,

+  IN OUT UINT32 *Size

+  );

+

+/**

+  This API function locks the interface so that no more policy updates

+  can be performed or changes made to the enforcement until the next boot.

+

+  @retval     EFI_SUCCESS

+  @retval     Others        An error has prevented this command from completing.

+

+**/

+typedef

+EFI_STATUS

+(EFIAPI *LOCK_VARIABLE_POLICY)(

+  VOID

+  );

+

+typedef struct {

+  UINT64                     Revision;

+  DISABLE_VARIABLE_POLICY    DisableVariablePolicy;

+  IS_VARIABLE_POLICY_ENABLED IsVariablePolicyEnabled;

+  REGISTER_VARIABLE_POLICY   RegisterVariablePolicy;

+  DUMP_VARIABLE_POLICY       DumpVariablePolicy;

+  LOCK_VARIABLE_POLICY       LockVariablePolicy;

+} _EDKII_VARIABLE_POLICY_PROTOCOL;

+

+typedef _EDKII_VARIABLE_POLICY_PROTOCOL EDKII_VARIABLE_POLICY_PROTOCOL;

+

+extern EFI_GUID gEdkiiVariablePolicyProtocolGuid;

+

+#endif

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 4f44af694862..2e0461b87c32 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -8,7 +8,7 @@
 # Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>

 # (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>

 # Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>

-# Copyright (c) 2016, Microsoft Corporation<BR>

+# Copyright (c) Microsoft Corporation.<BR>

 # SPDX-License-Identifier: BSD-2-Clause-Patent

 #

 ##

@@ -624,6 +624,9 @@ [Protocols]
 #   0x80000006 | Incorrect error code provided.

 #

 

+  ## Include/Protocol/VariablePolicy.h

+  gEdkiiVariablePolicyProtocolGuid = { 0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } }

+

 [PcdsFeatureFlag]

   ## Indicates if the platform can support update capsule across a system reset.<BR><BR>

   #   TRUE  - Supports update capsule across a system reset.<BR>

@@ -1129,6 +1132,15 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
   # @Prompt Variable storage size.

   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x10000|UINT32|0x30000005

 

+  ## Toggle for whether the VariablePolicy engine should allow disabling.

+  # The engine is enabled at power-on, but the interface allows the platform to

+  # disable enforcement for servicing flexibility. If this PCD is disabled, it will block the ability to

+  # disable the enforcement and VariablePolicy enforcement will always be ON.

+  #   TRUE - VariablePolicy can be disabled by request through the interface (until interface is locked)

+  #   FALSE - VariablePolicy interface will not accept requests to disable and is ALWAYS ON

+  # @Prompt Allow VariablePolicy enforcement to be disabled.

+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable|FALSE|BOOLEAN|0x30000020

+

   ## FFS filename to find the ACPI tables.

   # @Prompt FFS name of ACPI tables storage.

   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile|{ 0x25, 0x4e, 0x37, 0x7e, 0x01, 0x8e, 0xee, 0x4f, 0x87, 0xf2, 0x39, 0xc, 0x23, 0xc6, 0x6, 0xcd }|VOID*|0x30000016

diff --git a/MdeModulePkg/MdeModulePkg.uni b/MdeModulePkg/MdeModulePkg.uni
index 2007e0596c4f..b64e7f351cda 100644
--- a/MdeModulePkg/MdeModulePkg.uni
+++ b/MdeModulePkg/MdeModulePkg.uni
@@ -129,6 +129,13 @@
 

 #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdVariableStoreSize_HELP  #language en-US "The size of volatile buffer. This buffer is used to store VOLATILE attribute variables."

 

+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAllowVariablePolicyEnforcementDisable_PROMPT  #language en-US "Allow VariablePolicy enforcement to be disabled."

+

+#string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAllowVariablePolicyEnforcementDisable_HELP  #language en-US "If this PCD is disabled, it will block the ability to<BR>\n"

+                                                                                                          "disable the enforcement and VariablePolicy enforcement will always be ON.<BR>\n"

+                                                                                                          "TRUE - VariablePolicy can be disabled by request through the interface (until interface is locked)<BR>\n"

+                                                                                                          "FALSE - VariablePolicy interface will not accept requests to disable and is ALWAYS ON<BR>\n"

+

 #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiTableStorageFile_PROMPT  #language en-US "FFS name of ACPI tables storage"

 

 #string STR_gEfiMdeModulePkgTokenSpaceGuid_PcdAcpiTableStorageFile_HELP  #language en-US "FFS filename to find the ACPI tables."

--
2.26.2.windows.1.8.g01c50adf56.20200515075929


-=-=-=-=-=-=
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#60644): https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Fmessage%2F60644&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7Ccaae5a1fbb05498c984f08d807a3dae0%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747624441639&amp;sdata=ZQFJQe8PJmptFsKmkJCFozLPOxTS47DpJFUnScb0B3M%3D&amp;reserved=0
Mute This Topic: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgroups.io%2Fmt%2F74646433%2F1822150&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7Ccaae5a1fbb05498c984f08d807a3dae0%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747624441639&amp;sdata=xQG6kqTp47BHoWZnM%2BZ0RkY3Wzvxnf1E0YL2YCr8vJc%3D&amp;reserved=0
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Funsub&amp;data=02%7C01%7CBret.Barkelew%40microsoft.com%7Ccaae5a1fbb05498c984f08d807a3dae0%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747624441639&amp;sdata=Z7rwTjYt934NJzkClQX32dISKzS%2FA7SrSaFL%2FKwDPOM%3D&amp;reserved=0  [brbarkel@...]
-=-=-=-=-=-=


Re: [PATCH v4 1/4] MdeModulePkg.dec: Change PCDs for status code.

Wang, Jian J
 

Hi Ming,

I'd suggest to keep the type of FeatureFlag for these two PCDs.
So those platforms, which don't want to use dynamic type, have
no need to update it's dsc file.

Regards,
Jian

-----Original Message-----
From: Tan, Ming <ming.tan@...>
Sent: Wednesday, June 10, 2020 10:57 AM
To: devel@edk2.groups.io
Cc: Wang, Jian J <jian.j.wang@...>; Wu, Hao A <hao.a.wu@...>
Subject: [PATCH v4 1/4] MdeModulePkg.dec: Change PCDs for status code.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2786

In order to support enable/disable report status code through memory
or serial dynamic, change the following PCDs from [PcdsFeatureFlag] to
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]:
PcdStatusCodeUseSerial
PcdStatusCodeUseMemory
The original plaforms can use PcdsFixedAtBuild in .dsc files to save size.

Cc: Jian J Wang <jian.j.wang@...>
Cc: Hao A Wu <hao.a.wu@...>
Signed-off-by: Ming Tan <ming.tan@...>
---
V4: No change for this 1/4 patch, just modify the 2-4/4 patchs.
V3: Split one patch to several patchs, each Pkg has one patch.
V2: Change the new type from [PcdsDynamic] to [PcdsFixedAtBuild,
PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
And set to PcdsFixedAtBuild in the original platform .dsc files.

MdeModulePkg/MdeModulePkg.dec | 26 +++++++++----------
.../Pei/StatusCodeHandlerPei.c | 6 ++---
.../Pei/StatusCodeHandlerPei.inf | 6 ++---
.../RuntimeDxe/StatusCodeHandlerRuntimeDxe.c | 16 ++++++------
.../StatusCodeHandlerRuntimeDxe.inf | 6 ++---
.../Smm/StatusCodeHandlerSmm.c | 10 +++----
.../Smm/StatusCodeHandlerSmm.inf | 6 ++---
7 files changed, 35 insertions(+), 41 deletions(-)

diff --git a/MdeModulePkg/MdeModulePkg.dec
b/MdeModulePkg/MdeModulePkg.dec
index 4f44af694862..843e963ad34b 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -760,19 +760,6 @@ [PcdsFeatureFlag]
# @Prompt Enable PCI bridge IO alignment probe.

gEfiMdeModulePkgTokenSpaceGuid.PcdPciBridgeIoAlignmentProbe|FALSE|BOO
LEAN|0x0001004e

- ## Indicates if StatusCode is reported via Serial port.<BR><BR>
- # TRUE - Reports StatusCode via Serial port.<BR>
- # FALSE - Does not report StatusCode via Serial port.<BR>
- # @Prompt Enable StatusCode via Serial port.
-
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|TRUE|BOOLEAN|
0x00010022
-
- ## Indicates if StatusCode is stored in memory.
- # The memory is boot time memory in PEI Phase and is runtime memory in
DXE Phase.<BR><BR>
- # TRUE - Stores StatusCode in memory.<BR>
- # FALSE - Does not store StatusCode in memory.<BR>
- # @Prompt Enable StatusCode via memory.
-
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE|BOOLEA
N|0x00010023
-
## Indicates if PEI phase StatusCode will be replayed in DXE phase.<BR><BR>
# TRUE - Replays PEI phase StatusCode in DXE phased.<BR>
# FALSE - Does not replay PEI phase StatusCode in DXE phase.<BR>
@@ -2001,6 +1988,19 @@ [PcdsFixedAtBuild, PcdsPatchableInModule,
PcdsDynamic, PcdsDynamicEx]
# @Prompt TCG Platform Firmware Profile revision.

gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision|0|UINT3
2|0x00010077

+ ## Indicates if StatusCode is reported via Serial port.<BR><BR>
+ # TRUE - Reports StatusCode via Serial port.<BR>
+ # FALSE - Does not report StatusCode via Serial port.<BR>
+ # @Prompt Enable StatusCode via Serial port.
+
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|TRUE|BOOLEAN|
0x00010022
+
+ ## Indicates if StatusCode is stored in memory.
+ # The memory is boot time memory in PEI Phase and is runtime memory in
DXE Phase.<BR><BR>
+ # TRUE - Stores StatusCode in memory.<BR>
+ # FALSE - Does not store StatusCode in memory.<BR>
+ # @Prompt Enable StatusCode via memory.
+
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE|BOOLEA
N|0x00010023
+
[PcdsPatchableInModule]
## Specify memory size with page number for PEI code when
# Loading Module at Fixed Address feature is enabled.
diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.c
b/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.c
index 1b07f92f3ce8..9b2ea4ee84d9 100644
--- a/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.c
+++
b/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.c
@@ -2,7 +2,7 @@
Report Status Code Handler PEIM which produces general handlers and hook
them
onto the PEI status code router.

- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -45,13 +45,13 @@ StatusCodeHandlerPeiEntry (
// If enable UseSerial, then initialize serial port.
// if enable UseMemory, then initialize memory status code worker.
//
- if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
Status = SerialPortInitialize();
ASSERT_EFI_ERROR (Status);
Status = RscHandlerPpi->Register (SerialStatusCodeReportWorker);
ASSERT_EFI_ERROR (Status);
}
- if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
Status = MemoryStatusCodeInitializeWorker ();
ASSERT_EFI_ERROR (Status);
Status = RscHandlerPpi->Register (MemoryStatusCodeReportWorker);
diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
b/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
index 8aef9af34a05..64380ddfaccc 100644
---
a/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
+++
b/MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
@@ -53,11 +53,9 @@ [Guids]
[Ppis]
gEfiPeiRscHandlerPpiGuid ## CONSUMES

-[FeaturePcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
-
[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
CONSUMES

gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1|gEfiMdeMod
ulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
SOMETIMES_CONSUMES

[Depex]
diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandl
erRuntimeDxe.c
b/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandl
erRuntimeDxe.c
index 79cc48fa55a4..a8c0fe5b7149 100644
---
a/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandl
erRuntimeDxe.c
+++
b/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandl
erRuntimeDxe.c
@@ -2,7 +2,7 @@
Status Code Handler Driver which produces general handlers and hook them
onto the DXE status code router.

- Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -29,7 +29,7 @@ UnregisterBootTimeHandlers (
IN VOID *Context
)
{
- if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
mRscHandlerProtocol->Unregister (SerialStatusCodeReportWorker);
}
}
@@ -80,14 +80,14 @@ InitializationDispatcherWorker (
// If enable UseSerial, then initialize serial port.
// if enable UseRuntimeMemory, then initialize runtime memory status code
worker.
//
- if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
//
// Call Serial Port Lib API to initialize serial port.
//
Status = SerialPortInitialize ();
ASSERT_EFI_ERROR (Status);
}
- if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
Status = RtMemoryStatusCodeInitializeWorker ();
ASSERT_EFI_ERROR (Status);
}
@@ -115,7 +115,7 @@ InitializationDispatcherWorker (
//
// Dispatch records to devices based on feature flag.
//
- if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
SerialStatusCodeReportWorker (
Record[Index].CodeType,
Record[Index].Value,
@@ -124,7 +124,7 @@ InitializationDispatcherWorker (
NULL
);
}
- if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
RtMemoryStatusCodeReportWorker (
Record[Index].CodeType,
Record[Index].Value,
@@ -171,10 +171,10 @@ StatusCodeHandlerRuntimeDxeEntry (
//
InitializationDispatcherWorker ();

- if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
mRscHandlerProtocol->Register (SerialStatusCodeReportWorker,
TPL_HIGH_LEVEL);
}
- if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
mRscHandlerProtocol->Register (RtMemoryStatusCodeReportWorker,
TPL_HIGH_LEVEL);
}

diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandl
erRuntimeDxe.inf
b/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandl
erRuntimeDxe.inf
index d74c2a55dcaf..faadfd9578fe 100644
---
a/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandl
erRuntimeDxe.inf
+++
b/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandl
erRuntimeDxe.inf
@@ -58,12 +58,10 @@ [Guids]
[Protocols]
gEfiRscHandlerProtocolGuid ## CONSUMES

-[FeaturePcd]
+[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeReplayIn ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
-
-[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize |128|
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
SOMETIMES_CONSUMES

[Depex]
diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.
c
b/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.
c
index f54991ed3f67..20271571ded4 100644
---
a/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.
c
+++
b/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.
c
@@ -2,7 +2,7 @@
Status Code Handler Driver which produces general handlers and hook them
onto the SMM status code router.

- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -28,14 +28,14 @@ InitializationDispatcherWorker (
// If enable UseSerial, then initialize serial port.
// if enable UseRuntimeMemory, then initialize runtime memory status code
worker.
//
- if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
//
// Call Serial Port Lib API to initialize serial port.
//
Status = SerialPortInitialize ();
ASSERT_EFI_ERROR (Status);
}
- if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
Status = MemoryStatusCodeInitializeWorker ();
ASSERT_EFI_ERROR (Status);
}
@@ -73,10 +73,10 @@ StatusCodeHandlerSmmEntry (
//
InitializationDispatcherWorker ();

- if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ if (PcdGetBool (PcdStatusCodeUseSerial)) {
mRscHandlerProtocol->Register (SerialStatusCodeReportWorker);
}
- if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ if (PcdGetBool (PcdStatusCodeUseMemory)) {
mRscHandlerProtocol->Register (MemoryStatusCodeReportWorker);
}

diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.i
nf
b/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.i
nf
index 47d0545f9591..4e24d87e55d1 100644
---
a/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.i
nf
+++
b/MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.i
nf
@@ -53,11 +53,9 @@ [Guids]
[Protocols]
gEfiSmmRscHandlerProtocolGuid ## CONSUMES

-[FeaturePcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
-
[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize |128|
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ##
SOMETIMES_CONSUMES

[Depex]
--
2.24.0.windows.2


Re: [PATCH] OvmfPkg: End timer interrupt later to avoid stack overflow under load

Igor Druzhinin <igor.druzhinin@...>
 

On 16/06/2020 19:42, Laszlo Ersek wrote
If I understand correctly, TimerInterruptHandler()
[OvmfPkg/8254TimerDxe/Timer.c] currently does the following:

- RaiseTPL (TPL_HIGH_LEVEL) --> mask interrupts from being delivered

- mLegacy8259->EndOfInterrupt() --> permit the PIC to generate further
interrupts (= make them pending)

- RestoreTPL() --> unmask interrupts (allow delivery)

RestoreTPL() is always expected to invoke handlers (on its own stack)
that have just been unmasked, so that behavior is not unexpected, in my
opinion.
Yes, this is where I'd like to have a confirmation - opening a window
for uncontrollable number of nested interrupts with a small stack
looks dangerous.

What seems unexpected is the queueing of a huge number of timer
interrupts. I would think a timer interrupt is either pending or not
pending (i.e. if it's already pending, then the next generated interrupt
is coalesced, not queued). While there would still be a window between
the EOI and the unmasking, I don't think it would normally allow for a
*huge* number of queued interrupts (and consequently a stack overflow).
It's not a window between EOI and unmasking but the very fact vCPU is
descheduled for a considerable amount of time that causes backlog of
timer interrupts to build up. This is Xen default behavior and is
configurable (there are several timer modes including coalescing
you mention). That is done for compatibility with some guests basing
time accounting on the number of periodic interrupts they receive.

So I basically see the root of the problem in the interrupts being
queued rather than coalesced. I'm pretty unfamiliar with this x86 area
(= the 8259 PIC in general), but the following wiki article seems to
agree with my suspicion:

https://wiki.osdev.org/8259_PIC#How_does_the_8259_PIC_chip_work.3F

[...] and whether there's an interrupt already pending. If the
channel is unmasked and there's no interrupt pending, the PIC will
raise the interrupt line [...]

Can we say that the interrupt queueing (as opposed to coalescing) is a
Xen issue?
I can admit that the whole issue might be Xen specific if that form
of timer mode is not used in QEMU-KVM. What mode is typical there
then? We might consider switching Xen to a different mode if so, as I believe
those guests are not in support for many years.

(Hmmm... maybe the hypervisor *has* to queue the timer interrupts,
otherwise some of them would simply be lost, and the guest would lose
track of time.)

Either way, I'm not sure what the best approach is. This driver was
moved under OvmfPkg from PcAtChipsetPkg in commit 1a3ffdff82e6
("OvmfPkg: Copy 8254TimerDxe driver from PcAtChipsetPkg", 2019-04-11).
HpetTimerDxe also lives under PcAtChipsetPkg.

So I think I'll have to rely on the expertise of Ray here (CC'd).
Also note that since the issue might be Xen specific we might want to
try to fix it in XenTimer only - I modified 8254Timer due to the
fact Xen is still present in general config (but that should soon
go away).

Also, I recall a recent-ish QEMU commit that seems vaguely related
(i.e., to timer interrupt coalescing -- see 7a3e29b12f5a, "mc146818rtc:
fix timer interrupt reinjection again", 2019-11-19), so I'm CC'ing Paolo
too.
Hmm that looks more like a RTC implementation specific issue.

Some more comments / questions below:


diff --git a/OvmfPkg/8254TimerDxe/Timer.c b/OvmfPkg/8254TimerDxe/Timer.c
index 67e22f5..fd1691b 100644
--- a/OvmfPkg/8254TimerDxe/Timer.c
+++ b/OvmfPkg/8254TimerDxe/Timer.c
@@ -79,8 +79,6 @@ TimerInterruptHandler (

OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);

- mLegacy8259->EndOfInterrupt (mLegacy8259, Efi8259Irq0);
-
if (mTimerNotifyFunction != NULL) {
//
// @bug : This does not handle missed timer interrupts
@@ -89,6 +87,9 @@ TimerInterruptHandler (
}

gBS->RestoreTPL (OriginalTPL);
+
+ DisableInterrupts ();
+ mLegacy8259->EndOfInterrupt (mLegacy8259, Efi8259Irq0);
}
So this briefly (temporarily) unmasks interrupt delivery (between
RestoreTPL() and DisableInterrupts()) while the PIC is still blocked
from generating more, and then unblocks the PIC.

It looks plausible for preventing the unbounded recursion per se, but
why is it safe to leave the function with interrupts disabled? Before
the patch, that didn't use to be the case.
Quickly looking through the code it appears to me the first thing that
caller does after interrupt handler - it clears interrupt flag to make
sure those disabled. So I don't see any assumption that interrupts should
be enabled on exiting. But I might not know about all of the possible
combinations here.

Igor


Re: [PATCH V2 2/2] UefiPayloadPkg/Pci: Use the PCIE Base Addr stored in AcpiBoardInfo HOB

Ni, Ray
 

Maurice,

-----Original Message-----
From: Ma, Maurice <maurice.ma@...>
Sent: Monday, June 8, 2020 11:05 PM
To: Ni, Ray <ray.ni@...>; devel@edk2.groups.io
Cc: Dong, Guo <guo.dong@...>; You, Benjamin <benjamin.you@...>
Subject: RE: [PATCH V2 2/2] UefiPayloadPkg/Pci: Use the PCIE Base Addr stored in AcpiBoardInfo HOB

Hi, Ray,

I noticed in this V2 patch, you removed the following line from the DSC file.
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|$(PCIE_BASE)
It will make the PcdPciExpressBaseAddress become PcdsFixedAtBuild type instead of
PcdsDynamicDefault. Is this your intention ?
Yes. I want all modules in the payload access the PCI configure space in two ways:
1. Through PciRootBridgeIo/PciIo, this calling stack depends on the AcpiBoardInfo HOB because PciSegmentLibSegmentInfo is used.
2. Through PciCf8Lib.

In both ways the PCIE base address are configurable.

But if the concern is about performance impact of using CF8/CFC, I can keep the PciExpressLib access path.


Also this V2 patch forced PcdLib class instance to be BasePciLibCf8. It means all PCI configuration space access will use I/O
port access. We prefer using BasePciSegmentLibPci. I think we should keep the original code for this so that it is
configurable.

Also can we sync up DSC changes into UefiPayloadPkgIa32.dsc as well ?
Sure. I will apply the similar change to Ia32.dsc after I understand how to change the X64.dsc.


Thanks
Maurice
-----Original Message-----
From: Ni, Ray <ray.ni@...>
Sent: Wednesday, June 3, 2020 20:27
To: devel@edk2.groups.io
Cc: Ma, Maurice <maurice.ma@...>; Dong, Guo <guo.dong@...>;
You, Benjamin <benjamin.you@...>
Subject: [PATCH V2 2/2] UefiPayloadPkg/Pci: Use the PCIE Base Addr stored in
AcpiBoardInfo HOB

Today's UefiPayloadPkg always uses 0xE0000000 as the PCIE base address and
ignores the value set in AcpiBoardInfo HOB created by the boot loader. This
makes the payload binary cannot work in environment where the PCIE base
address set by boot loader doesn't equal to 0xE0000000.

The patch enhances UefiPayloadPkg so that the PCIE base address set by boot
loader in the AcpiBoardInfo HOB is used.

Signed-off-by: Ray Ni <ray.ni@...>
Cc: Maurice Ma <maurice.ma@...>
Cc: Guo Dong <guo.dong@...>
Cc: Benjamin You <benjamin.you@...>
---
.../PciSegmentInfoLibAcpiBoardInfo.c | 59 +++++++++++++++++++
.../PciSegmentInfoLibAcpiBoardInfo.inf | 36 +++++++++++
UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc | 16 +----
3 files changed, 98 insertions(+), 13 deletions(-) create mode 100644
UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentInfoLibAc
piBoardInfo.c
create mode 100644
UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentInfoLibAc
piBoardInfo.inf

diff --git
a/UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentInfoLib
AcpiBoardInfo.c
b/UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentInfoLib
AcpiBoardInfo.c
new file mode 100644
index 0000000000..d37c91cc9f
--- /dev/null
+++ b/UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentIn
+++ foLibAcpiBoardInfo.c
@@ -0,0 +1,59 @@
+/** @file+ PCI Segment Information Library that returns one segment
whose+ segment base address is retrieved from AcpiBoardInfo HOB.++
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>+ SPDX-License-
Identifier: BSD-2-Clause-Patent++**/++#include <PiDxe.h>+#include
<Guid/AcpiBoardInfoGuid.h>++#include <Library/HobLib.h>+#include
<Library/PciSegmentInfoLib.h>+#include <Library/DebugLib.h>++STATIC
PCI_SEGMENT_INFO mPciSegment0 = {+ 0, // Segment number+ 0, // To be
fixed later+ 0, // Start bus number+ 255 // End bus number+};++/**+ Return
an array of PCI_SEGMENT_INFO holding the segment information.++ Note: The
returned array/buffer is owned by callee.++ @param Count Return the count
of segments.++ @retval A callee owned array holding the segment
information.+**/+PCI_SEGMENT_INFO *+EFIAPI+GetPciSegmentInfo (+ UINTN
*Count+ )+{+ EFI_HOB_GUID_TYPE *GuidHob;+ ACPI_BOARD_INFO
*AcpiBoardInfo;++ ASSERT (Count != NULL);+ if (Count == NULL) {+ return
NULL;+ }++ if (mPciSegment0.BaseAddress == 0) {+ //+ // Find the acpi
board information guid hob+ //+ GuidHob = GetFirstGuidHob
(&gUefiAcpiBoardInfoGuid);+ ASSERT (GuidHob != NULL);++ AcpiBoardInfo =
(ACPI_BOARD_INFO *) GET_GUID_HOB_DATA (GuidHob);+
mPciSegment0.BaseAddress = AcpiBoardInfo->PcieBaseAddress;+ }+ *Count =
1;+ return &mPciSegment0;+}diff --git
a/UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentInfoLib
AcpiBoardInfo.inf
b/UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentInfoLib
AcpiBoardInfo.inf
new file mode 100644
index 0000000000..ec4dbaaa55
--- /dev/null
+++ b/UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentIn
+++ foLibAcpiBoardInfo.inf
@@ -0,0 +1,36 @@
+## @file+# PCI Segment Information Library that returns one segment
whose+# segment base address is retrieved from AcpiBoardInfo HOB.+#+#
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>+#+# SPDX-
License-Identifier: BSD-2-Clause-Patent+#+#+##++[Defines]+ INF_VERSION
= 0x00010005+ BASE_NAME = PciSegmentInfoLibAcpiBoardInfo+
FILE_GUID = 0EA82AA2-6C36-4FD5-BC90-FFA3ECB5E0CE+
MODULE_TYPE = BASE+ VERSION_STRING = 1.0+
LIBRARY_CLASS = PciSegmentInfoLib | DXE_DRIVER++#+# The
following information is for reference only and not required by the build
tools.+#+# VALID_ARCHITECTURES = IA32 X64 EBC+#++[Sources]+
PciSegmentInfoLibAcpiBoardInfo.c++[Packages]+ MdePkg/MdePkg.dec+
UefiPayloadPkg/UefiPayloadPkg.dec++[LibraryClasses]+ PcdLib+ HobLib+
DebugLibdiff --git a/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc
b/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc
index 0736cd9954..62d680eb79 100644
--- a/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkgIa32X64.dsc
@@ -3,7 +3,7 @@
# # Provides drivers and definitions to create uefi payload for bootloaders. #-#
Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>+#
Copyright (c) 2014 - 2020, Intel Corporation. All rights reserved.<BR> # SPDX-
License-Identifier: BSD-2-Clause-Patent # ##@@ -38,11 +38,6 @@ [Defines]
# DEFINE MAX_LOGICAL_PROCESSORS = 64 - #- # PCI options- #-
DEFINE PCIE_BASE = 0xE0000000- # # Serial port set up #@@ -
122,14 +117,10 @@ [LibraryClasses]
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf-!if $(PCIE_BASE)
== 0 PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf-!else-
PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf-
PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf-!endif-
PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.i
nf+
PciSegmentLib|MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLi
bSegmentInfo.inf+
PciSegmentInfoLib|UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/Pc
iSegmentInfoLibAcpiBoardInfo.inf
PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeC
offGetEntryPointLib.inf
CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCache
MaintenanceLib.inf@@ -288,7 +279,6 @@ [PcdsFixedAtBuild]
gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable|TRUE
gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa,
0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23,
0x31 } -
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|$(PCIE_BASE) !if
$(SOURCE_DEBUG_ENABLE)
gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2--
2.26.2.windows.1


Re: [PATCH 5/5] UefiCpuPkg: Uninstall EFI_SMM_CONFIGURATION_PROTOCOL at end of Dxe.

Zhiguang Liu
 

Hi Laszlo,
Thanks for the comments, I will take the first one.
But I can't find service to unregister protocol notify in EFI_SMM_SYSTEM_TABLE2.
Do you now how the unregister it in SMM driver?

Thanks
Zhiguang

-----Original Message-----
From: Laszlo Ersek <lersek@...>
Sent: Tuesday, June 16, 2020 11:07 PM
To: devel@edk2.groups.io; Liu, Zhiguang <zhiguang.liu@...>
Cc: Dong, Eric <eric.dong@...>; Ni, Ray <ray.ni@...>; Kumar,
Rahul1 <rahul1.kumar@...>
Subject: Re: [edk2-devel] [PATCH 5/5] UefiCpuPkg: Uninstall
EFI_SMM_CONFIGURATION_PROTOCOL at end of Dxe.

On 06/16/20 11:04, Zhiguang Liu wrote:
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2317
To avoid leaking information from SMM, uninstall
EFI_SMM_CONFIGURATION_PROTOCOL at end of Dxe.

Cc: Eric Dong <eric.dong@...>
Cc: Ray Ni <ray.ni@...>
Cc: Laszlo Ersek <lersek@...>
Cc: Rahul Kumar <rahul1.kumar@...>
Signed-off-by: Zhiguang Liu <zhiguang.liu@...>
---
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 37
+++++++++++++++++++++++++++++++++++++
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 1 +
2 files changed, 38 insertions(+)

diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
index db68e1316e..a1b209e125 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
@@ -520,6 +520,33 @@ SmmReadyToLockEventNotify (
return EFI_SUCCESS;
}

+/**
+ SMM End of Dxe event notification handler.
+
+ To avoid leaking information from SMM, uninstall
+ EFI_SMM_CONFIGURATION_PROTOCOL at end of Dxe.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification handler runs successfully.
+ **/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ gBS->UninstallProtocolInterface (
+ gSmmCpuPrivate->SmmCpuHandle,
+ &gEfiSmmConfigurationProtocolGuid, &gSmmCpuPrivate-
SmmConfiguration
+ );
+ return EFI_SUCCESS;
+}
(1) I suggest setting "gSmmCpuPrivate->SmmCpuHandle" to NULL here.

(2) I also suggest de-registering the gEfiSmmEndOfDxeProtocolGuid
notification.

Thanks
Laszlo

+
/**
The module Entry Point of the CPU SMM driver.

@@ -1038,6 +1065,16 @@ PiCpuSmmEntry (
);
ASSERT_EFI_ERROR (Status);

+ //
+ // register SMM End of Dxe notification // Status =
+ gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ SmmEndOfDxeNotify,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
//
// Initialize SMM Profile feature
//
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
index 76b1462996..bb994814d6 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
@@ -105,6 +105,7 @@
gEfiSmmConfigurationProtocolGuid ## PRODUCES
gEfiSmmCpuProtocolGuid ## PRODUCES
gEfiSmmReadyToLockProtocolGuid ## NOTIFY
+ gEfiSmmEndOfDxeProtocolGuid ## NOTIFY
gEfiSmmCpuServiceProtocolGuid ## PRODUCES
gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES
gEfiMmMpProtocolGuid ## PRODUCES


Re: [PATCH 1/5] MdeModulePkg: avoid SMM pointers being leaked by not using CopyMem()

Zhiguang Liu
 

Hi Mike,
This code change is to avoid expose the SMM data and using CopyMem() to copy the whole structure will Copy the "next" filed which contain SMM address.
But the Guid is not private information and I think it is ok to use CopyMem() to copy Guid.
Maybe the title is confusing, I will change the patch title.

Thanks
Zhiguang

-----Original Message-----
From: Kinney, Michael D <michael.d.kinney@...>
Sent: Wednesday, June 17, 2020 6:38 AM
To: devel@edk2.groups.io; Liu, Zhiguang <zhiguang.liu@...>; Kinney,
Michael D <michael.d.kinney@...>
Cc: Zeng, Star <star.zeng@...>; Gao, Liming <liming.gao@...>;
Wang, Jian J <jian.j.wang@...>; Wu, Hao A <hao.a.wu@...>
Subject: RE: [edk2-devel] [PATCH 1/5] MdeModulePkg: avoid SMM pointers
being leaked by not using CopyMem()

Zhiguang,

An implementation of CopyGuid() could use CopyMem().
Does CopyGuid() also need to be avoided?

Mike

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On
Behalf Of Zhiguang Liu
Sent: Tuesday, June 16, 2020 2:05 AM
To: devel@edk2.groups.io
Cc: Zeng, Star <star.zeng@...>; Gao, Liming
<liming.gao@...>; Wang, Jian J
<jian.j.wang@...>; Wu, Hao A <hao.a.wu@...>
Subject: [edk2-devel] [PATCH 1/5] MdeModulePkg: avoid
SMM pointers being leaked by not using CopyMem()

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2002

This commit will update the logic in function
SmmVariableGetStatistics()
so that the pointer fields ('Next' and 'Name') in
structure
VARIABLE_INFO_ENTRY will not be copied into the SMM
communication buffer.

Doing so will prevent SMM pointers address from being
leaked into non-SMM
environment.

Please note that newly introduced internal function
CopyVarInfoEntry()
will not use CopyMem() to copy the whole
VARIABLE_INFO_ENTRY structure and
then zero out the 'Next' and 'Name' fields. This is for
preventing race
conditions where the pointers value might still be read.

Cc: Star Zeng <star.zeng@...>
Cc: Liming Gao <liming.gao@...>
Cc: Jian J Wang <jian.j.wang@...>
Signed-off-by: Hao A Wu <hao.a.wu@...>
Signed-off-by: Zhiguang Liu <zhiguang.liu@...>
---

MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
| 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)

diff --git
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm
.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm
.c
index caca5c3241..74e756bc00 100644
---
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm
.c
+++
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm
.c
@@ -315,6 +315,35 @@ GetFvbCountAndBuffer (
}





+/**

+ Copy only the meaningful fields of the variable
statistics information from

+ source buffer to the destination buffer. Other fields
are filled with zero.

+

+ @param[out] DstInfoEntry A pointer to the buffer
of destination variable

+ information entry.

+ @param[in] SrcInfoEntry A pointer to the buffer
of source variable

+ information entry.

+

+**/

+static

+VOID

+CopyVarInfoEntry (

+ OUT VARIABLE_INFO_ENTRY *DstInfoEntry,

+ IN VARIABLE_INFO_ENTRY *SrcInfoEntry

+ )

+{

+ DstInfoEntry->Next = NULL;

+ DstInfoEntry->Name = NULL;

+

+ CopyGuid (&DstInfoEntry->VendorGuid, &SrcInfoEntry-
VendorGuid);
+ DstInfoEntry->Attributes = SrcInfoEntry->Attributes;

+ DstInfoEntry->ReadCount = SrcInfoEntry->ReadCount;

+ DstInfoEntry->WriteCount = SrcInfoEntry->WriteCount;

+ DstInfoEntry->DeleteCount = SrcInfoEntry-
DeleteCount;
+ DstInfoEntry->CacheCount = SrcInfoEntry->CacheCount;

+ DstInfoEntry->Volatile = SrcInfoEntry->Volatile;

+}

+

/**

Get the variable statistics information from the
information buffer pointed by gVariableInfo.



@@ -377,7 +406,7 @@ SmmVariableGetStatistics (
*InfoSize = StatisticsInfoSize;

return EFI_BUFFER_TOO_SMALL;

}

- CopyMem (InfoEntry, VariableInfo, sizeof
(VARIABLE_INFO_ENTRY));

+ CopyVarInfoEntry (InfoEntry, VariableInfo);

CopyMem (InfoName, VariableInfo->Name, NameSize);

*InfoSize = StatisticsInfoSize;

return EFI_SUCCESS;

@@ -417,7 +446,7 @@ SmmVariableGetStatistics (
return EFI_BUFFER_TOO_SMALL;

}



- CopyMem (InfoEntry, VariableInfo, sizeof
(VARIABLE_INFO_ENTRY));

+ CopyVarInfoEntry (InfoEntry, VariableInfo);

CopyMem (InfoName, VariableInfo->Name, NameSize);

*InfoSize = StatisticsInfoSize;



--
2.25.1.windows.1


-=-=-=-=-=-=
Groups.io Links: You receive all messages sent to this
group.

View/Reply Online (#61324):
https://edk2.groups.io/g/devel/message/61324
Mute This Topic: https://groups.io/mt/74912557/1643496
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub
[michael.d.kinney@...]
-=-=-=-=-=-=


Re: [PATCH 5/5] Platform/Intel/Vlv2TbltDevicePkg: Change PCDs type about status code

Sun, Zailiang
 

Reviewed-by: Zailiang Sun <zailiang.sun@...>

-----Original Message-----
From: Tan, Ming <ming.tan@...>
Sent: Tuesday, June 9, 2020 7:24 PM
To: devel@edk2.groups.io
Cc: Sun, Zailiang <zailiang.sun@...>; Qian, Yi <yi.qian@...>
Subject: [PATCH 5/5] Platform/Intel/Vlv2TbltDevicePkg: Change PCDs type about status code

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2791

Since the type of PcdStatusCodeUseSerial and PcdStatusCodeUseMemory in MdeModulePkg.dec are changed, so change them from PcdsFeatureFlag to PcdsFixedAtBuild in dsc files.

Cc: Zailiang Sun <zailiang.sun@...>
Cc: Yi Qian <yi.qian@...>
Signed-off-by: Ming Tan <ming.tan@...>
---
.../Intel/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc | 14 +++++++-------
.../Intel/Vlv2TbltDevicePkg/PlatformPkgX64.dsc | 14 +++++++-------
2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/Platform/Intel/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc b/Platform/Intel/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc
index 463b952e65..1cb0b9230a 100644
--- a/Platform/Intel/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc
+++ b/Platform/Intel/Vlv2TbltDevicePkg/PlatformPkgIA32.dsc
@@ -1,7 +1,7 @@
#/** @file # Platform description. #-# Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>+# Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR> # # SPDX-License-Identifier: BSD-2-Clause-Patent #@@ -432,12 +432,6 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset|FALSE !endif gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst|FALSE-!if $(TARGET) == RELEASE- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE-!else- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE-!endif- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE !if $(ISA_SERIAL_STATUS_CODE_ENABLE) == TRUE gEfiSerialPortTokenSpaceGuid.PcdStatusCodeUseIsaSerial|TRUE !else@@ -483,6 +477,12 @@
!else gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE !endif+!if $(TARGET) == RELEASE+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE+!else+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE+!endif+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE !if $(TARGET) == RELEASE gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0 gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x3diff --git a/Platform/Intel/Vlv2TbltDevicePkg/PlatformPkgX64.dsc b/Platform/Intel/Vlv2TbltDevicePkg/PlatformPkgX64.dsc
index ee18b45c97..62ff5f5c4d 100644
--- a/Platform/Intel/Vlv2TbltDevicePkg/PlatformPkgX64.dsc
+++ b/Platform/Intel/Vlv2TbltDevicePkg/PlatformPkgX64.dsc
@@ -1,7 +1,7 @@
#/** @file # Platform description. #-# Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>+# Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR> # # SPDX-License-Identifier: BSD-2-Clause-Patent #@@ -434,12 +434,6 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset|FALSE !endif gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst|FALSE-!if $(TARGET) == RELEASE- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE-!else- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE-!endif- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE !if $(ISA_SERIAL_STATUS_CODE_ENABLE) == TRUE gEfiSerialPortTokenSpaceGuid.PcdStatusCodeUseIsaSerial|TRUE !else@@ -485,6 +479,12 @@
!else gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE !endif+!if $(TARGET) == RELEASE+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE+!else+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE+!endif+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE !if $(TARGET) == RELEASE gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0 gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x3--
2.24.0.windows.2


Re: [PATCH 1/1 v2] MdeModulePkg/StatusCodeHandler: do not output \n\r for string data

Wang, Jian J
 

Reviewed-by: Jian J Wang <jian.j.wang@...>

Regards,
Jian

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Tan, Ming
Sent: Monday, June 15, 2020 10:04 AM
To: devel@edk2.groups.io
Subject: [edk2-devel] [PATCH 1/1 v2] MdeModulePkg/StatusCodeHandler: do
not output \n\r for string data

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2787

When output string data through serial port, will not ouput \n\r now.
Caller can output several data in one line, and output \n\r when needed.

Signed-off-by: Ming Tan <ming.tan@...>
---
V2: Make it as a standalone patch.
.../Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c | 2 +-
.../StatusCodeHandler/RuntimeDxe/SerialStatusCodeWorker.c | 2 +-
.../Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)

diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c
b/MdeModulePkg/Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c
index 2455f8b2a908..3aa5642b64fb 100644
---
a/MdeModulePkg/Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c
+++
b/MdeModulePkg/Universal/StatusCodeHandler/Pei/SerialStatusCodeWorker.c
@@ -134,7 +134,7 @@ SerialStatusCodeReportWorker (
CharCount = AsciiSPrint (
Buffer,
sizeof (Buffer),
- "%a\n\r",
+ "%a",
((EFI_STATUS_CODE_STRING_DATA *) Data)->String.Ascii
);
} else {
diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/SerialStatusCode
Worker.c
b/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/SerialStatusCode
Worker.c
index 2dc3ecfff52e..0b98e7ec6315 100644
---
a/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/SerialStatusCode
Worker.c
+++
b/MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/SerialStatusCode
Worker.c
@@ -129,7 +129,7 @@ SerialStatusCodeReportWorker (
CharCount = AsciiSPrint (
Buffer,
sizeof (Buffer),
- "%a\n\r",
+ "%a",
((EFI_STATUS_CODE_STRING_DATA *) Data)->String.Ascii
);
} else {
diff --git
a/MdeModulePkg/Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.
c
b/MdeModulePkg/Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.
c
index c0c907b32f5a..3df0a6712611 100644
---
a/MdeModulePkg/Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.
c
+++
b/MdeModulePkg/Universal/StatusCodeHandler/Smm/SerialStatusCodeWorker.
c
@@ -129,7 +129,7 @@ SerialStatusCodeReportWorker (
CharCount = AsciiSPrint (
Buffer,
sizeof (Buffer),
- "%a\n\r",
+ "%a",
((EFI_STATUS_CODE_STRING_DATA *) Data)->String.Ascii
);
} else {
--
2.24.0.windows.2



Re: [RFC PATCH 1/1] OvmfPkg: Introduce LSI 53C895A SCSI Controller Driver

Gary Lin
 

On Mon, Jun 15, 2020 at 01:27:22PM +0200, Laszlo Ersek wrote:
Hello Gary,
Hi Laszlo,

On 06/12/20 12:04, Gary Lin wrote:
This commit introduces the driver for LSI 53C895A SCSI Controller
which, so that OVMF can access the devices attached to the emulated
"lsi" SCSI controller.

Cc: Jordan Justen <jordan.l.justen@...>
Cc: Laszlo Ersek <lersek@...>
Cc: Ard Biesheuvel <ard.biesheuvel@...>
Signed-off-by: Gary Lin <glin@...>
---
Although lsi is now considered obsolete in QEMU, I wrote this driver
mainly for learning the UEFI SCSI driver and ... FUN! The majority of
the code is actually borrowed from VirtioScsci and MptScsi, and I
mainly focus on LsiScsiPassThru().

If it's fine to add this driver into OvmfPkg, I'll start to split this
patch into smaller pieces to make it easier to review.
(1) Do we have an official deprecation notice for this SCSI controller
in QEMU?

If we do, then (AIUI) the controller will be removed in QEMU in one or
two releases, so this code would become effectively dead in the mid
term. I wouldn't like to review and/or carry code that's soon to be
dead.
I just vaguely remember that virtio-scsi is the new default over lsi and
it's not recommended to use lsi except for the old OS without virtio-scsi
driver.

(2) If there is no official deprecation notice in QEMU, then I agree it
makes sense to include this driver. In that case, I have another
question:

Do you intend this driver for production purposes? I.e., do you expect
users or "layered products" (libvirt, proxmox, openstack, ...) to use
this SCSI controller for some well-defined purpose? (The MPT SCSI and PV
SCSI drivers had a clear product-oriented modivation:

https://edk2.groups.io/g/devel/message/55620
http://mid.mail-archive.com/a96b6b74-c35d-e291-2122-9d77f1d5f89c@oracle.com
)

(2a) If this driver is not meant for a production environment, then
LSI_SCSI_ENABLE should be FALSE by default (and I'll do a lighter
review).

(2b) If the driver is meant for production, then LSI_SCSI_ENABLE should
indeed be TRUE, and I'll have to be more diligent in reviewing this.
I kind of wonder if the any serious use for lsi+ovmf. If the OS is so
old and only supports lsi, seabios probably serves it better. Anyway,
I'll try to gather more information from my colleagues to see if they
got any feedback about lsi from our customers. If not, I'll set
LSI_SCSI_ENABLE to FALSE by default.

For either (2a) or (2b), please do split up the driver into smaller
patches, and please also add yourself to Maintainers.txt as the
designated reviewer of the new driver.
Sure. Will do that.

Thanks,

Gary Lin


Re: [PATCH edk2-platforms v3 3/4] Silicon/Hisilicon/Acpi: Add update sas address feature

Ming Huang
 

在 2020/6/16 22:20, Leif Lindholm 写道:
One remaining question, then this set is ready to go in:

On Tue, Jun 09, 2020 at 21:27:24 +0800, Ming Huang wrote:
The updating sas address feature is similar with apdating mac address.
Modify updating dsdt flow for add this feature.

Signed-off-by: Ming Huang <huangming23@...>
---
Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatform.c | 2 +-
Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf | 1 +
Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.c | 292 +++++++++++++++-----
Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.h | 2 +-
4 files changed, 227 insertions(+), 70 deletions(-)

diff --git a/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatform.c b/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatform.c
index c45a0bb..9cdf710 100644
--- a/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatform.c
+++ b/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatform.c
@@ -46,7 +46,7 @@ UpdateAcpiDsdt (
return;
}

- Status = EthMacInit ();
+ Status = UpdateAcpiDsdtTable ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, " UpdateAcpiDsdtTable Failed, Status = %r\n", Status));
}
diff --git a/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf b/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
index 866ff75..856309a 100644
--- a/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
+++ b/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -46,6 +46,7 @@
gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiAcpiSdtProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gHisiBoardNicProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gHisiSasConfigProtocolGuid

[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol
diff --git a/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.c b/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.c
index cd98506..841c94e 100644
--- a/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.c
+++ b/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.c
@@ -1,7 +1,7 @@
/** @file

Copyright (c) 2014, Applied Micro Curcuit Corporation. All rights reserved.<BR>
- Copyright (c) 2015, Hisilicon Limited. All rights reserved.<BR>
+ Copyright (c) 2015 - 2020, Hisilicon Limited. All rights reserved.<BR>
Copyright (c) 2015, Linaro Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

@@ -23,6 +23,7 @@
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/AcpiSystemDescriptionTable.h>
#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Library/PrintLib.h>
#include <Library/DebugLib.h>
@@ -32,6 +33,7 @@
#include <IndustryStandard/AcpiAml.h>

#include <Protocol/HisiBoardNicProtocol.h>
+#include <Protocol/HisiSasConfig.h>

// Turn on debug message by enabling below define
//#define ACPI_DEBUG
@@ -45,17 +47,27 @@
#define EFI_ACPI_MAX_NUM_TABLES 20
#define DSDT_SIGNATURE 0x54445344

-#define D03_ACPI_ETH_ID "HISI00C2"
-
#define ACPI_ETH_MAC_KEY "local-mac-address"
+#define ACPI_ETH_SAS_KEY "sas-addr"

#define PREFIX_VARIABLE_NAME L"MAC"
#define PREFIX_VARIABLE_NAME_COMPAT L"RGMII_MAC"
-#define MAC_MAX_LEN 30
+#define ADDRESS_MAX_LEN 30
+
+CHAR8 *mHisiAcpiDevId[] = {"HISI00C1","HISI00C2","HISI0162"};
+
+typedef enum {
+ DsdtDeviceUnknown,
+ DsdtDeviceLan,
+ DsdtDeviceSas
+} DSDT_DEVICE_TYPE;

-EFI_STATUS GetEnvMac(
- IN UINTN MacNextID,
- IN OUT UINT8 *MacBuffer)
+STATIC
+EFI_STATUS
+GetEnvMac(
+ IN UINTN MacNextID,
+ IN OUT UINT8 *MacBuffer
+ )
{
EFI_MAC_ADDRESS Mac;
EFI_STATUS Status;
@@ -89,12 +101,121 @@ EFI_STATUS GetEnvMac(
return EFI_SUCCESS;
}

-EFI_STATUS _SearchReplacePackageMACAddress(
+STATIC
+EFI_STATUS
+GetSasAddress (
+ IN UINT8 Index,
+ IN OUT UINT8 *SasAddrBuffer
+ )
+{
+ EFI_STATUS Status;
+ HISI_SAS_CONFIG_PROTOCOL *HisiSasConf;
+
+ if (SasAddrBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->LocateProtocol (&gHisiSasConfigProtocolGuid, NULL, (VOID **)&HisiSasConf);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Locate Sas Config Protocol failed %r\n", Status));
+ SasAddrBuffer[0] = 0x50;
+ SasAddrBuffer[1] = 0x01;
+ SasAddrBuffer[2] = 0x88;
+ SasAddrBuffer[3] = 0x20;
+ SasAddrBuffer[4] = 0x16;
+ SasAddrBuffer[5] = 0x00;
+ SasAddrBuffer[6] = 0x00;
+ SasAddrBuffer[7] = Index;
This is still a sompletely random-looking value being stuffed into the
buffer. What is it?
This is a random value. Maybe it is more appropriate to stuff zero into the
buffer here.

Thanks,
Ming


/
Leif

+ return Status;
+ }
+
+ return HisiSasConf->GetAddr (Index, SasAddrBuffer);
+}
+
+STATIC
+EFI_STATUS
+UpdateAddressInOption (
+ IN EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
+ IN EFI_ACPI_HANDLE ChildHandle,
+ IN UINTN DevNextID,
+ IN DSDT_DEVICE_TYPE FoundDev
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DATA_TYPE DataType;
+ CONST VOID *Buffer;
+ UINTN DataSize;
+ UINTN Count;
+ EFI_ACPI_HANDLE CurrentHandle;
+ UINT8 *AddressBuffer;
+ UINT8 AddressByte;
+
+ AddressByte = 0;
+ AddressBuffer = AllocateZeroPool (ADDRESS_MAX_LEN);
+ if (AddressBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a:%d AllocateZeroPool failed\n", __FILE__, __LINE__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ switch (FoundDev) {
+ case DsdtDeviceLan:
+ //Update the MAC
+ Status = GetEnvMac (DevNextID, AddressBuffer);
+ AddressByte = 6;
+ break;
+ case DsdtDeviceSas:
+ //Update SAS Address.
+ Status = GetSasAddress (DevNextID, AddressBuffer);
+ AddressByte = 8;
+ break;
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+ if (EFI_ERROR (Status)) {
+ FreePool (AddressBuffer);
+ return Status;
+ }
+
+ for (Count = 0; Count < AddressByte; Count++) {
+ Status = AcpiTableProtocol->GetOption (CurrentHandle, 1, &DataType, &Buffer, &DataSize);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (DataType != EFI_ACPI_DATA_TYPE_UINT)
+ break;
+
+ // only need one byte.
+ // FIXME: Assume the CPU is little endian
+ Status = AcpiTableProtocol->SetOption (
+ CurrentHandle,
+ 1,
+ AddressBuffer + Count,
+ sizeof(UINT8));
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = AcpiTableProtocol->GetChild (ChildHandle, &CurrentHandle);
+ if (EFI_ERROR (Status) || CurrentHandle == NULL) {
+ break;
+ }
+ }
+
+ FreePool (AddressBuffer);
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+UpdateAddressInPackage (
IN EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
IN EFI_ACPI_HANDLE ChildHandle,
IN UINTN Level,
IN OUT BOOLEAN *Found,
- IN UINTN MacNextID)
+ IN UINTN DevNextID,
+ IN DSDT_DEVICE_TYPE FoundDev
+ )
{
// ASL template for ethernet driver:
/*
@@ -114,15 +235,18 @@ EFI_STATUS _SearchReplacePackageMACAddress(
CONST UINT8 *Data;
CONST VOID *Buffer;
UINTN DataSize;
- UINTN Count;
EFI_ACPI_HANDLE CurrentHandle;
EFI_ACPI_HANDLE NextHandle;
- UINT8 MACBuffer[MAC_MAX_LEN];
+ EFI_ACPI_HANDLE Level1Handle;

DBG("In Level:%d\n", Level);
+ Level1Handle = NULL;
Status = EFI_SUCCESS;
for (CurrentHandle = NULL; ;) {
Status = AcpiTableProtocol->GetChild(ChildHandle, &CurrentHandle);
+ if (Level == 1) {
+ Level1Handle = CurrentHandle;
+ }
if (Level != 3 && (EFI_ERROR(Status) || CurrentHandle == NULL))
break;

@@ -143,11 +267,14 @@ EFI_STATUS _SearchReplacePackageMACAddress(
DataSize, Data[0], DataSize > 1 ? Data[1] : 0);

Data = Buffer;
- if (DataType != EFI_ACPI_DATA_TYPE_STRING
- || AsciiStrCmp((CHAR8 *) Data, ACPI_ETH_MAC_KEY) != 0)
+ if ((DataType != EFI_ACPI_DATA_TYPE_STRING) ||
+ ((AsciiStrCmp ((CHAR8 *) Data, ACPI_ETH_MAC_KEY) != 0) &&
+ (AsciiStrCmp ((CHAR8 *) Data, ACPI_ETH_SAS_KEY) != 0))) {
+ ChildHandle = Level1Handle;
continue;
+ }

- DBG("_DSD Key Type %d. Found MAC address key\n", DataType);
+ DBG("_DSD Key Type %d. Found address key\n", DataType);

//
// We found the node.
@@ -157,33 +284,7 @@ EFI_STATUS _SearchReplacePackageMACAddress(
}

if (Level == 3 && *Found) {
-
- //Update the MAC
- Status = GetEnvMac(MacNextID, MACBuffer);
- if (EFI_ERROR(Status))
- break;
-
- for (Count = 0; Count < 6; Count++) {
- Status = AcpiTableProtocol->GetOption(CurrentHandle, 1, &DataType, &Buffer, &DataSize);
- if (EFI_ERROR(Status))
- break;
-
- Data = Buffer;
- DBG(" _DSD Child Subnode Store Op Code 0x%02X 0x%02X %02X DataType 0x%X\n",
- DataSize, Data[0], DataSize > 1 ? Data[1] : 0, DataType);
-
- if (DataType != EFI_ACPI_DATA_TYPE_UINT)
- break;
-
- // only need one byte.
- // FIXME: Assume the CPU is little endian
- Status = AcpiTableProtocol->SetOption(CurrentHandle, 1, (VOID *)&MACBuffer[Count], sizeof(UINT8));
- if (EFI_ERROR(Status))
- break;
- Status = AcpiTableProtocol->GetChild(ChildHandle, &CurrentHandle);
- if (EFI_ERROR(Status) || CurrentHandle == NULL)
- break;
- }
+ Status = UpdateAddressInOption (AcpiTableProtocol, ChildHandle, DevNextID, FoundDev);
break;
}

@@ -192,7 +293,13 @@ EFI_STATUS _SearchReplacePackageMACAddress(

//Search next package
AcpiTableProtocol->Open((VOID *) Buffer, &NextHandle);
- Status = _SearchReplacePackageMACAddress(AcpiTableProtocol, NextHandle, Level + 1, Found, MacNextID);
+ Status = UpdateAddressInPackage (
+ AcpiTableProtocol,
+ NextHandle,
+ Level + 1,
+ Found,
+ DevNextID,
+ FoundDev);
AcpiTableProtocol->Close(NextHandle);
if (!EFI_ERROR(Status))
break;
@@ -201,22 +308,28 @@ EFI_STATUS _SearchReplacePackageMACAddress(
return Status;
}

-EFI_STATUS SearchReplacePackageMACAddress(
+STATIC
+EFI_STATUS
+SearchReplacePackageAddress (
IN EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
IN EFI_ACPI_HANDLE ChildHandle,
- IN UINTN MacNextID)
+ IN UINTN DevNextID,
+ IN DSDT_DEVICE_TYPE FoundDev
+ )
{
BOOLEAN Found = FALSE;
UINTN Level = 0;

- return _SearchReplacePackageMACAddress(AcpiTableProtocol, ChildHandle, Level, &Found, MacNextID);
+ return UpdateAddressInPackage (AcpiTableProtocol, ChildHandle, Level,
+ &Found, DevNextID, FoundDev);
}

EFI_STATUS
-GetEthID (
+GetDeviceInfo (
EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
EFI_ACPI_HANDLE ChildHandle,
- UINTN *EthID
+ UINTN *DevID,
+ DSDT_DEVICE_TYPE *FoundDev
)
{
EFI_STATUS Status;
@@ -225,7 +338,7 @@ GetEthID (
CONST VOID *Buffer;
UINTN DataSize;

- // Get NameString ETHx
+ // Get NameString
Status = AcpiTableProtocol->GetOption (ChildHandle, 1, &DataType, &Buffer, &DataSize);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "[%a:%d] Get NameString failed: %r\n", __FUNCTION__, __LINE__, Status));
@@ -236,14 +349,23 @@ GetEthID (
DBG("Size %p Data %02x %02x %02x %02x\n", DataSize, Data[0], Data[1], Data[2], Data[3]);

Data[4] = '\0';
- if (DataSize != 4 ||
- AsciiStrnCmp ("ETH", Data, 3) != 0 ||
- Data[3] > '9' || Data[3] < '0') {
- DEBUG ((EFI_D_ERROR, "[%a:%d] The NameString %a is not ETHn\n", __FUNCTION__, __LINE__, Data));
+ if ((DataSize != 4) ||
+ (Data[3] > '9' || Data[3] < '0')) {
+ DEBUG ((DEBUG_ERROR, "The NameString %a is not ETHn or SASn\n", Data));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (AsciiStrnCmp ("ETH", Data, 3) == 0) {
+ *FoundDev = DsdtDeviceLan;
+ } else if (AsciiStrnCmp ("SAS", Data, 3) == 0) {
+ *FoundDev = DsdtDeviceSas;
+ } else {
+ DEBUG ((DEBUG_ERROR, "[%a:%d] The NameString %a is not ETHn or SASn\n",
+ __FUNCTION__, __LINE__, Data));
return EFI_INVALID_PARAMETER;
}

- *EthID = Data[3] - '0';
+ *DevID = Data[3] - '0';
return EFI_SUCCESS;
}

@@ -257,8 +379,10 @@ EFI_STATUS ProcessDSDTDevice (
CONST VOID *Buffer;
UINTN DataSize;
EFI_ACPI_HANDLE DevHandle;
- INTN Found = 0;
- UINTN MacNextID;
+ DSDT_DEVICE_TYPE FoundDev = DsdtDeviceUnknown;
+ UINTN DevNextID;
+ BOOLEAN HisiAcpiDevNotFound;
+ UINTN Index;

Status = AcpiTableProtocol->GetOption(ChildHandle, 0, &DataType, &Buffer, &DataSize);
if (EFI_ERROR(Status))
@@ -280,7 +404,7 @@ EFI_STATUS ProcessDSDTDevice (
break;

//
- // Search for _HID with Ethernet ID
+ // Search for _HID with Device ID
//
Status = AcpiTableProtocol->GetOption(DevHandle, 0, &DataType, &Buffer, &DataSize);
if (EFI_ERROR(Status))
@@ -312,23 +436,34 @@ EFI_STATUS ProcessDSDTDevice (
DBG("[%a:%d] - _HID = %a\n", __FUNCTION__, __LINE__, Data);

if (EFI_ERROR(Status) ||
- DataType != EFI_ACPI_DATA_TYPE_STRING ||
- (AsciiStrCmp((CHAR8 *) Data, D03_ACPI_ETH_ID) != 0)) {
- AcpiTableProtocol->Close(ValueHandle);
- Found = 0;
+ DataType != EFI_ACPI_DATA_TYPE_STRING) {
+ AcpiTableProtocol->Close (ValueHandle);
+ FoundDev = DsdtDeviceUnknown;
+ continue;
+ }
+
+ HisiAcpiDevNotFound = TRUE;
+ for (Index = 0; Index < ARRAY_SIZE (mHisiAcpiDevId); Index++) {
+ if (AsciiStrCmp ((CHAR8 *)Data, mHisiAcpiDevId[Index]) == 0) {
+ HisiAcpiDevNotFound = FALSE;
+ break;
+ }
+ }
+ if (HisiAcpiDevNotFound) {
+ AcpiTableProtocol->Close (ValueHandle);
+ FoundDev = DsdtDeviceUnknown;
continue;
}

- DBG("Found Ethernet device\n");
+ DBG("Found device\n");
AcpiTableProtocol->Close(ValueHandle);
- Status = GetEthID (AcpiTableProtocol, ChildHandle, &MacNextID);
+ Status = GetDeviceInfo (AcpiTableProtocol, ChildHandle, &DevNextID, &FoundDev);
if (EFI_ERROR (Status)) {
continue;
}
- Found = 1;
- } else if (Found == 1 && AsciiStrnCmp((CHAR8 *) Data, "_DSD", 4) == 0) {
+ } else if ((FoundDev != DsdtDeviceUnknown) && AsciiStrnCmp((CHAR8 *) Data, "_DSD", 4) == 0) {
//
- // Patch MAC address for open source kernel
+ // Patch DSD data
//
EFI_ACPI_HANDLE PkgHandle;
Status = AcpiTableProtocol->GetOption(DevHandle, 2, &DataType, &Buffer, &DataSize);
@@ -351,12 +486,30 @@ EFI_STATUS ProcessDSDTDevice (
//
// Walk the _DSD node
//
- if (DataSize == 1 && Data[0] == AML_PACKAGE_OP)
- Status = SearchReplacePackageMACAddress(AcpiTableProtocol, PkgHandle, MacNextID);
+ if (DataSize == 1 && Data[0] == AML_PACKAGE_OP) {
+ Status = SearchReplacePackageAddress (AcpiTableProtocol, PkgHandle, DevNextID, FoundDev);
+ }

AcpiTableProtocol->Close(PkgHandle);
+ } else if (AsciiStrnCmp ((CHAR8 *) Data, "_ADR", 4) == 0) {
+ Status = AcpiTableProtocol->GetOption (DevHandle, 2, &DataType, &Buffer, &DataSize);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (DataType != EFI_ACPI_DATA_TYPE_CHILD) {
+ continue;
+ }
+
+ Status = GetDeviceInfo (AcpiTableProtocol, ChildHandle, &DevNextID, &FoundDev);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
}
}
+ } else if ((DataSize == 2) && (Data[0] == AML_EXT_OP) && (Data[1] == AML_EXT_DEVICE_OP)) {
+ ProcessDSDTDevice (AcpiTableProtocol, DevHandle);
}
}

@@ -457,7 +610,10 @@ AcpiCheckSum (
Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Table->Length);
}

-EFI_STATUS EthMacInit(void)
+EFI_STATUS
+UpdateAcpiDsdtTable (
+ VOID
+ )
{
EFI_STATUS Status;
EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol;
diff --git a/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.h b/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.h
index 0a3e811..a7e1eed 100644
--- a/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.h
+++ b/Silicon/Hisilicon/Drivers/AcpiPlatformDxe/EthMac.h
@@ -10,7 +10,7 @@
#ifndef _ETH_MAC_H_
#define _ETH_MAC_H_

-EFI_STATUS EthMacInit(VOID);
+EFI_STATUS UpdateAcpiDsdtTable (VOID);

#endif

--
2.8.1



.


Upcoming Event: TianoCore Bug Triage - APAC / NAMO - Tue, 06/16/2020 6:30pm-7:30pm #cal-reminder

devel@edk2.groups.io Calendar <devel@...>
 

Reminder: TianoCore Bug Triage - APAC / NAMO

When: Tuesday, 16 June 2020, 6:30pm to 7:30pm, (GMT-07:00) America/Los Angeles

Where:https://bluejeans.com/889357567?src=join_info

View Event

Organizer: Brian Richardson brian.richardson@...

Description:

https://www.tianocore.org/bug-triage

 

Meeting URL

https://bluejeans.com/889357567?src=join_info

 

Meeting ID

889 357 567

 

Want to dial in from a phone?

Dial one of the following numbers:

+1.408.740.7256 (US (San Jose))

+1.408.317.9253 (US (Primary, San Jose))

 

(see all numbers - https://www.bluejeans.com/numbers)

Enter the meeting ID and passcode followed by #


Re: [PATCH v1 1/2] UefiCpuPkg: Move StandardSignatureIsAuthenticAMD to BaseUefiCpuLib

Dong, Eric
 

Reviewed-by: Eric Dong <eric.dong@...>

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
Kirkendall, Garrett
Sent: Tuesday, June 16, 2020 2:30 AM
To: devel@edk2.groups.io
Cc: Dong, Eric <eric.dong@...>; Ni, Ray <ray.ni@...>; Laszlo
Ersek <lersek@...>
Subject: [edk2-devel] [PATCH v1 1/2] UefiCpuPkg: Move
StandardSignatureIsAuthenticAMD to BaseUefiCpuLib

Refactor StandardSignatureIsAuthenticAMD into BaseUefiCpuLib from
separate copies in BaseXApicLib, BaseXApicX2ApicLib, and MpInitLib.
This allows for future use of StandarSignatureIsAuthinticAMD without
creating more instances in other modules.

This function allows IA32/X64 code to determine if it is running on an AMD
brand processor.

UefiCpuLib is already included directly or indirectly in all modified modules.
Complete move is made in this change.

Cc: Eric Dong <eric.dong@...>
Cc: Ray Ni <ray.ni@...>
Cc: Laszlo Ersek <lersek@...>
Signed-off-by: Garrett Kirkendall <garrett.kirkendall@...>
---
UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf | 7 ++++
UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf | 2 ++
UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf | 2 ++
UefiCpuPkg/Include/Library/UefiCpuLib.h | 14 ++++++++
UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.c | 38
++++++++++++++++++++
UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c | 25 ++-----------
UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 25 ++------
-----
UefiCpuPkg/Library/MpInitLib/MpLib.c | 23 ------------
8 files changed, 67 insertions(+), 69 deletions(-)

diff --git a/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
b/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
index 006b7acbf14e..34d3a7bb4303 100644
--- a/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
+++ b/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
@@ -4,6 +4,7 @@
# The library routines are UEFI specification compliant.
#
# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -29,6 +30,12 @@
[Sources.IA32] [Sources.X64]
X64/InitializeFpu.nasm

+[Sources]
+ BaseUefiCpuLib.c
+
[Packages]
MdePkg/MdePkg.dec
UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
diff --git a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
index bdb2ff372677..561baa44b0e6 100644
--- a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
+++ b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
@@ -5,6 +5,7 @@
# where local APIC is disabled.
#
# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -37,6 +38,7 @@
[LibraryClasses]
TimerLib
IoLib
PcdLib
+ UefiCpuLib

[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds ##
SOMETIMES_CONSUMES diff --git
a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
index ac1e0a1c9896..1e2a4f8b790f 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
@@ -5,6 +5,7 @@
# where local APIC is disabled.
#
# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -37,6 +38,7 @@
[LibraryClasses]
TimerLib
IoLib
PcdLib
+ UefiCpuLib

[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds ##
SOMETIMES_CONSUMES diff --git
a/UefiCpuPkg/Include/Library/UefiCpuLib.h
b/UefiCpuPkg/Include/Library/UefiCpuLib.h
index 82e53bab3a0f..5326e7246301 100644
--- a/UefiCpuPkg/Include/Library/UefiCpuLib.h
+++ b/UefiCpuPkg/Include/Library/UefiCpuLib.h
@@ -5,6 +5,7 @@
to be UEFI specification compliant.

Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
@@ -29,4 +30,17 @@ InitializeFloatingPointUnits (
VOID
);

+/**
+ Determine if the standard CPU signature is "AuthenticAMD".
+
+ @retval TRUE The CPU signature matches.
+ @retval FALSE The CPU signature does not match.
+
+**/
+BOOLEAN
+EFIAPI
+StandardSignatureIsAuthenticAMD (
+ VOID
+ );
+
#endif
diff --git a/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.c
b/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.c
new file mode 100644
index 000000000000..c2cc3ff9a709
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.c
@@ -0,0 +1,38 @@
+/** @file
+ This library defines some routines that are generic for IA32 family CPU.
+
+ The library routines are UEFI specification compliant.
+
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Register/Intel/Cpuid.h>
+#include <Register/Amd/Cpuid.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiCpuLib.h>
+
+/**
+ Determine if the standard CPU signature is "AuthenticAMD".
+
+ @retval TRUE The CPU signature matches.
+ @retval FALSE The CPU signature does not match.
+
+**/
+BOOLEAN
+EFIAPI
+StandardSignatureIsAuthenticAMD (
+ VOID
+ )
+{
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT32 RegEdx;
+
+ AsmCpuid (CPUID_SIGNATURE, NULL, &RegEbx, &RegEcx, &RegEdx);
+ return (RegEbx == CPUID_SIGNATURE_AUTHENTIC_AMD_EBX &&
+ RegEcx == CPUID_SIGNATURE_AUTHENTIC_AMD_ECX &&
+ RegEdx == CPUID_SIGNATURE_AUTHENTIC_AMD_EDX);
+}
diff --git a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
index 33ea15ca2916..52bd90d33428 100644
--- a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
@@ -4,7 +4,7 @@
This local APIC library instance supports xAPIC mode only.

Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
- Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
+ Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent

@@ -21,33 +21,12 @@
#include <Library/IoLib.h>
#include <Library/TimerLib.h>
#include <Library/PcdLib.h>
+#include <Library/UefiCpuLib.h>

//
// Library internal functions
//

-/**
- Determine if the standard CPU signature is "AuthenticAMD".
-
- @retval TRUE The CPU signature matches.
- @retval FALSE The CPU signature does not match.
-
-**/
-BOOLEAN
-StandardSignatureIsAuthenticAMD (
- VOID
- )
-{
- UINT32 RegEbx;
- UINT32 RegEcx;
- UINT32 RegEdx;
-
- AsmCpuid (CPUID_SIGNATURE, NULL, &RegEbx, &RegEcx, &RegEdx);
- return (RegEbx == CPUID_SIGNATURE_AUTHENTIC_AMD_EBX &&
- RegEcx == CPUID_SIGNATURE_AUTHENTIC_AMD_ECX &&
- RegEdx == CPUID_SIGNATURE_AUTHENTIC_AMD_EDX);
-}
-
/**
Determine if the CPU supports the Local APIC Base Address MSR.

diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index d0f92b33dc8c..cdcbca046191 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -5,7 +5,7 @@
which have xAPIC and x2APIC modes.

Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
- Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
+ Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent

@@ -22,33 +22,12 @@
#include <Library/IoLib.h>
#include <Library/TimerLib.h>
#include <Library/PcdLib.h>
+#include <Library/UefiCpuLib.h>

//
// Library internal functions
//

-/**
- Determine if the standard CPU signature is "AuthenticAMD".
-
- @retval TRUE The CPU signature matches.
- @retval FALSE The CPU signature does not match.
-
-**/
-BOOLEAN
-StandardSignatureIsAuthenticAMD (
- VOID
- )
-{
- UINT32 RegEbx;
- UINT32 RegEcx;
- UINT32 RegEdx;
-
- AsmCpuid (CPUID_SIGNATURE, NULL, &RegEbx, &RegEcx, &RegEdx);
- return (RegEbx == CPUID_SIGNATURE_AUTHENTIC_AMD_EBX &&
- RegEcx == CPUID_SIGNATURE_AUTHENTIC_AMD_ECX &&
- RegEdx == CPUID_SIGNATURE_AUTHENTIC_AMD_EDX);
-}
-
/**
Determine if the CPU supports the Local APIC Base Address MSR.

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c
b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index ab7a8ed6633a..9b0660a5d4ea 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -13,29 +13,6 @@
EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;


-/**
- Determine if the standard CPU signature is "AuthenticAMD".
-
- @retval TRUE The CPU signature matches.
- @retval FALSE The CPU signature does not match.
-
-**/
-STATIC
-BOOLEAN
-StandardSignatureIsAuthenticAMD (
- VOID
- )
-{
- UINT32 RegEbx;
- UINT32 RegEcx;
- UINT32 RegEdx;
-
- AsmCpuid (CPUID_SIGNATURE, NULL, &RegEbx, &RegEcx, &RegEdx);
- return (RegEbx == CPUID_SIGNATURE_AUTHENTIC_AMD_EBX &&
- RegEcx == CPUID_SIGNATURE_AUTHENTIC_AMD_ECX &&
- RegEdx == CPUID_SIGNATURE_AUTHENTIC_AMD_EDX);
-}
-
/**
The function will check if BSP Execute Disable is enabled.

--
2.27.0



Re: [PATCH 2/5] MdeModulePkg/SmmCore: Remove UEFI LOADED_IMAGE from SMM.

Michael D Kinney
 

Zhiguang,

The commit message should not have more than one Signed-off-by.

Use of Suggested-by may be more appropriate here.

Mike

-----Original Message-----
From: Liu, Zhiguang <zhiguang.liu@...>
Sent: Tuesday, June 16, 2020 2:05 AM
To: devel@edk2.groups.io
Cc: Tian, Feng <feng.tian@...>; Zeng, Star
<star.zeng@...>; Kinney, Michael D
<michael.d.kinney@...>; Laszlo Ersek
<lersek@...>; Yao, Jiewen <jiewen.yao@...>
Subject: [PATCH 2/5] MdeModulePkg/SmmCore: Remove UEFI
LOADED_IMAGE from SMM.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2317

This patch removes EFI_LOADED_IMAGE_PROTOCOL from DXE
database.
The SmmCore only install EFI_LOADED_IMAGE_PROTOCOL to
SMM database.

Exposing LOADED_IMAGE_PROTOCOL may cause SMM information
leakage
to non-SMM component.

Cc: Feng Tian <feng.tian@...>
Cc: Star Zeng <star.zeng@...>
Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Laszlo Ersek <lersek@...>
Signed-off-by: Jiewen Yao <jiewen.yao@...>
Signed-off-by: Zhiguang Liu <zhiguang.liu@...>
---
MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 104
+++++++++++---------------------------------------------
------------------------------------------------
MdeModulePkg/Core/PiSmmCore/PiSmmCore.c | 34 --------
--------------------------
MdeModulePkg/Core/PiSmmCore/PiSmmCore.h | 4 ++--
3 files changed, 13 insertions(+), 129 deletions(-)

diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
index 76ee9e0b89..2be2866234 100644
--- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
+++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
@@ -316,7 +316,7 @@ SmmLoadImage (
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;

PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;



- PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle);

+ PERF_LOAD_IMAGE_BEGIN (DriverEntry->SmmImageHandle);



Buffer = NULL;

Size = 0;

@@ -546,51 +546,14 @@ SmmLoadImage (
DriverEntry->ImageBuffer = DstBuffer;

DriverEntry->NumberOfPage = PageCount;



- //

- // Allocate a Loaded Image Protocol in
EfiBootServicesData

- //

- Status = gBS->AllocatePool (EfiBootServicesData,
sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID
**)&DriverEntry->LoadedImage);

- if (EFI_ERROR (Status)) {

- if (Buffer != NULL) {

- gBS->FreePool (Buffer);

- }

- SmmFreePages (DstBuffer, PageCount);

- return Status;

- }

-

- ZeroMem (DriverEntry->LoadedImage, sizeof
(EFI_LOADED_IMAGE_PROTOCOL));

//

// Fill in the remaining fields of the Loaded Image
Protocol instance.

- // Note: ImageBase is an SMRAM address that can not
be accessed outside of SMRAM if SMRAM window is closed.

//

- DriverEntry->LoadedImage->Revision =
EFI_LOADED_IMAGE_PROTOCOL_REVISION;

- DriverEntry->LoadedImage->ParentHandle =
gSmmCorePrivate->SmmIplImageHandle;

- DriverEntry->LoadedImage->SystemTable = gST;

- DriverEntry->LoadedImage->DeviceHandle =
DeviceHandle;

-

DriverEntry->SmmLoadedImage.Revision =
EFI_LOADED_IMAGE_PROTOCOL_REVISION;

DriverEntry->SmmLoadedImage.ParentHandle =
gSmmCorePrivate->SmmIplImageHandle;

DriverEntry->SmmLoadedImage.SystemTable = gST;

DriverEntry->SmmLoadedImage.DeviceHandle =
DeviceHandle;



- //

- // Make an EfiBootServicesData buffer copy of
FilePath

- //

- Status = gBS->AllocatePool (EfiBootServicesData,
GetDevicePathSize (FilePath), (VOID **)&DriverEntry-
LoadedImage->FilePath);
- if (EFI_ERROR (Status)) {

- if (Buffer != NULL) {

- gBS->FreePool (Buffer);

- }

- SmmFreePages (DstBuffer, PageCount);

- return Status;

- }

- CopyMem (DriverEntry->LoadedImage->FilePath,
FilePath, GetDevicePathSize (FilePath));

-

- DriverEntry->LoadedImage->ImageBase = (VOID
*)(UINTN) ImageContext.ImageAddress;

- DriverEntry->LoadedImage->ImageSize =
ImageContext.ImageSize;

- DriverEntry->LoadedImage->ImageCodeType =
EfiRuntimeServicesCode;

- DriverEntry->LoadedImage->ImageDataType =
EfiRuntimeServicesData;

-

//

// Make a buffer copy of FilePath

//

@@ -599,7 +562,6 @@ SmmLoadImage (
if (Buffer != NULL) {

gBS->FreePool (Buffer);

}

- gBS->FreePool (DriverEntry->LoadedImage->FilePath);

SmmFreePages (DstBuffer, PageCount);

return Status;

}

@@ -610,16 +572,6 @@ SmmLoadImage (
DriverEntry->SmmLoadedImage.ImageCodeType =
EfiRuntimeServicesCode;

DriverEntry->SmmLoadedImage.ImageDataType =
EfiRuntimeServicesData;



- //

- // Create a new image handle in the UEFI handle
database for the SMM Driver

- //

- DriverEntry->ImageHandle = NULL;

- Status = gBS->InstallMultipleProtocolInterfaces (

- &DriverEntry->ImageHandle,

- &gEfiLoadedImageProtocolGuid,
DriverEntry->LoadedImage,

- NULL

- );

-

//

// Create a new image handle in the SMM handle
database for the SMM Driver

//

@@ -631,7 +583,7 @@ SmmLoadImage (
&DriverEntry->SmmLoadedImage

);



- PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle);

+ PERF_LOAD_IMAGE_END (DriverEntry->SmmImageHandle);



//

// Print the load address and the PDB file name if it
is available

@@ -856,7 +808,7 @@ SmmDispatcher (
// Untrused to Scheduled it would have already
been loaded so we may need to

// skip the LoadImage

//

- if (DriverEntry->ImageHandle == NULL) {

+ if (DriverEntry->SmmImageHandle == NULL) {

Status = SmmLoadImage (DriverEntry);



//

@@ -885,8 +837,8 @@ SmmDispatcher (
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (

EFI_PROGRESS_CODE,

EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,

- &DriverEntry->ImageHandle,

- sizeof (DriverEntry->ImageHandle)

+ &DriverEntry->SmmImageHandle,

+ sizeof (DriverEntry->SmmImageHandle)

);



//

@@ -898,9 +850,10 @@ SmmDispatcher (
// For each SMM driver, pass NULL as ImageHandle

//

RegisterSmramProfileImage (DriverEntry, TRUE);

- PERF_START_IMAGE_BEGIN (DriverEntry-
ImageHandle);
- Status =
((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry-
ImageEntryPoint)(DriverEntry->ImageHandle, gST);
- PERF_START_IMAGE_END (DriverEntry->ImageHandle);

+ DEBUG ((DEBUG_INFO, "SMM StartImage - 0x%11p\n",
DriverEntry->ImageEntryPoint));

+ PERF_START_IMAGE_BEGIN (DriverEntry-
SmmImageHandle);
+ Status =
((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry-
ImageEntryPoint)(DriverEntry->SmmImageHandle, gST);
+ PERF_START_IMAGE_END (DriverEntry-
SmmImageHandle);
if (EFI_ERROR(Status)){

DEBUG ((

DEBUG_ERROR,

@@ -910,20 +863,6 @@ SmmDispatcher (
));

UnregisterSmramProfileImage (DriverEntry,
TRUE);

SmmFreePages(DriverEntry->ImageBuffer,
DriverEntry->NumberOfPage);

- //

- // Uninstall LoadedImage

- //

- Status = gBS->UninstallProtocolInterface (

- DriverEntry->ImageHandle,

- &gEfiLoadedImageProtocolGuid,

- DriverEntry->LoadedImage

- );

- if (!EFI_ERROR (Status)) {

- if (DriverEntry->LoadedImage->FilePath !=
NULL) {

- gBS->FreePool (DriverEntry->LoadedImage-
FilePath);
- }

- gBS->FreePool (DriverEntry->LoadedImage);

- }

Status = SmmUninstallProtocolInterface (

DriverEntry->SmmImageHandle,

&gEfiLoadedImageProtocolGuid,

@@ -939,8 +878,8 @@ SmmDispatcher (
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (

EFI_PROGRESS_CODE,

EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,

- &DriverEntry->ImageHandle,

- sizeof (DriverEntry->ImageHandle)

+ &DriverEntry->SmmImageHandle,

+ sizeof (DriverEntry->SmmImageHandle)

);



if (!PreviousSmmEntryPointRegistered &&
gSmmCorePrivate->SmmEntryPointRegistered) {

@@ -1344,27 +1283,6 @@ SmmDriverDispatchHandler (
//

// If this is the SMM core fill in it's
DevicePath & DeviceHandle

//

- if (mSmmCoreLoadedImage->FilePath == NULL)
{

- //

- // Maybe one special FV contains only one
SMM_CORE module, so its device path must

- // be initialized completely.

- //

- EfiInitializeFwVolDevicepathNode
(&mFvDevicePath.File, &NameGuid);

- SetDevicePathEndNode
(&mFvDevicePath.End);

-

- //

- // Make an EfiBootServicesData buffer
copy of FilePath

- //

- Status = gBS->AllocatePool (

- EfiBootServicesData,

- GetDevicePathSize
((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),

- (VOID
**)&mSmmCoreLoadedImage->FilePath

- );

- ASSERT_EFI_ERROR (Status);

- CopyMem (mSmmCoreLoadedImage->FilePath,
&mFvDevicePath, GetDevicePathSize
((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));

-

- mSmmCoreLoadedImage->DeviceHandle =
FvHandle;

- }

if (mSmmCoreDriverEntry-
SmmLoadedImage.FilePath == NULL) {
//

// Maybe one special FV contains only one
SMM_CORE module, so its device path must

diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
index cfa9922cbd..c1b18b047e 100644
--- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
+++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
@@ -104,8 +104,6 @@ EFI_SMRAM_DESCRIPTOR
*mFullSmramRanges;


EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry;



-EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage;

-

/**

Place holder function until all the SMM System Table
Service are available.



@@ -756,38 +754,6 @@ SmmCoreInstallLoadedImage (
)

{

EFI_STATUS Status;

- EFI_HANDLE Handle;

-

- //

- // Allocate a Loaded Image Protocol in
EfiBootServicesData

- //

- Status = gBS->AllocatePool (EfiBootServicesData,
sizeof(EFI_LOADED_IMAGE_PROTOCOL), (VOID
**)&mSmmCoreLoadedImage);

- ASSERT_EFI_ERROR (Status);

-

- ZeroMem (mSmmCoreLoadedImage, sizeof
(EFI_LOADED_IMAGE_PROTOCOL));

- //

- // Fill in the remaining fields of the Loaded Image
Protocol instance.

- // Note: ImageBase is an SMRAM address that can not
be accessed outside of SMRAM if SMRAM window is closed.

- //

- mSmmCoreLoadedImage->Revision =
EFI_LOADED_IMAGE_PROTOCOL_REVISION;

- mSmmCoreLoadedImage->ParentHandle = gSmmCorePrivate-
SmmIplImageHandle;
- mSmmCoreLoadedImage->SystemTable = gST;

-

- mSmmCoreLoadedImage->ImageBase = (VOID
*)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase;

- mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate-
PiSmmCoreImageSize;
- mSmmCoreLoadedImage->ImageCodeType =
EfiRuntimeServicesCode;

- mSmmCoreLoadedImage->ImageDataType =
EfiRuntimeServicesData;

-

- //

- // Create a new image handle in the UEFI handle
database for the SMM Driver

- //

- Handle = NULL;

- Status = gBS->InstallMultipleProtocolInterfaces (

- &Handle,

- &gEfiLoadedImageProtocolGuid,
mSmmCoreLoadedImage,

- NULL

- );

- ASSERT_EFI_ERROR (Status);



//

// Allocate a Loaded Image Protocol in SMM

diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
index 50a7fc0000..3bbd1e1603 100644
--- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
+++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
@@ -122,8 +122,8 @@ typedef struct {
BOOLEAN Initialized;

BOOLEAN DepexProtocolError;



- EFI_HANDLE ImageHandle;

- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;

+ EFI_HANDLE
ImageHandle_Reserved1;

+ EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage_Reserved2;

//

// Image EntryPoint in SMRAM

//

--
2.25.1.windows.1


Re: [PATCH 3/5] MdePkg: Remove DXE_SMM_DRIVER support for some libraries

Michael D Kinney
 

Reviewed-by: Michael D Kinney <michael.d.kinney@...>

Mike

-----Original Message-----
From: Liu, Zhiguang <zhiguang.liu@...>
Sent: Tuesday, June 16, 2020 2:05 AM
To: devel@edk2.groups.io
Cc: Kinney, Michael D <michael.d.kinney@...>; Gao,
Liming <liming.gao@...>
Subject: [PATCH 3/5] MdePkg: Remove DXE_SMM_DRIVER
support for some libraries

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2317
Remove DXE_SMM_DRIVER support for some libraries because
they
have the risks of leaking data from SMM mode to non-SMM
mode.

Cc: Kinney Michael D <michael.d.kinney@...>
Cc: Gao Liming <liming.gao@...>
Signed-off-by: Zhiguang Liu <zhiguang.liu@...>
---

MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuid
edSectionLib.inf | 2 +-
MdePkg/Library/DxeHstiLib/DxeHstiLib.inf
| 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git
a/MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGu
idedSectionLib.inf
b/MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGu
idedSectionLib.inf
index 33eeab405f..acbe62e352 100644
---
a/MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGu
idedSectionLib.inf
+++
b/MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGu
idedSectionLib.inf
@@ -17,7 +17,7 @@
FILE_GUID = f773469b-e265-4b0c-
b0a6-2f971fbfe72b

MODULE_TYPE = DXE_DRIVER

VERSION_STRING = 1.0

- LIBRARY_CLASS =
ExtractGuidedSectionLib|DXE_CORE DXE_DRIVER
DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION
UEFI_DRIVER

+ LIBRARY_CLASS =
ExtractGuidedSectionLib|DXE_CORE DXE_DRIVER
DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER



CONSTRUCTOR =
DxeExtractGuidedSectionLibConstructor



diff --git a/MdePkg/Library/DxeHstiLib/DxeHstiLib.inf
b/MdePkg/Library/DxeHstiLib/DxeHstiLib.inf
index c719481cdd..8c1cb3d0cc 100644
--- a/MdePkg/Library/DxeHstiLib/DxeHstiLib.inf
+++ b/MdePkg/Library/DxeHstiLib/DxeHstiLib.inf
@@ -14,7 +14,7 @@
FILE_GUID = 7DE1C620-F587-4116-
A36D-40F3467B9A0C

MODULE_TYPE = DXE_DRIVER

VERSION_STRING = 1.0

- LIBRARY_CLASS = HstiLib|DXE_CORE
DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
UEFI_APPLICATION UEFI_DRIVER

+ LIBRARY_CLASS = HstiLib|DXE_CORE
DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
UEFI_DRIVER



[Sources]

HstiAip.c

--
2.25.1.windows.1


Re: [PATCH 2/5] MdeModulePkg/SmmCore: Remove UEFI LOADED_IMAGE from SMM.

Michael D Kinney
 

Zhiguang,

There are some source level debug solutions that depend
on the EDI_LOADED_IMAGE_PROTOCOL structure. Does this
change reduce the source level debug capabilities for
SMM drivers under development?

Thanks,

Mike

-----Original Message-----
From: Liu, Zhiguang <zhiguang.liu@...>
Sent: Tuesday, June 16, 2020 2:05 AM
To: devel@edk2.groups.io
Cc: Tian, Feng <feng.tian@...>; Zeng, Star
<star.zeng@...>; Kinney, Michael D
<michael.d.kinney@...>; Laszlo Ersek
<lersek@...>; Yao, Jiewen <jiewen.yao@...>
Subject: [PATCH 2/5] MdeModulePkg/SmmCore: Remove UEFI
LOADED_IMAGE from SMM.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2317

This patch removes EFI_LOADED_IMAGE_PROTOCOL from DXE
database.
The SmmCore only install EFI_LOADED_IMAGE_PROTOCOL to
SMM database.

Exposing LOADED_IMAGE_PROTOCOL may cause SMM information
leakage
to non-SMM component.

Cc: Feng Tian <feng.tian@...>
Cc: Star Zeng <star.zeng@...>
Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Laszlo Ersek <lersek@...>
Signed-off-by: Jiewen Yao <jiewen.yao@...>
Signed-off-by: Zhiguang Liu <zhiguang.liu@...>
---
MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 104
+++++++++++---------------------------------------------
------------------------------------------------
MdeModulePkg/Core/PiSmmCore/PiSmmCore.c | 34 --------
--------------------------
MdeModulePkg/Core/PiSmmCore/PiSmmCore.h | 4 ++--
3 files changed, 13 insertions(+), 129 deletions(-)

diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
index 76ee9e0b89..2be2866234 100644
--- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
+++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
@@ -316,7 +316,7 @@ SmmLoadImage (
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;

PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;



- PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle);

+ PERF_LOAD_IMAGE_BEGIN (DriverEntry->SmmImageHandle);



Buffer = NULL;

Size = 0;

@@ -546,51 +546,14 @@ SmmLoadImage (
DriverEntry->ImageBuffer = DstBuffer;

DriverEntry->NumberOfPage = PageCount;



- //

- // Allocate a Loaded Image Protocol in
EfiBootServicesData

- //

- Status = gBS->AllocatePool (EfiBootServicesData,
sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID
**)&DriverEntry->LoadedImage);

- if (EFI_ERROR (Status)) {

- if (Buffer != NULL) {

- gBS->FreePool (Buffer);

- }

- SmmFreePages (DstBuffer, PageCount);

- return Status;

- }

-

- ZeroMem (DriverEntry->LoadedImage, sizeof
(EFI_LOADED_IMAGE_PROTOCOL));

//

// Fill in the remaining fields of the Loaded Image
Protocol instance.

- // Note: ImageBase is an SMRAM address that can not
be accessed outside of SMRAM if SMRAM window is closed.

//

- DriverEntry->LoadedImage->Revision =
EFI_LOADED_IMAGE_PROTOCOL_REVISION;

- DriverEntry->LoadedImage->ParentHandle =
gSmmCorePrivate->SmmIplImageHandle;

- DriverEntry->LoadedImage->SystemTable = gST;

- DriverEntry->LoadedImage->DeviceHandle =
DeviceHandle;

-

DriverEntry->SmmLoadedImage.Revision =
EFI_LOADED_IMAGE_PROTOCOL_REVISION;

DriverEntry->SmmLoadedImage.ParentHandle =
gSmmCorePrivate->SmmIplImageHandle;

DriverEntry->SmmLoadedImage.SystemTable = gST;

DriverEntry->SmmLoadedImage.DeviceHandle =
DeviceHandle;



- //

- // Make an EfiBootServicesData buffer copy of
FilePath

- //

- Status = gBS->AllocatePool (EfiBootServicesData,
GetDevicePathSize (FilePath), (VOID **)&DriverEntry-
LoadedImage->FilePath);
- if (EFI_ERROR (Status)) {

- if (Buffer != NULL) {

- gBS->FreePool (Buffer);

- }

- SmmFreePages (DstBuffer, PageCount);

- return Status;

- }

- CopyMem (DriverEntry->LoadedImage->FilePath,
FilePath, GetDevicePathSize (FilePath));

-

- DriverEntry->LoadedImage->ImageBase = (VOID
*)(UINTN) ImageContext.ImageAddress;

- DriverEntry->LoadedImage->ImageSize =
ImageContext.ImageSize;

- DriverEntry->LoadedImage->ImageCodeType =
EfiRuntimeServicesCode;

- DriverEntry->LoadedImage->ImageDataType =
EfiRuntimeServicesData;

-

//

// Make a buffer copy of FilePath

//

@@ -599,7 +562,6 @@ SmmLoadImage (
if (Buffer != NULL) {

gBS->FreePool (Buffer);

}

- gBS->FreePool (DriverEntry->LoadedImage->FilePath);

SmmFreePages (DstBuffer, PageCount);

return Status;

}

@@ -610,16 +572,6 @@ SmmLoadImage (
DriverEntry->SmmLoadedImage.ImageCodeType =
EfiRuntimeServicesCode;

DriverEntry->SmmLoadedImage.ImageDataType =
EfiRuntimeServicesData;



- //

- // Create a new image handle in the UEFI handle
database for the SMM Driver

- //

- DriverEntry->ImageHandle = NULL;

- Status = gBS->InstallMultipleProtocolInterfaces (

- &DriverEntry->ImageHandle,

- &gEfiLoadedImageProtocolGuid,
DriverEntry->LoadedImage,

- NULL

- );

-

//

// Create a new image handle in the SMM handle
database for the SMM Driver

//

@@ -631,7 +583,7 @@ SmmLoadImage (
&DriverEntry->SmmLoadedImage

);



- PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle);

+ PERF_LOAD_IMAGE_END (DriverEntry->SmmImageHandle);



//

// Print the load address and the PDB file name if it
is available

@@ -856,7 +808,7 @@ SmmDispatcher (
// Untrused to Scheduled it would have already
been loaded so we may need to

// skip the LoadImage

//

- if (DriverEntry->ImageHandle == NULL) {

+ if (DriverEntry->SmmImageHandle == NULL) {

Status = SmmLoadImage (DriverEntry);



//

@@ -885,8 +837,8 @@ SmmDispatcher (
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (

EFI_PROGRESS_CODE,

EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,

- &DriverEntry->ImageHandle,

- sizeof (DriverEntry->ImageHandle)

+ &DriverEntry->SmmImageHandle,

+ sizeof (DriverEntry->SmmImageHandle)

);



//

@@ -898,9 +850,10 @@ SmmDispatcher (
// For each SMM driver, pass NULL as ImageHandle

//

RegisterSmramProfileImage (DriverEntry, TRUE);

- PERF_START_IMAGE_BEGIN (DriverEntry-
ImageHandle);
- Status =
((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry-
ImageEntryPoint)(DriverEntry->ImageHandle, gST);
- PERF_START_IMAGE_END (DriverEntry->ImageHandle);

+ DEBUG ((DEBUG_INFO, "SMM StartImage - 0x%11p\n",
DriverEntry->ImageEntryPoint));

+ PERF_START_IMAGE_BEGIN (DriverEntry-
SmmImageHandle);
+ Status =
((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry-
ImageEntryPoint)(DriverEntry->SmmImageHandle, gST);
+ PERF_START_IMAGE_END (DriverEntry-
SmmImageHandle);
if (EFI_ERROR(Status)){

DEBUG ((

DEBUG_ERROR,

@@ -910,20 +863,6 @@ SmmDispatcher (
));

UnregisterSmramProfileImage (DriverEntry,
TRUE);

SmmFreePages(DriverEntry->ImageBuffer,
DriverEntry->NumberOfPage);

- //

- // Uninstall LoadedImage

- //

- Status = gBS->UninstallProtocolInterface (

- DriverEntry->ImageHandle,

- &gEfiLoadedImageProtocolGuid,

- DriverEntry->LoadedImage

- );

- if (!EFI_ERROR (Status)) {

- if (DriverEntry->LoadedImage->FilePath !=
NULL) {

- gBS->FreePool (DriverEntry->LoadedImage-
FilePath);
- }

- gBS->FreePool (DriverEntry->LoadedImage);

- }

Status = SmmUninstallProtocolInterface (

DriverEntry->SmmImageHandle,

&gEfiLoadedImageProtocolGuid,

@@ -939,8 +878,8 @@ SmmDispatcher (
REPORT_STATUS_CODE_WITH_EXTENDED_DATA (

EFI_PROGRESS_CODE,

EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,

- &DriverEntry->ImageHandle,

- sizeof (DriverEntry->ImageHandle)

+ &DriverEntry->SmmImageHandle,

+ sizeof (DriverEntry->SmmImageHandle)

);



if (!PreviousSmmEntryPointRegistered &&
gSmmCorePrivate->SmmEntryPointRegistered) {

@@ -1344,27 +1283,6 @@ SmmDriverDispatchHandler (
//

// If this is the SMM core fill in it's
DevicePath & DeviceHandle

//

- if (mSmmCoreLoadedImage->FilePath == NULL)
{

- //

- // Maybe one special FV contains only one
SMM_CORE module, so its device path must

- // be initialized completely.

- //

- EfiInitializeFwVolDevicepathNode
(&mFvDevicePath.File, &NameGuid);

- SetDevicePathEndNode
(&mFvDevicePath.End);

-

- //

- // Make an EfiBootServicesData buffer
copy of FilePath

- //

- Status = gBS->AllocatePool (

- EfiBootServicesData,

- GetDevicePathSize
((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),

- (VOID
**)&mSmmCoreLoadedImage->FilePath

- );

- ASSERT_EFI_ERROR (Status);

- CopyMem (mSmmCoreLoadedImage->FilePath,
&mFvDevicePath, GetDevicePathSize
((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));

-

- mSmmCoreLoadedImage->DeviceHandle =
FvHandle;

- }

if (mSmmCoreDriverEntry-
SmmLoadedImage.FilePath == NULL) {
//

// Maybe one special FV contains only one
SMM_CORE module, so its device path must

diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
index cfa9922cbd..c1b18b047e 100644
--- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
+++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
@@ -104,8 +104,6 @@ EFI_SMRAM_DESCRIPTOR
*mFullSmramRanges;


EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry;



-EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage;

-

/**

Place holder function until all the SMM System Table
Service are available.



@@ -756,38 +754,6 @@ SmmCoreInstallLoadedImage (
)

{

EFI_STATUS Status;

- EFI_HANDLE Handle;

-

- //

- // Allocate a Loaded Image Protocol in
EfiBootServicesData

- //

- Status = gBS->AllocatePool (EfiBootServicesData,
sizeof(EFI_LOADED_IMAGE_PROTOCOL), (VOID
**)&mSmmCoreLoadedImage);

- ASSERT_EFI_ERROR (Status);

-

- ZeroMem (mSmmCoreLoadedImage, sizeof
(EFI_LOADED_IMAGE_PROTOCOL));

- //

- // Fill in the remaining fields of the Loaded Image
Protocol instance.

- // Note: ImageBase is an SMRAM address that can not
be accessed outside of SMRAM if SMRAM window is closed.

- //

- mSmmCoreLoadedImage->Revision =
EFI_LOADED_IMAGE_PROTOCOL_REVISION;

- mSmmCoreLoadedImage->ParentHandle = gSmmCorePrivate-
SmmIplImageHandle;
- mSmmCoreLoadedImage->SystemTable = gST;

-

- mSmmCoreLoadedImage->ImageBase = (VOID
*)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase;

- mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate-
PiSmmCoreImageSize;
- mSmmCoreLoadedImage->ImageCodeType =
EfiRuntimeServicesCode;

- mSmmCoreLoadedImage->ImageDataType =
EfiRuntimeServicesData;

-

- //

- // Create a new image handle in the UEFI handle
database for the SMM Driver

- //

- Handle = NULL;

- Status = gBS->InstallMultipleProtocolInterfaces (

- &Handle,

- &gEfiLoadedImageProtocolGuid,
mSmmCoreLoadedImage,

- NULL

- );

- ASSERT_EFI_ERROR (Status);



//

// Allocate a Loaded Image Protocol in SMM

diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
index 50a7fc0000..3bbd1e1603 100644
--- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
+++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
@@ -122,8 +122,8 @@ typedef struct {
BOOLEAN Initialized;

BOOLEAN DepexProtocolError;



- EFI_HANDLE ImageHandle;

- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;

+ EFI_HANDLE
ImageHandle_Reserved1;

+ EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage_Reserved2;

//

// Image EntryPoint in SMRAM

//

--
2.25.1.windows.1


Re: [PATCH 1/5] MdeModulePkg: avoid SMM pointers being leaked by not using CopyMem()

Michael D Kinney
 

Zhiguang,

An implementation of CopyGuid() could use CopyMem().
Does CopyGuid() also need to be avoided?

Mike

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On
Behalf Of Zhiguang Liu
Sent: Tuesday, June 16, 2020 2:05 AM
To: devel@edk2.groups.io
Cc: Zeng, Star <star.zeng@...>; Gao, Liming
<liming.gao@...>; Wang, Jian J
<jian.j.wang@...>; Wu, Hao A <hao.a.wu@...>
Subject: [edk2-devel] [PATCH 1/5] MdeModulePkg: avoid
SMM pointers being leaked by not using CopyMem()

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2002

This commit will update the logic in function
SmmVariableGetStatistics()
so that the pointer fields ('Next' and 'Name') in
structure
VARIABLE_INFO_ENTRY will not be copied into the SMM
communication buffer.

Doing so will prevent SMM pointers address from being
leaked into non-SMM
environment.

Please note that newly introduced internal function
CopyVarInfoEntry()
will not use CopyMem() to copy the whole
VARIABLE_INFO_ENTRY structure and
then zero out the 'Next' and 'Name' fields. This is for
preventing race
conditions where the pointers value might still be read.

Cc: Star Zeng <star.zeng@...>
Cc: Liming Gao <liming.gao@...>
Cc: Jian J Wang <jian.j.wang@...>
Signed-off-by: Hao A Wu <hao.a.wu@...>
Signed-off-by: Zhiguang Liu <zhiguang.liu@...>
---

MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
| 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)

diff --git
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm
.c
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm
.c
index caca5c3241..74e756bc00 100644
---
a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm
.c
+++
b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm
.c
@@ -315,6 +315,35 @@ GetFvbCountAndBuffer (
}





+/**

+ Copy only the meaningful fields of the variable
statistics information from

+ source buffer to the destination buffer. Other fields
are filled with zero.

+

+ @param[out] DstInfoEntry A pointer to the buffer
of destination variable

+ information entry.

+ @param[in] SrcInfoEntry A pointer to the buffer
of source variable

+ information entry.

+

+**/

+static

+VOID

+CopyVarInfoEntry (

+ OUT VARIABLE_INFO_ENTRY *DstInfoEntry,

+ IN VARIABLE_INFO_ENTRY *SrcInfoEntry

+ )

+{

+ DstInfoEntry->Next = NULL;

+ DstInfoEntry->Name = NULL;

+

+ CopyGuid (&DstInfoEntry->VendorGuid, &SrcInfoEntry-
VendorGuid);
+ DstInfoEntry->Attributes = SrcInfoEntry->Attributes;

+ DstInfoEntry->ReadCount = SrcInfoEntry->ReadCount;

+ DstInfoEntry->WriteCount = SrcInfoEntry->WriteCount;

+ DstInfoEntry->DeleteCount = SrcInfoEntry-
DeleteCount;
+ DstInfoEntry->CacheCount = SrcInfoEntry->CacheCount;

+ DstInfoEntry->Volatile = SrcInfoEntry->Volatile;

+}

+

/**

Get the variable statistics information from the
information buffer pointed by gVariableInfo.



@@ -377,7 +406,7 @@ SmmVariableGetStatistics (
*InfoSize = StatisticsInfoSize;

return EFI_BUFFER_TOO_SMALL;

}

- CopyMem (InfoEntry, VariableInfo, sizeof
(VARIABLE_INFO_ENTRY));

+ CopyVarInfoEntry (InfoEntry, VariableInfo);

CopyMem (InfoName, VariableInfo->Name, NameSize);

*InfoSize = StatisticsInfoSize;

return EFI_SUCCESS;

@@ -417,7 +446,7 @@ SmmVariableGetStatistics (
return EFI_BUFFER_TOO_SMALL;

}



- CopyMem (InfoEntry, VariableInfo, sizeof
(VARIABLE_INFO_ENTRY));

+ CopyVarInfoEntry (InfoEntry, VariableInfo);

CopyMem (InfoName, VariableInfo->Name, NameSize);

*InfoSize = StatisticsInfoSize;



--
2.25.1.windows.1


-=-=-=-=-=-=
Groups.io Links: You receive all messages sent to this
group.

View/Reply Online (#61324):
https://edk2.groups.io/g/devel/message/61324
Mute This Topic: https://groups.io/mt/74912557/1643496
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub
[michael.d.kinney@...]
-=-=-=-=-=-=


Re: [PATCH v3] MdePkg/BasePrintLib: avoid absolute addresses for error strings

Ard Biesheuvel
 

On 6/16/20 11:12 PM, Andrew Fish wrote:
I was wondering what would happen if we converted the CHAR8 arrays in to strings with multiple nulls [1]. Looks like it saves space in uncompressed FVs, but not in compressed FVs.
Yeah, those NUL bytes compress really well, so the overhead of the extra code you need to unpack your strings stands out in the compressed FV.


Here are the Xcode numbers for X64 DEBUG Ovmf:
With this Patch:
SECFV [14%Full] 212992 total, 30128 used, 182864 free
PEIFV [29%Full] 917504 total, 273192 used, 644312 free
DXEFV [39%Full] 12582912 total, 4997120 used, 7585792 free
FVMAIN_COMPACT [36%Full] 3440640 total, 1271264 used, 2169376 free
Vs my patch:
SECFV [14%Full] 212992 total, 29872 used, 183120 free
PEIFV [29%Full] 917504 total, 271048 used, 646456 free
DXEFV [39%Full] 12582912 total, 4979552 used, 7603360 free
FVMAIN_COMPACT [36%Full] 3440640 total, 1271824 used, 2168816 free
SEC: -256
PEI: -2,144
Dxe: -17,568
Compact: +560
[1] $ git diff
*diff --git a/MdePkg/Library/BasePrintLib/PrintLibInternal.c b/MdePkg/Library/BasePrintLib/PrintLibInternal.c*
*index 50c6e8559c43..db2533e7affb 100644*
*--- a/MdePkg/Library/BasePrintLib/PrintLibInternal.c*
*+++ b/MdePkg/Library/BasePrintLib/PrintLibInternal.c*
@@ -30,53 +30,73 @@GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','
 //
 // Longest string: RETURN_WARN_BUFFER_TOO_SMALL => 24 characters plus NUL byte
 //
-GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mWarningString[][24+1] = {
-  "Success",                      //  RETURN_SUCCESS                = 0
-  "Warning Unknown Glyph",        //  RETURN_WARN_UNKNOWN_GLYPH     = 1
-  "Warning Delete Failure",       //  RETURN_WARN_DELETE_FAILURE    = 2
-  "Warning Write Failure",        //  RETURN_WARN_WRITE_FAILURE     = 3
-  "Warning Buffer Too Small",     //  RETURN_WARN_BUFFER_TOO_SMALL  = 4
-  "Warning Stale Data",           //  RETURN_WARN_STALE_DATA        = 5
-};
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mWarningString =     \
+  "Success\0"                      /*  RETURN_SUCCESS                = 0 */ \
+  "Warning Unknown Glyph\0"        /*  RETURN_WARN_UNKNOWN_GLYPH     = 1 */ \
+  "Warning Delete Failure\0"       /*  RETURN_WARN_DELETE_FAILURE    = 2 */ \
+  "Warning Write Failure\0"        /*  RETURN_WARN_WRITE_FAILURE     = 3 */ \
+  "Warning Buffer Too Small\0"     /*  RETURN_WARN_BUFFER_TOO_SMALL  = 4 */ \
+  "Warning Stale Data";            /*  RETURN_WARN_STALE_DATA        = 5 */
 //
 // Longest string: RETURN_INCOMPATIBLE_VERSION => 20 characters plus NUL byte
 //
-GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mErrorString[][20+1] = {
-  "Load Error",                   //  RETURN_LOAD_ERROR             = 1  | MAX_BIT
-  "Invalid Parameter",            //  RETURN_INVALID_PARAMETER      = 2  | MAX_BIT
-  "Unsupported",                  //  RETURN_UNSUPPORTED            = 3  | MAX_BIT
-  "Bad Buffer Size",              //  RETURN_BAD_BUFFER_SIZE        = 4  | MAX_BIT
-  "Buffer Too Small",             //  RETURN_BUFFER_TOO_SMALL,      = 5  | MAX_BIT
-  "Not Ready",                    //  RETURN_NOT_READY              = 6  | MAX_BIT
-  "Device Error",                 //  RETURN_DEVICE_ERROR           = 7  | MAX_BIT
-  "Write Protected",              //  RETURN_WRITE_PROTECTED        = 8  | MAX_BIT
-  "Out of Resources",             //  RETURN_OUT_OF_RESOURCES       = 9  | MAX_BIT
-  "Volume Corrupt",               //  RETURN_VOLUME_CORRUPTED       = 10 | MAX_BIT
-  "Volume Full",                  //  RETURN_VOLUME_FULL            = 11 | MAX_BIT
-  "No Media",                     //  RETURN_NO_MEDIA               = 12 | MAX_BIT
-  "Media changed",                //  RETURN_MEDIA_CHANGED          = 13 | MAX_BIT
-  "Not Found",                    //  RETURN_NOT_FOUND              = 14 | MAX_BIT
-  "Access Denied",                //  RETURN_ACCESS_DENIED          = 15 | MAX_BIT
-  "No Response",                  //  RETURN_NO_RESPONSE            = 16 | MAX_BIT
-  "No mapping",                   //  RETURN_NO_MAPPING             = 17 | MAX_BIT
-  "Time out",                     //  RETURN_TIMEOUT                = 18 | MAX_BIT
-  "Not started",                  //  RETURN_NOT_STARTED            = 19 | MAX_BIT
-  "Already started",              //  RETURN_ALREADY_STARTED        = 20 | MAX_BIT
-  "Aborted",                      //  RETURN_ABORTED                = 21 | MAX_BIT
-  "ICMP Error",                   //  RETURN_ICMP_ERROR             = 22 | MAX_BIT
-  "TFTP Error",                   //  RETURN_TFTP_ERROR             = 23 | MAX_BIT
-  "Protocol Error",               //  RETURN_PROTOCOL_ERROR         = 24 | MAX_BIT
-  "Incompatible Version",         //  RETURN_INCOMPATIBLE_VERSION   = 25 | MAX_BIT
-  "Security Violation",           //  RETURN_SECURITY_VIOLATION     = 26 | MAX_BIT
-  "CRC Error",                    //  RETURN_CRC_ERROR              = 27 | MAX_BIT
-  "End of Media",                 //  RETURN_END_OF_MEDIA           = 28 | MAX_BIT
-  "Reserved (29)",                //  RESERVED                      = 29 | MAX_BIT
-  "Reserved (30)",                //  RESERVED                      = 30 | MAX_BIT
-  "End of File",                  //  RETURN_END_OF_FILE            = 31 | MAX_BIT
-  "Invalid Language",             //  RETURN_INVALID_LANGUAGE       = 32 | MAX_BIT
-  "Compromised Data"              //  RETURN_COMPROMISED_DATA       = 33 | MAX_BIT
-};
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mErrorString =                 \
+  "Load Error\0"                   /*  RETURN_LOAD_ERROR             = 1  | MAX_BIT */ \
+  "Invalid Parameter\0"            /*  RETURN_INVALID_PARAMETER      = 2  | MAX_BIT */ \
+  "Unsupported\0"                  /*  RETURN_UNSUPPORTED            = 3  | MAX_BIT */ \
+  "Bad Buffer Size\0"              /*  RETURN_BAD_BUFFER_SIZE        = 4  | MAX_BIT */ \
+  "Buffer Too Small\0"             /*  RETURN_BUFFER_TOO_SMALL,      = 5  | MAX_BIT */ \
+  "Not Ready\0"                    /*  RETURN_NOT_READY              = 6  | MAX_BIT */ \
+  "Device Error\0"                 /*  RETURN_DEVICE_ERROR           = 7  | MAX_BIT */ \
+  "Write Protected\0"              /*  RETURN_WRITE_PROTECTED        = 8  | MAX_BIT */ \
+  "Out of Resources\0"             /*  RETURN_OUT_OF_RESOURCES       = 9  | MAX_BIT */ \
+  "Volume Corrupt\0"               /*  RETURN_VOLUME_CORRUPTED       = 10 | MAX_BIT */ \
+  "Volume Full\0"                  /*  RETURN_VOLUME_FULL            = 11 | MAX_BIT */ \
+  "No Media\0"                     /*  RETURN_NO_MEDIA               = 12 | MAX_BIT */ \
+  "Media changed\0"                /*  RETURN_MEDIA_CHANGED          = 13 | MAX_BIT */ \
+  "Not Found\0"                    /*  RETURN_NOT_FOUND              = 14 | MAX_BIT */ \
+  "Access Denied\0"                /*  RETURN_ACCESS_DENIED          = 15 | MAX_BIT */ \
+  "No Response\0"                  /*  RETURN_NO_RESPONSE            = 16 | MAX_BIT */ \
+  "No mapping\0"                   /*  RETURN_NO_MAPPING             = 17 | MAX_BIT */ \
+  "Time out\0"                     /*  RETURN_TIMEOUT                = 18 | MAX_BIT */ \
+  "Not started\0"                  /*  RETURN_NOT_STARTED            = 19 | MAX_BIT */ \
+  "Already started\0"              /*  RETURN_ALREADY_STARTED        = 20 | MAX_BIT */ \
+  "Aborted\0"                      /*  RETURN_ABORTED                = 21 | MAX_BIT */ \
+  "ICMP Error\0"                   /*  RETURN_ICMP_ERROR             = 22 | MAX_BIT */ \
+  "TFTP Error\0"                   /*  RETURN_TFTP_ERROR             = 23 | MAX_BIT */ \
+  "Protocol Error\0"               /*  RETURN_PROTOCOL_ERROR         = 24 | MAX_BIT */ \
+  "Incompatible Version\0"         /*  RETURN_INCOMPATIBLE_VERSION   = 25 | MAX_BIT */ \
+  "Security Violation\0"           /*  RETURN_SECURITY_VIOLATION     = 26 | MAX_BIT */ \
+  "CRC Error\0"                    /*  RETURN_CRC_ERROR              = 27 | MAX_BIT */ \
+  "End of Media\0"                 /*  RETURN_END_OF_MEDIA           = 28 | MAX_BIT */ \
+  "Reserved (29)\0"                /*  RESERVED                      = 29 | MAX_BIT */ \
+  "Reserved (30)\0"                /*  RESERVED                      = 30 | MAX_BIT */ \
+  "End of File\0"                  /*  RETURN_END_OF_FILE            = 31 | MAX_BIT */ \
+  "Invalid Language\0"             /*  RETURN_INVALID_LANGUAGE       = 32 | MAX_BIT */ \
+  "Compromised Data";              /*  RETURN_COMPROMISED_DATA       = 33 | MAX_BIT */
+
+
+CONST CHAR8 *
+FindNthStr (
+  IN CONST CHAR8 *Start,
+  IN UINTN       Index
+  )
+{
+  CONST CHAR8 *str;
+
+  for (str = Start; Index > 0; str++) {
+    if (*str == '\0') {
+      Index--;
+      if (Index == 0) {
+        str++;
+        break;
+      }
+    }
+  }
+
+  return str;
+}
 /**
@@ -1005,12 +1025,12 @@BasePrintLibSPrintMarker (
           //
           Index = Status & ~MAX_BIT;
           if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
-            ArgumentString = mErrorString [Index - 1];
+            ArgumentString = FindNthStr (mErrorString, Index - 1);
           }
         } else {
           Index = Status;
           if (Index <= WARNING_STATUS_NUMBER) {
-            ArgumentString = mWarningString [Index];
+            ArgumentString = FindNthStr (mWarningString, Index);
           }
         }
         if (ArgumentString == ValueBuffer) {
Thanks,
Andrew Fish

On Jun 15, 2020, at 6:57 PM, Liming Gao <liming.gao@... <mailto:liming.gao@...>> wrote:

This data is great. The change is good. Reviewed-by: Liming Gao <liming.gao@... <mailto:liming.gao@...>>
*From:*Liu, Zhiguang <zhiguang.liu@... <mailto:zhiguang.liu@...>>
*Sent:*2020年6月15日15:34
*To:*Ard Biesheuvel <ard.biesheuvel@... <mailto:ard.biesheuvel@...>>; Gao, Liming <liming.gao@... <mailto:liming.gao@...>>;devel@edk2.groups.io <mailto:devel@edk2.groups.io>
*Cc:*Kinney, Michael D <michael.d.kinney@... <mailto:michael.d.kinney@...>>
*Subject:*RE: [edk2-devel] [PATCH v3] MdePkg/BasePrintLib: avoid absolute addresses for error strings
Hi Ard,
I also collected the image size of OVMFX64 size building with VS2015x86.

Debug

Release

before

after

After-before

before

after

after-before
sec

27664

27409

-255

13968

13968

0
pei

223016

221000

-2016

107208

106984

-224
dxe

4507000

4481336

-25664

2987064

2979384

-7680
compact

1179776

1172528

-7248

922664

920304

-2360

It can reduce the image size in X64.
Reviewed-by: Zhiguang Liu <zhiguang.liu@... <mailto:zhiguang.liu@...>>
-----Original Message-----
From: Ard Biesheuvel <ard.biesheuvel@... <mailto:ard.biesheuvel@...>>
Sent: Friday, June 12, 2020 11:11 PM
To: Gao, Liming <liming.gao@...
<mailto:liming.gao@...>>;devel@edk2.groups.io <mailto:devel@edk2.groups.io>
Cc: Kinney, Michael D <michael.d.kinney@... <mailto:michael.d.kinney@...>>; Liu,
Zhiguang
<zhiguang.liu@... <mailto:zhiguang.liu@...>>
Subject: Re: [edk2-devel] [PATCH v3] MdePkg/BasePrintLib: avoid absolute
addresses for error strings

On 6/12/20 4:33 PM, Gao, Liming wrote:
Ard:
    I will collect the image size on OVMF X64 platform with this patch.
Building OvmfPkgX64.dsc in RELEASE mode using GCC5 profile gives me


Before:
SECFV [5%Full] 212992 total, 11760 used, 201232 free PEIFV [9%Full] 917504
total, 89384 used, 828120 free DXEFV [22%Full] 12582912 total, 2806320 used,
9776592 free FVMAIN_COMPACT [26%Full] 3440640 total, 918760 used,
2521880 free

After:
SECFV [5%Full] 212992 total, 11760 used, 201232 free PEIFV [9%Full] 917504
total, 89192 used, 828312 free DXEFV [22%Full] 12582912 total, 2802928 used,
9779984 free FVMAIN_COMPACT [26%Full] 3440640 total, 916784 used,
2523856 free

So no change for SECFV, -192 bytes for PEIFV, -3392 bytes for DXEFV and
-1976 bytes for the resulting outer FV image.



-----Original Message-----
From:devel@edk2.groups.io
<mailto:devel@edk2.groups.io><devel@edk2.groups.io <mailto:devel@edk2.groups.io>> On Behalf Of Ard
Biesheuvel
Sent: Friday, June 12, 2020 6:35 AM
To:devel@edk2.groups.io <mailto:devel@edk2.groups.io>
Cc: Ard Biesheuvel <ard.biesheuvel@... <mailto:ard.biesheuvel@...>>; Kinney, Michael D
<michael.d.kinney@... <mailto:michael.d.kinney@...>>; Gao,
Liming <liming.gao@... <mailto:liming.gao@...>>
Subject: [edk2-devel] [PATCH v3] MdePkg/BasePrintLib: avoid absolute
addresses for error strings

The mStatusString[] array is constructed as an array of pointer-to-char,
which means that on X64 or AARCH64, it is emitted as a single linear list
of 64-bit quantities, each containing the absolute address of one of the
string literals in memory.

This means that each string takes up 8 bytes of additional space, along
with 2 bytes of relocation data. It also means that extra work needs to
be done at runtime to process these relocations, every time a module is
loaded that incorporates this library.

So fix both issues, by splitting mStatusString into two arrays of char
arrays. The memory footprint decreases from 955 to 843 bytes, and given
that in the latter case, the overhead consists of 278 NUL characters rather
than 390 bytes worth of absolute addresses and relocation records, the
size
of a compressed image is reduced even further. For example, when
building
ArmVirtQemu.dsc in RELEASE mode for AARCH64 with the GCC5 profile, I
get:

    Before

    FV Space Information
    FVMAIN [100%Full] 5329920 total, 5329920 used, 0 free
    FVMAIN_COMPACT [38%Full] 2093056 total, 811840 used, 1281216 free

    After

    FV Space Information
    FVMAIN [100%Full] 5321728 total, 5321728 used, 0 free
    FVMAIN_COMPACT [38%Full] 2093056 total, 809696 used, 1283360 free

So the uncompressed contents of the compressed image are 8 KB smaller,
whereas the resulting flash image (consisting of the compressed image
along with SEC, PEI_CORE and a set of PEIMs that execute in place) is
2 KB smaller.

Cc: "Kinney, Michael D" <michael.d.kinney@... <mailto:michael.d.kinney@...>>
Cc: "Gao, Liming" <liming.gao@... <mailto:liming.gao@...>>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@... <mailto:ard.biesheuvel@...>>
---
v3:
- add code comments to explain what the inner dimension of each array is
    based on

v2:
- split off this patch from the StandaloneMmPkg series, since they are not
    interdependent anyway, and so they can be discussed separately
- remove mention of StandaloneMmPkg from the commit log - the space
savings
    by themselves are sufficient justification
- update the before/after numbers with the current results
- split the warnings and errors into a separate array, so that the latter
    can use smaller entries
- clarify the commit log to explain the effect on compressed as well as
    XIP images (which both get smaller)

   MdePkg/Library/BasePrintLib/PrintLibInternal.c | 15 ++++++++++++---
   1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/MdePkg/Library/BasePrintLib/PrintLibInternal.c
b/MdePkg/Library/BasePrintLib/PrintLibInternal.c
index b6ec5ac4fbb9..50c6e8559c43 100644
--- a/MdePkg/Library/BasePrintLib/PrintLibInternal.c
+++ b/MdePkg/Library/BasePrintLib/PrintLibInternal.c
@@ -27,13 +27,22 @@


   GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexStr[] =
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};



-GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 * CONST
mStatusString[] = {

+//

+// Longest string: RETURN_WARN_BUFFER_TOO_SMALL => 24
characters plus NUL byte

+//

+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
mWarningString[][24+1] = {

     "Success",                      //  RETURN_SUCCESS                = 0

     "Warning Unknown Glyph",        //  RETURN_WARN_UNKNOWN_GLYPH
= 1

     "Warning Delete Failure",       //  RETURN_WARN_DELETE_FAILURE    = 2

     "Warning Write Failure",        //  RETURN_WARN_WRITE_FAILURE     = 3

     "Warning Buffer Too Small",     //
RETURN_WARN_BUFFER_TOO_SMALL  = 4

     "Warning Stale Data",           //  RETURN_WARN_STALE_DATA        = 5

+};

+

+//

+// Longest string: RETURN_INCOMPATIBLE_VERSION => 20 characters
plus NUL byte

+//

+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
mErrorString[][20+1] = {

     "Load Error",                   //  RETURN_LOAD_ERROR             = 1  | MAX_BIT

     "Invalid Parameter",            //  RETURN_INVALID_PARAMETER      = 2  |
MAX_BIT

     "Unsupported",                  //  RETURN_UNSUPPORTED            = 3  |
MAX_BIT

@@ -996,12 +1005,12 @@ BasePrintLibSPrintMarker (
             //

             Index = Status & ~MAX_BIT;

             if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {

-            ArgumentString = mStatusString [Index +
WARNING_STATUS_NUMBER];

+            ArgumentString = mErrorString [Index - 1];

             }

           } else {

             Index = Status;

             if (Index <= WARNING_STATUS_NUMBER) {

-            ArgumentString = mStatusString [Index];

+            ArgumentString = mWarningString [Index];

             }

           }

           if (ArgumentString == ValueBuffer) {

--
2.26.2


-=-=-=-=-=-=
Groups.io <http://groups.io/>Links: You receive all messages sent to
this group.

View/Reply Online (#61170):
https://edk2.groups.io/g/devel/message/61170
Mute This Topic:https://groups.io/mt/74829004/1759384
Group Owner:devel+owner@edk2.groups.io <mailto:devel+owner@edk2.groups.io>
Unsubscribe:https://edk2.groups.io/g/devel/unsub
[liming.gao@... <mailto:liming.gao@...>]
-=-=-=-=-=-=


Re: [PATCH edk2-platforms] Silicon/Broadcom/BcmGenetDxe: implement media state adapter info protocol

Ard Biesheuvel
 

On 6/16/20 8:17 PM, Ard Biesheuvel wrote:
NetLibDetectMedia () in DxeNetLib is used as a fallback on implementations
of the SNP protocol that do not also carry an implementation of the adapter
info protocol to provide media state information, and it does all kinds of
terrible things to the network interface (stopping and restarting multiple
times, reprogramming the multicast filters etc etc) to workaround some
alleged UNDI shortcoming.
Although our GENET code should be bullet proof and therefore able to take
this kind of abuse, it is better to avoid it, and provide an implementation
of the adapter info protocol that returns the media state directly, without
the need to mistreat the SNP layer.
Cc: Pete Batard <pete@...>
Cc: Andrei Warkentin (awarkentin@...) <awarkentin@...>
Cc: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@...>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@...>
---
Note that this code was build tested only, and turns out not to work as expected. Samer and I are collaborating off-list, I will follow up with a v2 once we have code that actually works.


Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf | 3 +
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h | 4 +
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/AdapterInfo.c | 109 ++++++++++++++++++++
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c | 12 ++-
4 files changed, 123 insertions(+), 5 deletions(-)
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
index 28f3e66ebaf0..89dee9f10c83 100644
--- a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
@@ -19,6 +19,7 @@ [Defines]
UNLOAD_IMAGE = GenetUnload
[Sources]
+ AdapterInfo.c
BcmGenetDxe.h
ComponentName.c
DriverBinding.c
@@ -49,10 +50,12 @@ [LibraryClasses]
[Protocols]
gBcmGenetPlatformDeviceProtocolGuid ## TO_START
+ gEfiAdapterInformationProtocolGuid ## BY_START
gEfiDevicePathProtocolGuid ## BY_START
gEfiSimpleNetworkProtocolGuid ## BY_START
[Guids]
+ gEfiAdapterInfoMediaStateGuid
gEfiEventExitBootServicesGuid
[FixedPcd]
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h
index 0af9d5209cf2..48bb8550426f 100644
--- a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h
@@ -14,6 +14,7 @@
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Protocol/BcmGenetPlatformDevice.h>
+#include <Protocol/AdapterInformation.h>
#include <Protocol/ComponentName.h>
#include <Protocol/ComponentName2.h>
#include <Protocol/SimpleNetwork.h>
@@ -209,6 +210,8 @@ typedef struct {
EFI_SIMPLE_NETWORK_PROTOCOL Snp;
EFI_SIMPLE_NETWORK_MODE SnpMode;
+ EFI_ADAPTER_INFORMATION_PROTOCOL Aip;
+
BCM_GENET_PLATFORM_DEVICE_PROTOCOL *Dev;
GENERIC_PHY_PRIVATE_DATA Phy;
@@ -234,6 +237,7 @@ extern EFI_COMPONENT_NAME_PROTOCOL gGenetComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gGenetComponentName2;
extern CONST EFI_SIMPLE_NETWORK_PROTOCOL gGenetSimpleNetworkTemplate;
+extern CONST EFI_ADAPTER_INFORMATION_PROTOCOL gGenetAdapterInfoTemplate;
#define GENET_DRIVER_SIGNATURE SIGNATURE_32('G', 'N', 'E', 'T')
#define GENET_PRIVATE_DATA_FROM_SNP_THIS(a) CR(a, GENET_PRIVATE_DATA, Snp, GENET_DRIVER_SIGNATURE)
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/AdapterInfo.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/AdapterInfo.c
new file mode 100644
index 000000000000..cb7733bbba76
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/AdapterInfo.c
@@ -0,0 +1,109 @@
+/** @file
+
+ Copyright (c) 2020 Arm, Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "BcmGenetDxe.h"
+
+STATIC
+EFI_STATUS
+EFIAPI
+GenetAipGetInformation (
+ IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ OUT VOID **InformationBlock,
+ OUT UINTN *InformationBlockSize
+ )
+{
+ EFI_ADAPTER_INFO_MEDIA_STATE *AdapterInfo;
+ GENET_PRIVATE_DATA *Genet;
+
+ if (This == NULL || InformationBlock == NULL ||
+ InformationBlockSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!CompareGuid (InformationType, &gEfiAdapterInfoMediaStateGuid)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ AdapterInfo = AllocateZeroPool (sizeof (EFI_ADAPTER_INFO_MEDIA_STATE));
+ if (AdapterInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *InformationBlock = AdapterInfo;
+ *InformationBlockSize = sizeof (EFI_ADAPTER_INFO_MEDIA_STATE);
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->Snp.Mode->MediaPresent) {
+ AdapterInfo->MediaState = EFI_SUCCESS;
+ } else {
+ AdapterInfo->MediaState = EFI_NOT_READY;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+GenetAipSetInformation (
+ IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN VOID *InformationBlock,
+ IN UINTN InformationBlockSize
+ )
+{
+ if (This == NULL || InformationBlock == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompareGuid (InformationType, &gEfiAdapterInfoMediaStateGuid)) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+GenetAipGetSupportedTypes (
+ IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
+ OUT EFI_GUID **InfoTypesBuffer,
+ OUT UINTN *InfoTypesBufferCount
+ )
+{
+ EFI_GUID *Guid;
+
+ if (This == NULL || InfoTypesBuffer == NULL ||
+ InfoTypesBufferCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Guid = AllocatePool (sizeof *Guid);
+ if (Guid == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyGuid (Guid, &gEfiAdapterInfoMediaStateGuid);
+
+ *InfoTypesBuffer = Guid;
+ *InfoTypesBufferCount = 1;
+
+ return EFI_SUCCESS;
+}
+
+CONST EFI_ADAPTER_INFORMATION_PROTOCOL gGenetAdapterInfoTemplate = {
+ GenetAipGetInformation,
+ GenetAipSetInformation,
+ GenetAipGetSupportedTypes,
+};
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
index 7f93c68cd608..f9aa006dc799 100644
--- a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
@@ -163,6 +163,7 @@ GenetDriverBindingStart (
EfiInitializeLock (&Genet->Lock, TPL_CALLBACK);
CopyMem (&Genet->Snp, &gGenetSimpleNetworkTemplate, sizeof Genet->Snp);
+ CopyMem (&Genet->Aip, &gGenetAdapterInfoTemplate, sizeof Genet->Aip);
Genet->Snp.Mode = &Genet->SnpMode;
Genet->SnpMode.State = EfiSimpleNetworkStopped;
@@ -203,7 +204,8 @@ GenetDriverBindingStart (
}
Status = gBS->InstallMultipleProtocolInterfaces (&ControllerHandle,
- &gEfiSimpleNetworkProtocolGuid, &Genet->Snp,
+ &gEfiSimpleNetworkProtocolGuid, &Genet->Snp,
+ &gEfiAdapterInformationProtocolGuid, &Genet->Aip,
NULL);
if (EFI_ERROR (Status)) {
@@ -273,10 +275,10 @@ GenetDriverBindingStop (
ASSERT (Genet->ControllerHandle == ControllerHandle);
- Status = gBS->UninstallProtocolInterface (ControllerHandle,
- &gEfiSimpleNetworkProtocolGuid,
- &Genet->Snp
- );
+ Status = gBS->UninstallMultipleProtocolInterfaces (ControllerHandle,
+ &gEfiSimpleNetworkProtocolGuid, &Genet->Snp,
+ &gEfiAdapterInformationProtocolGuid, &Genet->Aip,
+ NULL);
if (EFI_ERROR (Status)) {
return Status;
}