--- /dev/null
+/** @file\r
+ Var Check PCD handler.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Library/VarCheckLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+\r
+#include "VarCheckPcdStructure.h"\r
+\r
+//#define DUMP_VAR_CHECK_PCD\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckPcdHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\r
+\r
+/**\r
+ Dump some hexadecimal data.\r
+\r
+ @param[in] Indent How many spaces to indent the output.\r
+ @param[in] Offset The offset of the dump.\r
+ @param[in] DataSize The size in bytes of UserData.\r
+ @param[in] UserData The data to dump.\r
+\r
+**/\r
+VOID\r
+VarCheckPcdInternalDumpHex (\r
+ IN UINTN Indent,\r
+ IN UINTN Offset,\r
+ IN UINTN DataSize,\r
+ IN VOID *UserData\r
+ )\r
+{\r
+ UINT8 *Data;\r
+\r
+ CHAR8 Val[50];\r
+\r
+ CHAR8 Str[20];\r
+\r
+ UINT8 TempByte;\r
+ UINTN Size;\r
+ UINTN Index;\r
+\r
+ Data = UserData;\r
+ while (DataSize != 0) {\r
+ Size = 16;\r
+ if (Size > DataSize) {\r
+ Size = DataSize;\r
+ }\r
+\r
+ for (Index = 0; Index < Size; Index += 1) {\r
+ TempByte = Data[Index];\r
+ Val[Index * 3 + 0] = mVarCheckPcdHex[TempByte >> 4];\r
+ Val[Index * 3 + 1] = mVarCheckPcdHex[TempByte & 0xF];\r
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);\r
+ }\r
+\r
+ Val[Index * 3] = 0;\r
+ Str[Index] = 0;\r
+ DEBUG ((EFI_D_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));\r
+\r
+ Data += Size;\r
+ Offset += Size;\r
+ DataSize -= Size;\r
+ }\r
+}\r
+\r
+/**\r
+ Var Check Pcd ValidData.\r
+\r
+ @param[in] PcdValidData Pointer to Pcd ValidData\r
+ @param[in] Data Data pointer.\r
+ @param[in] DataSize Size of Data to set.\r
+\r
+ @retval TRUE Check pass\r
+ @retval FALSE Check fail.\r
+\r
+**/\r
+BOOLEAN\r
+VarCheckPcdValidData (\r
+ IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData,\r
+ IN VOID *Data,\r
+ IN UINTN DataSize\r
+ )\r
+{\r
+ UINT64 OneData;\r
+ UINT64 Minimum;\r
+ UINT64 Maximum;\r
+ UINT64 OneValue;\r
+ UINT8 *Ptr;\r
+\r
+ OneData = 0;\r
+ CopyMem (&OneData, (UINT8 *) Data + PcdValidData->VarOffset, PcdValidData->StorageWidth);\r
+\r
+ switch (PcdValidData->Type) {\r
+ case VarCheckPcdValidList:\r
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_LIST *) PcdValidData + 1);\r
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {\r
+ OneValue = 0;\r
+ CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);\r
+ if (OneData == OneValue) {\r
+ //\r
+ // Match\r
+ //\r
+ break;\r
+ }\r
+ Ptr += PcdValidData->StorageWidth;\r
+ }\r
+ if ((UINTN) Ptr >= ((UINTN) PcdValidData + PcdValidData->Length)) {\r
+ //\r
+ // No match\r
+ //\r
+ DEBUG ((EFI_D_INFO, "VarCheckPcdValidData fail: ValidList mismatch (0x%lx)\n", OneData));\r
+ DEBUG_CODE (VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *) PcdValidData););\r
+ return FALSE;\r
+ }\r
+ break;\r
+\r
+ case VarCheckPcdValidRange:\r
+ Minimum = 0;\r
+ Maximum = 0;\r
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_RANGE *) PcdValidData + 1);\r
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {\r
+ CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);\r
+ Ptr += PcdValidData->StorageWidth;\r
+ CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);\r
+ Ptr += PcdValidData->StorageWidth;\r
+\r
+ if ((OneData >= Minimum) && (OneData <= Maximum)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ DEBUG ((EFI_D_INFO, "VarCheckPcdValidData fail: ValidRange mismatch (0x%lx)\n", OneData));\r
+ DEBUG_CODE (VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *) PcdValidData););\r
+ return FALSE;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+VAR_CHECK_PCD_VARIABLE_HEADER *mVarCheckPcdBin = NULL;\r
+UINTN mVarCheckPcdBinSize = 0;\r
+\r
+/**\r
+ SetVariable check handler PCD.\r
+\r
+ @param[in] VariableName Name of Variable to set.\r
+ @param[in] VendorGuid Variable vendor GUID.\r
+ @param[in] Attributes Attribute value of the variable.\r
+ @param[in] DataSize Size of Data to set.\r
+ @param[in] Data Data pointer.\r
+\r
+ @retval EFI_SUCCESS The SetVariable check result was success.\r
+ @retval EFI_SECURITY_VIOLATION Check fail.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetVariableCheckHandlerPcd (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;\r
+ VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;\r
+\r
+ if (mVarCheckPcdBin == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {\r
+ //\r
+ // Do not check delete variable.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // For Pcd Variable header align.\r
+ //\r
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (mVarCheckPcdBin);\r
+ while ((UINTN) PcdVariable < ((UINTN) mVarCheckPcdBin + mVarCheckPcdBinSize)) {\r
+ if ((StrCmp ((CHAR16 *) (PcdVariable + 1), VariableName) == 0) &&\r
+ (CompareGuid (&PcdVariable->Guid, VendorGuid))) {\r
+ //\r
+ // Found the Pcd Variable that could be used to do check.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));\r
+ if ((PcdVariable->Attributes != 0) && PcdVariable->Attributes != Attributes) {\r
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable fail for Attributes - 0x%08x\n", PcdVariable->Attributes));\r
+ return EFI_SECURITY_VIOLATION;\r
+ }\r
+\r
+ if (DataSize == 0) {\r
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - CHECK PASS with DataSize == 0 !\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Do the check.\r
+ // For Pcd ValidData header align.\r
+ //\r
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->HeaderLength));\r
+ while ((UINTN) PcdValidData < ((UINTN) PcdVariable + PcdVariable->Length)) {\r
+ if (((UINTN) PcdValidData->VarOffset + PcdValidData->StorageWidth) <= DataSize) {\r
+ if (!VarCheckPcdValidData (PcdValidData, Data, DataSize)) {\r
+ return EFI_SECURITY_VIOLATION;\r
+ }\r
+ }\r
+ //\r
+ // For Pcd ValidData header align.\r
+ //\r
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdValidData + PcdValidData->Length));\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - ALL CHECK PASS!\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // For Pcd Variable header align.\r
+ //\r
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->Length));\r
+ }\r
+\r
+ // Not found, so pass.\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+#ifdef DUMP_VAR_CHECK_PCD\r
+/**\r
+ Dump Pcd ValidData.\r
+\r
+ @param[in] PcdValidData Pointer to Pcd ValidData.\r
+\r
+**/\r
+VOID\r
+DumpPcdValidData (\r
+ IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData\r
+ )\r
+{\r
+ UINT64 Minimum;\r
+ UINT64 Maximum;\r
+ UINT64 OneValue;\r
+ UINT8 *Ptr;\r
+\r
+ DEBUG ((EFI_D_INFO, " VAR_CHECK_PCD_VALID_DATA_HEADER\n"));\r
+ DEBUG ((EFI_D_INFO, " Type - 0x%02x\n", PcdValidData->Type));\r
+ DEBUG ((EFI_D_INFO, " Length - 0x%02x\n", PcdValidData->Length));\r
+ DEBUG ((EFI_D_INFO, " VarOffset - 0x%04x\n", PcdValidData->VarOffset));\r
+ DEBUG ((EFI_D_INFO, " StorageWidth - 0x%02x\n", PcdValidData->StorageWidth));\r
+\r
+ switch (PcdValidData->Type) {\r
+ case VarCheckPcdValidList:\r
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_LIST *) PcdValidData + 1);\r
+ while ((UINTN) Ptr < ((UINTN) PcdValidData + PcdValidData->Length)) {\r
+ OneValue = 0;\r
+ CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);\r
+ switch (PcdValidData->StorageWidth) {\r
+ case sizeof (UINT8):\r
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%02x\n", OneValue));\r
+ break;\r
+ case sizeof (UINT16):\r
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%04x\n", OneValue));\r
+ break;\r
+ case sizeof (UINT32):\r
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%08x\n", OneValue));\r
+ break;\r
+ case sizeof (UINT64):\r
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%016lx\n", OneValue));\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+ Ptr += PcdValidData->StorageWidth;\r
+ }\r
+ break;\r
+\r
+ case VarCheckPcdValidRange:\r
+ Minimum = 0;\r
+ Maximum = 0;\r
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_RANGE *) PcdValidData + 1);\r
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {\r
+ CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);\r
+ Ptr += PcdValidData->StorageWidth;\r
+ CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);\r
+ Ptr += PcdValidData->StorageWidth;\r
+\r
+ switch (PcdValidData->StorageWidth) {\r
+ case sizeof (UINT8):\r
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%02x\n", Minimum));\r
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%02x\n", Maximum));\r
+ break;\r
+ case sizeof (UINT16):\r
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%04x\n", Minimum));\r
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%04x\n", Maximum));\r
+ break;\r
+ case sizeof (UINT32):\r
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%08x\n", Minimum));\r
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%08x\n", Maximum));\r
+ break;\r
+ case sizeof (UINT64):\r
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%016lx\n", Minimum));\r
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%016lx\n", Maximum));\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+}\r
+\r
+/**\r
+ Dump Pcd Variable.\r
+\r
+ @param[in] PcdVariable Pointer to Pcd Variable.\r
+\r
+**/\r
+VOID\r
+DumpPcdVariable (\r
+ IN VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable\r
+ )\r
+{\r
+ VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;\r
+\r
+ DEBUG ((EFI_D_INFO, "VAR_CHECK_PCD_VARIABLE_HEADER\n"));\r
+ DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", PcdVariable->Revision));\r
+ DEBUG ((EFI_D_INFO, " HeaderLength - 0x%04x\n", PcdVariable->HeaderLength));\r
+ DEBUG ((EFI_D_INFO, " Length - 0x%08x\n", PcdVariable->Length));\r
+ DEBUG ((EFI_D_INFO, " Type - 0x%02x\n", PcdVariable->Type));\r
+ DEBUG ((EFI_D_INFO, " Attributes - 0x%08x\n", PcdVariable->Attributes));\r
+ DEBUG ((EFI_D_INFO, " Guid - %g\n", &PcdVariable->Guid));\r
+ DEBUG ((EFI_D_INFO, " Name - %s\n", PcdVariable + 1));\r
+\r
+ //\r
+ // For Pcd ValidData header align.\r
+ //\r
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->HeaderLength));\r
+ while ((UINTN) PcdValidData < ((UINTN) PcdVariable + PcdVariable->Length)) {\r
+ //\r
+ // Dump Pcd ValidData related to the Pcd Variable.\r
+ //\r
+ DumpPcdValidData (PcdValidData);\r
+ //\r
+ // For Pcd ValidData header align.\r
+ //\r
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdValidData + PcdValidData->Length));\r
+ }\r
+}\r
+\r
+/**\r
+ Dump Var Check PCD.\r
+\r
+ @param[in] VarCheckPcdBin Pointer to VarCheckPcdBin.\r
+ @param[in] VarCheckPcdBinSize VarCheckPcdBin size.\r
+\r
+**/\r
+VOID\r
+DumpVarCheckPcd (\r
+ IN VOID *VarCheckPcdBin,\r
+ IN UINTN VarCheckPcdBinSize\r
+ )\r
+{\r
+ VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;\r
+\r
+ DEBUG ((EFI_D_INFO, "DumpVarCheckPcd\n"));\r
+\r
+ //\r
+ // For Pcd Variable header align.\r
+ //\r
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (VarCheckPcdBin);\r
+ while ((UINTN) PcdVariable < ((UINTN) VarCheckPcdBin + VarCheckPcdBinSize)) {\r
+ DumpPcdVariable (PcdVariable);\r
+ //\r
+ // For Pcd Variable header align.\r
+ //\r
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->Length));\r
+ }\r
+}\r
+#endif\r
+\r
+/**\r
+ Locate VarCheckPcdBin.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+LocateVarCheckPcdBin (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VAR_CHECK_PCD_VARIABLE_HEADER *VarCheckPcdBin;\r
+ UINTN VarCheckPcdBinSize;\r
+\r
+ //\r
+ // Search the VarCheckPcdBin from the first RAW section of current FFS.\r
+ //\r
+ Status = GetSectionFromFfs (\r
+ EFI_SECTION_RAW,\r
+ 0,\r
+ (VOID **) &VarCheckPcdBin,\r
+ &VarCheckPcdBinSize\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // AllocateRuntimeZeroPool () from MemoryAllocateLib is used for runtime access\r
+ // in SetVariable check handler.\r
+ //\r
+ mVarCheckPcdBin = AllocateRuntimeCopyPool (VarCheckPcdBinSize, VarCheckPcdBin);\r
+ ASSERT (mVarCheckPcdBin != NULL);\r
+ mVarCheckPcdBinSize = VarCheckPcdBinSize;\r
+ FreePool (VarCheckPcdBin);\r
+\r
+ DEBUG ((EFI_D_INFO, "VarCheckPcdBin - at 0x%x size = 0x%x\n", mVarCheckPcdBin, mVarCheckPcdBinSize));\r
+\r
+#ifdef DUMP_VAR_CHECK_PCD\r
+ DEBUG_CODE (\r
+ DumpVarCheckPcd (mVarCheckPcdBin, mVarCheckPcdBinSize);\r
+ );\r
+#endif\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "[VarCheckPcd] No VarCheckPcdBin found at the first RAW section\n"));\r
+ }\r
+}\r
+\r
+/**\r
+ Constructor function of VarCheckPcdLib to register var check PCD handler.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The constructor executed correctly.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VarCheckPcdLibNullClassConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ LocateVarCheckPcdBin ();\r
+ VarCheckLibRegisterAddressPointer ((VOID **) &mVarCheckPcdBin);\r
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerPcd);\r
+\r
+ return EFI_SUCCESS;\r
+}\r