--- /dev/null
+/** @file\r
+ System Management System Table Services MmInstallConfigurationTable service\r
+\r
+ Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ 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 "StandaloneMmCore.h"\r
+\r
+#define CONFIG_TABLE_SIZE_INCREASED 0x10\r
+\r
+UINTN mMmSystemTableAllocateSize = 0;\r
+\r
+/**\r
+ The MmInstallConfigurationTable() function is used to maintain the list\r
+ of configuration tables that are stored in the System Management System\r
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list\r
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.\r
+\r
+ @param SystemTable A pointer to the SMM System Table (SMST).\r
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.\r
+ @param Table A pointer to the buffer of the table to add.\r
+ @param TableSize The size of the table to install.\r
+\r
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.\r
+ @retval EFI_INVALID_PARAMETER Guid is not valid.\r
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmInstallConfigurationTable (\r
+ IN CONST EFI_MM_SYSTEM_TABLE *SystemTable,\r
+ IN CONST EFI_GUID *Guid,\r
+ IN VOID *Table,\r
+ IN UINTN TableSize\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;\r
+ EFI_CONFIGURATION_TABLE *OldTable;\r
+\r
+ //\r
+ // If Guid is NULL, then this operation cannot be performed\r
+ //\r
+ if (Guid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ConfigurationTable = gMmCoreMmst.MmConfigurationTable;\r
+\r
+ //\r
+ // Search all the table for an entry that matches Guid\r
+ //\r
+ for (Index = 0; Index < gMmCoreMmst.NumberOfTableEntries; Index++) {\r
+ if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index < gMmCoreMmst.NumberOfTableEntries) {\r
+ //\r
+ // A match was found, so this is either a modify or a delete operation\r
+ //\r
+ if (Table != NULL) {\r
+ //\r
+ // If Table is not NULL, then this is a modify operation.\r
+ // Modify the table entry and return.\r
+ //\r
+ ConfigurationTable[Index].VendorTable = Table;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // A match was found and Table is NULL, so this is a delete operation.\r
+ //\r
+ gMmCoreMmst.NumberOfTableEntries--;\r
+\r
+ //\r
+ // Copy over deleted entry\r
+ //\r
+ CopyMem (\r
+ &(ConfigurationTable[Index]),\r
+ &(ConfigurationTable[Index + 1]),\r
+ (gMmCoreMmst.NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)\r
+ );\r
+\r
+ } else {\r
+ //\r
+ // No matching GUIDs were found, so this is an add operation.\r
+ //\r
+ if (Table == NULL) {\r
+ //\r
+ // If Table is NULL on an add operation, then return an error.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Assume that Index == gMmCoreMmst.NumberOfTableEntries\r
+ //\r
+ if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mMmSystemTableAllocateSize) {\r
+ //\r
+ // Allocate a table with one additional entry.\r
+ //\r
+ mMmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));\r
+ ConfigurationTable = AllocatePool (mMmSystemTableAllocateSize);\r
+ if (ConfigurationTable == NULL) {\r
+ //\r
+ // If a new table could not be allocated, then return an error.\r
+ //\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (gMmCoreMmst.MmConfigurationTable != NULL) {\r
+ //\r
+ // Copy the old table to the new table.\r
+ //\r
+ CopyMem (\r
+ ConfigurationTable,\r
+ gMmCoreMmst.MmConfigurationTable,\r
+ Index * sizeof (EFI_CONFIGURATION_TABLE)\r
+ );\r
+\r
+ //\r
+ // Record the old table pointer.\r
+ //\r
+ OldTable = gMmCoreMmst.MmConfigurationTable;\r
+\r
+ //\r
+ // As the MmInstallConfigurationTable() may be re-entered by FreePool() in\r
+ // its calling stack, updating System table to the new table pointer must\r
+ // be done before calling FreePool() to free the old table.\r
+ // It can make sure the gMmCoreMmst.MmConfigurationTable point to the new\r
+ // table and avoid the errors of use-after-free to the old table by the\r
+ // reenter of MmInstallConfigurationTable() in FreePool()'s calling stack.\r
+ //\r
+ gMmCoreMmst.MmConfigurationTable = ConfigurationTable;\r
+\r
+ //\r
+ // Free the old table after updating System Table to the new table pointer.\r
+ //\r
+ FreePool (OldTable);\r
+ } else {\r
+ //\r
+ // Update System Table\r
+ //\r
+ gMmCoreMmst.MmConfigurationTable = ConfigurationTable;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Fill in the new entry\r
+ //\r
+ CopyGuid ((VOID *)&ConfigurationTable[Index].VendorGuid, Guid);\r
+ ConfigurationTable[Index].VendorTable = Table;\r
+\r
+ //\r
+ // This is an add operation, so increment the number of table entries\r
+ //\r
+ gMmCoreMmst.NumberOfTableEntries++;\r
+ }\r
+\r
+ //\r
+ // CRC-32 field is ignorable for SMM System Table and should be set to zero\r
+ //\r
+\r
+ return EFI_SUCCESS;\r
+}\r