]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
MdeModulePkg/SmmCorePerformanceLib: Update mPerformanceLength
[mirror_edk2.git] / MdeModulePkg / Library / SmmCorePerformanceLib / SmmCorePerformanceLib.c
index 2834a685d7ee266bf84297741948ffc62da96a61..e03d41ed37bccb0ca66bc109333a94c536713832 100644 (file)
@@ -45,31 +45,80 @@ typedef struct {
 HANDLE_GUID_MAP      mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];\r
 UINTN                mCachePairCount = 0;\r
 \r
-UINT32               mPerformanceLength    = 0;\r
+UINT32               mPerformanceLength    = sizeof (SMM_BOOT_PERFORMANCE_TABLE);\r
 UINT32               mMaxPerformanceLength = 0;\r
+UINT32               mLoadImageCount       = 0;\r
 BOOLEAN              mFpdtDataIsReported   = FALSE;\r
 BOOLEAN              mLackSpaceIsReport    = FALSE;\r
 CHAR8                *mPlatformLanguage    = NULL;\r
 SPIN_LOCK            mSmmFpdtLock;\r
 PERFORMANCE_PROPERTY  mPerformanceProperty;\r
+UINT32               mCachedLength         = 0;\r
 \r
 //\r
-// Interfaces for SMM Performance Protocol.\r
+// Interfaces for SMM PerformanceMeasurement Protocol.\r
 //\r
-PERFORMANCE_PROTOCOL mPerformanceInterface = {\r
-  StartGauge,\r
-  EndGauge,\r
-  GetGauge\r
+EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {\r
+  CreatePerformanceMeasurement,\r
 };\r
 \r
-//\r
-// Interfaces for SMM PerformanceEx Protocol.\r
-//\r
-PERFORMANCE_EX_PROTOCOL mPerformanceExInterface = {\r
-  StartGaugeEx,\r
-  EndGaugeEx,\r
-  GetGaugeEx\r
-};\r
+/**\r
+  Return the pointer to the FPDT record in the allocated memory.\r
+\r
+  @param  RecordSize             The size of FPDT record.\r
+  @param  FpdtRecordPtr          Pointer the FPDT record in the allocated memory.\r
+\r
+  @retval EFI_SUCCESS            Successfully get the pointer to the FPDT record.\r
+  @retval EFI_OUT_OF_RESOURCES   Ran out of space to store the records.\r
+**/\r
+EFI_STATUS\r
+GetFpdtRecordPtr (\r
+  IN     UINT8               RecordSize,\r
+  IN OUT FPDT_RECORD_PTR     *FpdtRecordPtr\r
+)\r
+{\r
+  if (mFpdtDataIsReported) {\r
+    //\r
+    // Append Boot records after Smm boot performance records have been reported.\r
+    //\r
+    if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {\r
+      if (!mLackSpaceIsReport) {\r
+        DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save boot records\n"));\r
+        mLackSpaceIsReport = TRUE;\r
+      }\r
+      return EFI_OUT_OF_RESOURCES;\r
+    } else {\r
+      //\r
+      // Covert buffer to FPDT Ptr Union type.\r
+      //\r
+      FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);\r
+    }\r
+  } else {\r
+    //\r
+    // Check if pre-allocated buffer is full\r
+    //\r
+    if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {\r
+      mSmmBootPerformanceTable = ReallocatePool (\r
+                                   mPerformanceLength,\r
+                                   mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER,\r
+                                   mSmmBootPerformanceTable\r
+                              );\r
+\r
+      if (mSmmBootPerformanceTable == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      mSmmBootPerformanceTable->Header.Length = mPerformanceLength;\r
+      mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER;\r
+    }\r
+    //\r
+    // Covert buffer to FPDT Ptr Union type.\r
+    //\r
+    FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);\r
+  }\r
+  FpdtRecordPtr->RecordHeader->Length = 0;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 \r
 /**\r
 Check whether the Token is a known one which is uesed by core.\r
@@ -85,6 +134,10 @@ IsKnownTokens (
   IN CONST CHAR8  *Token\r
   )\r
 {\r
+  if (Token == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
   if (AsciiStrCmp (Token, SEC_TOK) == 0 ||\r
       AsciiStrCmp (Token, PEI_TOK) == 0 ||\r
       AsciiStrCmp (Token, DXE_TOK) == 0 ||\r
@@ -132,113 +185,59 @@ IsKnownID (
 }\r
 \r
 /**\r
-  Get the FPDT record info.\r
+  Get the FPDT record identifier.\r
 \r
-  @param  IsStart                 TRUE if the performance log is start log.\r
-  @param  Handle                  Pointer to environment specific context used\r
-                                  to identify the component being measured.\r
-  @param  Token                   Pointer to a Null-terminated ASCII string\r
-                                  that identifies the component being measured.\r
-  @param  Module                  Pointer to a Null-terminated ASCII string\r
-                                  that identifies the module being measured.\r
-  @param  RecordInfo              On return, pointer to the info of the record.\r
-  @param  UseModuleName           Only useful for FPDT_DYNAMIC_STRING_EVENT_TYPE, indicate that whether need use\r
-                                  Module name to fill the string field in the FPDT_DYNAMIC_STRING_EVENT_RECORD.\r
+  @param Attribute                The attribute of the Record.\r
+                                  PerfStartEntry: Start Record.\r
+                                  PerfEndEntry: End Record.\r
+  @param  Handle                  Pointer to environment specific context used to identify the component being measured.\r
+  @param  String                  Pointer to a Null-terminated ASCII string that identifies the component being measured.\r
+  @param  ProgressID              On return, pointer to the ProgressID.\r
 \r
-  @retval EFI_SUCCESS             Get record info successfully.\r
-  @retval EFI_UNSUPPORTED         No matched FPDT record.\r
+  @retval EFI_SUCCESS              Get record info successfully.\r
+  @retval EFI_INVALID_PARAMETER    No matched FPDT record.\r
 \r
 **/\r
 EFI_STATUS\r
-GetFpdtRecordInfo (\r
-  IN BOOLEAN                  IsStart,\r
-  IN CONST VOID               *Handle,\r
-  IN CONST CHAR8              *Token,\r
-  IN CONST CHAR8              *Module,\r
-  OUT FPDT_BASIC_RECORD_INFO  *RecordInfo,\r
-  IN OUT BOOLEAN              *UseModuleName\r
+GetFpdtRecordId (\r
+  IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute,\r
+  IN CONST VOID                        *Handle,\r
+  IN CONST CHAR8                       *String,\r
+  OUT UINT16                           *ProgressID\r
   )\r
 {\r
-  UINT16              RecordType;\r
-  UINTN               StringSize;\r
-\r
-  RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
-\r
   //\r
-  // Token to Type and Id.\r
+  // Token to Id.\r
   //\r
-  if (Token != NULL) {\r
-    if (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) {              // "StartImage:"\r
-      *UseModuleName = TRUE;\r
-      RecordType     = FPDT_GUID_EVENT_TYPE;\r
-      if (IsStart) {\r
-        RecordInfo->ProgressID  = MODULE_START_ID;\r
+  if (String != NULL) {\r
+    if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) {              // "StartImage:"\r
+      if (Attribute == PerfStartEntry) {\r
+        *ProgressID  = MODULE_START_ID;\r
       } else {\r
-        RecordInfo->ProgressID  = MODULE_END_ID;\r
+        *ProgressID  = MODULE_END_ID;\r
       }\r
-    } else if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) {        // "LoadImage:"\r
-      *UseModuleName = TRUE;\r
-      RecordType     = FPDT_GUID_QWORD_EVENT_TYPE;\r
-      if (IsStart) {\r
-        RecordInfo->ProgressID  = MODULE_LOADIMAGE_START_ID;\r
+    } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) {        // "LoadImage:"\r
+      if (Attribute == PerfStartEntry) {\r
+        *ProgressID  = MODULE_LOADIMAGE_START_ID;\r
       } else {\r
-        RecordInfo->ProgressID  = MODULE_LOADIMAGE_END_ID;\r
+        *ProgressID  = MODULE_LOADIMAGE_END_ID;\r
       }\r
     } else {                                                      // Pref used in Modules\r
-      if (IsStart) {\r
-        RecordInfo->ProgressID  = PERF_INMODULE_START_ID;\r
+      if (Attribute == PerfStartEntry) {\r
+        *ProgressID  = PERF_INMODULE_START_ID;\r
       } else {\r
-        RecordInfo->ProgressID  = PERF_INMODULE_END_ID;\r
+        *ProgressID  = PERF_INMODULE_END_ID;\r
       }\r
     }\r
-  } else if (Handle != NULL || Module != NULL) {                 // Pref used in Modules\r
-    if (IsStart) {\r
-      RecordInfo->ProgressID    = PERF_INMODULE_START_ID;\r
+  } else if (Handle != NULL) {                                    // Pref used in Modules\r
+    if (Attribute == PerfStartEntry) {\r
+      *ProgressID    = PERF_INMODULE_START_ID;\r
     } else {\r
-      RecordInfo->ProgressID    = PERF_INMODULE_END_ID;\r
+      *ProgressID    = PERF_INMODULE_END_ID;\r
     }\r
   } else {\r
     return EFI_UNSUPPORTED;\r
   }\r
-\r
-  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
-    RecordType               = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
-    RecordInfo->RecordSize   = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE;\r
-  } else {\r
-    switch (RecordType) {\r
-    case FPDT_GUID_EVENT_TYPE:\r
-      RecordInfo->RecordSize  = sizeof (FPDT_GUID_EVENT_RECORD);\r
-      break;\r
-\r
-    case FPDT_DYNAMIC_STRING_EVENT_TYPE:\r
-      if (*UseModuleName) {\r
-        StringSize   = STRING_SIZE;\r
-      } else if (Token != NULL) {\r
-        StringSize  = AsciiStrSize (Token);\r
-      } else if (Module != NULL) {\r
-        StringSize  = AsciiStrSize (Module);\r
-      } else {\r
-        StringSize  = STRING_SIZE;\r
-      }\r
-      if (StringSize > STRING_SIZE) {\r
-        StringSize  = STRING_SIZE;\r
-      }\r
-      RecordInfo->RecordSize  = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize);\r
-      break;\r
-\r
-    case FPDT_GUID_QWORD_EVENT_TYPE:\r
-      RecordInfo->RecordSize  = (UINT8)sizeof (FPDT_GUID_QWORD_EVENT_RECORD);\r
-      break;\r
-\r
-    default:\r
-      //\r
-      // Record type is unsupported in SMM phase.\r
-      //\r
-      return EFI_UNSUPPORTED;\r
-    }\r
-  }\r
-\r
-  RecordInfo->Type = RecordType;\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -444,119 +443,140 @@ Done:
 }\r
 \r
 /**\r
-  Add performance log to FPDT boot record table.\r
+  Copies the string from Source into Destination and updates Length with the\r
+  size of the string.\r
 \r
-  @param  IsStart                 TRUE if the performance log is start log.\r
-  @param  Handle                  Pointer to environment specific context used\r
-                                  to identify the component being measured.\r
-  @param  Token                   Pointer to a Null-terminated ASCII string\r
-                                  that identifies the component being measured.\r
-  @param  Module                  Pointer to a Null-terminated ASCII string\r
-                                  that identifies the module being measured.\r
-  @param  Ticker                  64-bit time stamp.\r
-  @param  Identifier              32-bit identifier. If the value is 0, the created record\r
-                                  is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.\r
+  @param Destination - destination of the string copy\r
+  @param Source      - pointer to the source string which will get copied\r
+  @param Length      - pointer to a length variable to be updated\r
+\r
+**/\r
+VOID\r
+CopyStringIntoPerfRecordAndUpdateLength (\r
+  IN OUT CHAR8  *Destination,\r
+  IN     CONST CHAR8  *Source,\r
+  IN OUT UINT8  *Length\r
+  )\r
+{\r
+  UINTN  StringLen;\r
+  UINTN  DestMax;\r
 \r
-  @retval EFI_SUCCESS             Add FPDT boot record.\r
-  @retval EFI_OUT_OF_RESOURCES    There are not enough resources to record the measurement.\r
-  @retval EFI_UNSUPPORTED         No matched FPDT record.\r
+  ASSERT (Source != NULL);\r
+\r
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
+    DestMax = STRING_SIZE;\r
+  } else {\r
+    DestMax = AsciiStrSize (Source);\r
+    if (DestMax > STRING_SIZE) {\r
+      DestMax = STRING_SIZE;\r
+    }\r
+  }\r
+  StringLen = AsciiStrLen (Source);\r
+  if (StringLen >= DestMax) {\r
+    StringLen = DestMax -1;\r
+  }\r
+\r
+  AsciiStrnCpyS(Destination, DestMax, Source, StringLen);\r
+  *Length += (UINT8)DestMax;\r
+\r
+  return;\r
+}\r
+\r
+/**\r
+  Create performance record with event description and a timestamp.\r
+\r
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID.\r
+  @param Guid              - Pointer to a GUID.\r
+  @param String            - Pointer to a string describing the measurement.\r
+  @param Ticker            - 64-bit time stamp.\r
+  @param Address           - Pointer to a location in memory relevant to the measurement.\r
+  @param PerfId            - Performance identifier describing the type of measurement.\r
+  @param Attribute         - The attribute of the measurement. According to attribute can create a start\r
+                             record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,\r
+                             or a general record for other Perf macros.\r
+\r
+  @retval EFI_SUCCESS           - Successfully created performance record.\r
+  @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records.\r
+  @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL\r
+                                  pointer or invalid PerfId.\r
+\r
+  @retval EFI_SUCCESS           - Successfully created performance record\r
+  @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records\r
+  @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL\r
+                                  pointer or invalid PerfId\r
 \r
 **/\r
 EFI_STATUS\r
-InsertFpdtMeasurement (\r
-  IN BOOLEAN      IsStart,\r
-  IN CONST VOID   *Handle,  OPTIONAL\r
-  IN CONST CHAR8  *Token,   OPTIONAL\r
-  IN CONST CHAR8  *Module,  OPTIONAL\r
-  IN UINT64       Ticker,\r
-  IN UINT32       Identifier\r
+InsertFpdtRecord (\r
+  IN CONST VOID                        *CallerIdentifier,  OPTIONAL\r
+  IN CONST VOID                        *Guid,    OPTIONAL\r
+  IN CONST CHAR8                       *String,  OPTIONAL\r
+  IN       UINT64                      Ticker,\r
+  IN       UINT64                      Address,  OPTIONAL\r
+  IN       UINT16                      PerfId,\r
+  IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute\r
   )\r
+\r
 {\r
+  EFI_STATUS                   Status;\r
   EFI_GUID                     ModuleGuid;\r
   CHAR8                        ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];\r
-  EFI_STATUS                   Status;\r
   FPDT_RECORD_PTR              FpdtRecordPtr;\r
+  FPDT_RECORD_PTR              CachedFpdtRecordPtr;\r
   UINT64                       TimeStamp;\r
-  FPDT_BASIC_RECORD_INFO       RecordInfo;\r
-  UINTN                        DestMax;\r
-  UINTN                        StrLength;\r
   CONST CHAR8                  *StringPtr;\r
-  BOOLEAN                      UseModuleName;\r
+  UINTN                        DestMax;\r
+  UINTN                        StringLen;\r
+  UINT16                       ProgressId;\r
 \r
   StringPtr     = NULL;\r
-  UseModuleName = FALSE;\r
   ZeroMem (ModuleName, sizeof (ModuleName));\r
 \r
   //\r
-  // Get record info includes type, size, ProgressID.\r
-  //\r
-  Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo, &UseModuleName);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  //\r
-  // If PERF_START()/PERF_END() have specified the ProgressID,it has high priority.\r
-  // !!! Note: If the Pref is not the known Token used in the core but have same\r
-  // ID with the core Token, this case will not be supported.\r
-  // And in currtnt usage mode, for the unkown ID, there is a general rule:\r
-  // If it is start pref: the lower 4 bits of the ID should be 0.\r
-  // If it is end pref: the lower 4 bits of the ID should not be 0.\r
-  // If input ID doesn't follow the rule, we will adjust it.\r
+  // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.\r
+  //    notes: For other Perf macros (Attribute == PerfEntry), their Id is known.\r
   //\r
-  if ((Identifier != 0) && (IsKnownID (Identifier)) && (!IsKnownTokens (Token))) {\r
-    return EFI_UNSUPPORTED;\r
-  } else if ((Identifier != 0) && (!IsKnownID (Identifier)) && (!IsKnownTokens (Token))) {\r
-    if (IsStart && ((Identifier & 0x000F) != 0)) {\r
-      Identifier &= 0xFFF0;\r
-    } else if ((!IsStart) && ((Identifier & 0x000F) == 0)) {\r
-      Identifier += 1;\r
-    }\r
-    RecordInfo.ProgressID = (UINT16)Identifier;\r
-  }\r
-\r
-  if (mFpdtDataIsReported) {\r
+  if (Attribute != PerfEntry) {\r
     //\r
-    // Append Boot records after Smm boot performance records have been reported.\r
+    // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.\r
+    // !!! Note: If the Perf is not the known Token used in the core but have same\r
+    // ID with the core Token, this case will not be supported.\r
+    // And in currtnt usage mode, for the unkown ID, there is a general rule:\r
+    // If it is start pref: the lower 4 bits of the ID should be 0.\r
+    // If it is end pref: the lower 4 bits of the ID should not be 0.\r
+    // If input ID doesn't follow the rule, we will adjust it.\r
     //\r
-    if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) {\r
-      if (!mLackSpaceIsReport) {\r
-        DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save boot records\n"));\r
-        mLackSpaceIsReport = TRUE;\r
+    if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {\r
+      if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {\r
+        PerfId &= 0xFFF0;\r
+      } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {\r
+        PerfId += 1;\r
       }\r
-      return EFI_OUT_OF_RESOURCES;\r
-    } else {\r
+    }\r
+    if (PerfId == 0) {\r
       //\r
-      // Covert buffer to FPDT Ptr Union type.\r
+      // Get ProgressID form the String Token.\r
       //\r
-      FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);\r
-    }\r
-  } else {\r
-    //\r
-    // Check if pre-allocated buffer is full\r
-    //\r
-    if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) {\r
-      mSmmBootPerformanceTable = ReallocatePool (\r
-                                   mPerformanceLength,\r
-                                   mPerformanceLength + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER,\r
-                                   mSmmBootPerformanceTable\r
-                              );\r
-\r
-      if (mSmmBootPerformanceTable == NULL) {\r
-        return EFI_OUT_OF_RESOURCES;\r
+      Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
       }\r
-      mSmmBootPerformanceTable->Header.Length = sizeof (SMM_BOOT_PERFORMANCE_TABLE) + mPerformanceLength;\r
-      mMaxPerformanceLength = mPerformanceLength + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER;\r
+      PerfId = ProgressId;\r
     }\r
-    //\r
-    // Covert buffer to FPDT Ptr Union type.\r
-    //\r
-    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);\r
   }\r
-  FpdtRecordPtr.RecordHeader->Length = 0;\r
 \r
   //\r
-  // Get the TimeStamp.\r
+  // 2. Get the buffer to store the FPDT record.\r
+  //\r
+  Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // 3. Get the TimeStamp.\r
   //\r
   if (Ticker == 0) {\r
     Ticker    = GetPerformanceCounter ();\r
@@ -568,70 +588,192 @@ InsertFpdtMeasurement (
   }\r
 \r
   //\r
-  // Get the ModuleName and ModuleGuid form the handle.\r
+  // 4. Fill in the FPDT record according to different Performance Identifier.\r
   //\r
-  GetModuleInfoFromHandle ((EFI_HANDLE *)Handle, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
-\r
-  //\r
-  // Fill in the record information.\r
-  //\r
-  switch (RecordInfo.Type) {\r
-  case FPDT_GUID_EVENT_TYPE:\r
-    FpdtRecordPtr.GuidEvent->Header.Type                = FPDT_GUID_EVENT_TYPE;\r
-    FpdtRecordPtr.GuidEvent->Header.Length              = RecordInfo.RecordSize;\r
-    FpdtRecordPtr.GuidEvent->Header.Revision            = FPDT_RECORD_REVISION_1;\r
-    FpdtRecordPtr.GuidEvent->ProgressID                 = RecordInfo.ProgressID;\r
-    FpdtRecordPtr.GuidEvent->Timestamp                  = TimeStamp;\r
-    CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));\r
+  switch (PerfId) {\r
+  case MODULE_START_ID:\r
+  case MODULE_END_ID:\r
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
+    StringPtr = ModuleName;\r
+    //\r
+    // Cache the offset of start image start record and use to update the start image end record if needed.\r
+    //\r
+    if (PerfId == MODULE_START_ID && Attribute == PerfEntry) {\r
+      mCachedLength = mSmmBootPerformanceTable->Header.Length;\r
+    }\r
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
+      FpdtRecordPtr.GuidEvent->Header.Type                = FPDT_GUID_EVENT_TYPE;\r
+      FpdtRecordPtr.GuidEvent->Header.Length              = sizeof (FPDT_GUID_EVENT_RECORD);\r
+      FpdtRecordPtr.GuidEvent->Header.Revision            = FPDT_RECORD_REVISION_1;\r
+      FpdtRecordPtr.GuidEvent->ProgressID                 = PerfId;\r
+      FpdtRecordPtr.GuidEvent->Timestamp                  = TimeStamp;\r
+      CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));\r
+      if (CallerIdentifier == NULL && PerfId == MODULE_END_ID && mCachedLength != 0) {\r
+        CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);\r
+        CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));\r
+        mCachedLength = 0;\r
+      }\r
+    }\r
     break;\r
 \r
-  case FPDT_DYNAMIC_STRING_EVENT_TYPE:\r
-    FpdtRecordPtr.DynamicStringEvent->Header.Type       = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
-    FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordInfo.RecordSize;\r
-    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = FPDT_RECORD_REVISION_1;\r
-    FpdtRecordPtr.DynamicStringEvent->ProgressID        = RecordInfo.ProgressID;\r
-    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;\r
-    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
-\r
-    if (UseModuleName) {\r
-      StringPtr     = ModuleName;\r
-    } else if (Token != NULL) {\r
-      StringPtr     = Token;\r
-    } else if (Module != NULL) {\r
-      StringPtr     = Module;\r
-    } else if (ModuleName != NULL) {\r
-      StringPtr     = ModuleName;\r
+  case MODULE_LOADIMAGE_START_ID:\r
+  case MODULE_LOADIMAGE_END_ID:\r
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
+    StringPtr = ModuleName;\r
+    if (PerfId == MODULE_LOADIMAGE_START_ID) {\r
+      mLoadImageCount++;\r
+      //\r
+      // Cache the offset of load image start record and use to be updated by the load image end record if needed.\r
+      //\r
+      if (CallerIdentifier == NULL && Attribute == PerfEntry) {\r
+        mCachedLength = mSmmBootPerformanceTable->Header.Length;\r
+      }\r
     }\r
-    if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) {\r
-      StrLength     = AsciiStrLen (StringPtr);\r
-      DestMax       = (RecordInfo.RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8);\r
-      if (StrLength >= DestMax) {\r
-        StrLength   = DestMax -1;\r
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
+      FpdtRecordPtr.GuidQwordEvent->Header.Type           = FPDT_GUID_QWORD_EVENT_TYPE;\r
+      FpdtRecordPtr.GuidQwordEvent->Header.Length         = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);\r
+      FpdtRecordPtr.GuidQwordEvent->Header.Revision       = FPDT_RECORD_REVISION_1;\r
+      FpdtRecordPtr.GuidQwordEvent->ProgressID            = PerfId;\r
+      FpdtRecordPtr.GuidQwordEvent->Timestamp             = TimeStamp;\r
+      FpdtRecordPtr.GuidQwordEvent->Qword                 = mLoadImageCount;\r
+      CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));\r
+      if (PerfId == MODULE_LOADIMAGE_END_ID && mCachedLength != 0) {\r
+        CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);\r
+        CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));\r
+        mCachedLength = 0;\r
       }\r
-      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength);\r
-    } else {\r
-      AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name");\r
     }\r
     break;\r
 \r
-  case FPDT_GUID_QWORD_EVENT_TYPE:\r
-    FpdtRecordPtr.GuidQwordEvent->Header.Type           = FPDT_GUID_QWORD_EVENT_TYPE;\r
-    FpdtRecordPtr.GuidQwordEvent->Header.Length         = RecordInfo.RecordSize;\r
-    FpdtRecordPtr.GuidQwordEvent->Header.Revision       = FPDT_RECORD_REVISION_1;\r
-    FpdtRecordPtr.GuidQwordEvent->ProgressID            = RecordInfo.ProgressID;\r
-    FpdtRecordPtr.GuidQwordEvent->Timestamp             = TimeStamp;\r
-    CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));\r
+  case PERF_EVENTSIGNAL_START_ID:\r
+  case PERF_EVENTSIGNAL_END_ID:\r
+  case PERF_CALLBACK_START_ID:\r
+  case PERF_CALLBACK_END_ID:\r
+    if (String == NULL || Guid == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    StringPtr = String;\r
+    if (AsciiStrLen (String) == 0) {\r
+      StringPtr = "unknown name";\r
+    }\r
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
+      FpdtRecordPtr.DualGuidStringEvent->Header.Type      = FPDT_DUAL_GUID_STRING_EVENT_TYPE;\r
+      FpdtRecordPtr.DualGuidStringEvent->Header.Length    = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);\r
+      FpdtRecordPtr.DualGuidStringEvent->Header.Revision  = FPDT_RECORD_REVISION_1;\r
+      FpdtRecordPtr.DualGuidStringEvent->ProgressID       = PerfId;\r
+      FpdtRecordPtr.DualGuidStringEvent->Timestamp        = TimeStamp;\r
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));\r
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));\r
+      CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);\r
+    }\r
+    break;\r
+\r
+  case PERF_EVENT_ID:\r
+  case PERF_FUNCTION_START_ID:\r
+  case PERF_FUNCTION_END_ID:\r
+  case PERF_INMODULE_START_ID:\r
+  case PERF_INMODULE_END_ID:\r
+  case PERF_CROSSMODULE_START_ID:\r
+  case PERF_CROSSMODULE_END_ID:\r
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
+    if (String != NULL) {\r
+      StringPtr = String;\r
+    } else {\r
+      StringPtr = ModuleName;\r
+    }\r
+    if (AsciiStrLen (StringPtr) == 0) {\r
+      StringPtr = "unknown name";\r
+    }\r
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
+      FpdtRecordPtr.DynamicStringEvent->Header.Type       = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
+      FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
+      FpdtRecordPtr.DynamicStringEvent->Header.Revision   = FPDT_RECORD_REVISION_1;\r
+      FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;\r
+      FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;\r
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
+      CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);\r
+    }\r
     break;\r
 \r
   default:\r
-    //\r
-    // Record is not supported in current SMM phase, return EFI_UNSUPPORTED\r
-    //\r
-    return EFI_UNSUPPORTED;\r
+    if (Attribute != PerfEntry) {\r
+      GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
+      if (String != NULL) {\r
+        StringPtr = String;\r
+      } else {\r
+        StringPtr = ModuleName;\r
+      }\r
+      if (AsciiStrLen (StringPtr) == 0) {\r
+        StringPtr = "unknown name";\r
+      }\r
+      if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
+        FpdtRecordPtr.DynamicStringEvent->Header.Type       = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
+        FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
+        FpdtRecordPtr.DynamicStringEvent->Header.Revision   = FPDT_RECORD_REVISION_1;\r
+        FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;\r
+        FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;\r
+        CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
+        CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);\r
+      }\r
+    } else {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    break;\r
   }\r
 \r
   //\r
-  // Update the cached FPDT record buffer.\r
+  // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.\r
+  //\r
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
+    if (StringPtr == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    FpdtRecordPtr.DynamicStringEvent->Header.Type       = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
+    FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
+    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = FPDT_RECORD_REVISION_1;\r
+    FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;\r
+    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;\r
+    if (Guid != NULL) {\r
+      //\r
+      // Cache the event guid in string event record.\r
+      //\r
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
+    } else {\r
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
+    }\r
+    if (AsciiStrLen (StringPtr) == 0) {\r
+      StringPtr = "unknown name";\r
+    }\r
+    CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);\r
+\r
+    if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {\r
+      FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);\r
+    }\r
+    if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && mCachedLength != 0) {\r
+      CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);\r
+      if (PerfId == MODULE_LOADIMAGE_END_ID) {\r
+        DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
+        StringLen = AsciiStrLen (StringPtr);\r
+        if (StringLen >= DestMax) {\r
+          StringLen = DestMax -1;\r
+        }\r
+        CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));\r
+        AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen);\r
+      } else if (PerfId == MODULE_END_ID) {\r
+        DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
+        StringLen = AsciiStrLen (CachedFpdtRecordPtr.DynamicStringEvent->String);\r
+        if (StringLen >= DestMax) {\r
+          StringLen = DestMax -1;\r
+        }\r
+        CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));\r
+        AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);\r
+      }\r
+      mCachedLength = 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // 5. Update the length of the used buffer after fill in the record.\r
   //\r
   mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;\r
   mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;\r
@@ -639,235 +781,6 @@ InsertFpdtMeasurement (
   return EFI_SUCCESS;\r
 }\r
 \r
-/**\r
-  Adds a record at the end of the performance measurement log\r
-  that records the start time of a performance measurement.\r
-\r
-  Adds a record to the end of the performance measurement log\r
-  that contains the Handle, Token, Module and Identifier.\r
-  The end time of the new record must be set to zero.\r
-  If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.\r
-  If TimeStamp is zero, the start time in the record is filled in with the value\r
-  read from the current time stamp.\r
-\r
-  @param  Handle                  Pointer to environment specific context used\r
-                                  to identify the component being measured.\r
-  @param  Token                   Pointer to a Null-terminated ASCII string\r
-                                  that identifies the component being measured.\r
-  @param  Module                  Pointer to a Null-terminated ASCII string\r
-                                  that identifies the module being measured.\r
-  @param  TimeStamp               64-bit time stamp.\r
-  @param  Identifier              32-bit identifier. If the value is 0, the created record\r
-                                  is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.\r
-\r
-  @retval EFI_SUCCESS             The data was read correctly from the device.\r
-  @retval EFI_OUT_OF_RESOURCES    There are not enough resources to record the measurement.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-StartGaugeEx (\r
-  IN CONST VOID   *Handle,  OPTIONAL\r
-  IN CONST CHAR8  *Token,   OPTIONAL\r
-  IN CONST CHAR8  *Module,  OPTIONAL\r
-  IN UINT64       TimeStamp,\r
-  IN UINT32       Identifier\r
-  )\r
-{\r
-  EFI_STATUS    Status;\r
-\r
-  AcquireSpinLock (&mSmmFpdtLock);\r
-\r
-  Status = InsertFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, Identifier);\r
-\r
-  ReleaseSpinLock (&mSmmFpdtLock);\r
-\r
-  return Status;\r
-}\r
-\r
-/**\r
-  Searches the performance measurement log from the beginning of the log\r
-  for the first matching record that contains a zero end time and fills in a valid end time.\r
-\r
-  Searches the performance measurement log from the beginning of the log\r
-  for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.\r
-  If the record can not be found then return EFI_NOT_FOUND.\r
-  If the record is found and TimeStamp is not zero,\r
-  then the end time in the record is filled in with the value specified by TimeStamp.\r
-  If the record is found and TimeStamp is zero, then the end time in the matching record\r
-  is filled in with the current time stamp value.\r
-\r
-  @param  Handle                  Pointer to environment specific context used\r
-                                  to identify the component being measured.\r
-  @param  Token                   Pointer to a Null-terminated ASCII string\r
-                                  that identifies the component being measured.\r
-  @param  Module                  Pointer to a Null-terminated ASCII string\r
-                                  that identifies the module being measured.\r
-  @param  TimeStamp               64-bit time stamp.\r
-  @param  Identifier              32-bit identifier. If the value is 0, the found record\r
-                                  is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.\r
-\r
-  @retval EFI_SUCCESS             The end of  the measurement was recorded.\r
-  @retval EFI_NOT_FOUND           The specified measurement record could not be found.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-EndGaugeEx (\r
-  IN CONST VOID   *Handle,  OPTIONAL\r
-  IN CONST CHAR8  *Token,   OPTIONAL\r
-  IN CONST CHAR8  *Module,  OPTIONAL\r
-  IN UINT64       TimeStamp,\r
-  IN UINT32       Identifier\r
-  )\r
-{\r
-  EFI_STATUS     Status;\r
-\r
-  AcquireSpinLock (&mSmmFpdtLock);\r
-\r
-  Status = InsertFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, Identifier);\r
-\r
-  ReleaseSpinLock (&mSmmFpdtLock);\r
-\r
-  return Status;\r
-}\r
-\r
-/**\r
-  Retrieves a previously logged performance measurement.\r
-  It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,\r
-  and then assign the Identifier with 0.\r
-\r
-  !!! Not Support!!!\r
-\r
-  Retrieves the performance log entry from the performance log specified by LogEntryKey.\r
-  If it stands for a valid entry, then EFI_SUCCESS is returned and\r
-  GaugeDataEntryEx stores the pointer to that entry.\r
-\r
-  @param  LogEntryKey             The key for the previous performance measurement log entry.\r
-                                  If 0, then the first performance measurement log entry is retrieved.\r
-  @param  GaugeDataEntryEx        The indirect pointer to the extended gauge data entry specified by LogEntryKey\r
-                                  if the retrieval is successful.\r
-\r
-  @retval EFI_SUCCESS             The GuageDataEntryEx is successfully found based on LogEntryKey.\r
-  @retval EFI_NOT_FOUND           The LogEntryKey is the last entry (equals to the total entry number).\r
-  @retval EFI_INVALIDE_PARAMETER  The LogEntryKey is not a valid entry (greater than the total entry number).\r
-  @retval EFI_INVALIDE_PARAMETER  GaugeDataEntryEx is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-GetGaugeEx (\r
-  IN  UINTN                 LogEntryKey,\r
-  OUT GAUGE_DATA_ENTRY_EX   **GaugeDataEntryEx\r
-  )\r
-{\r
-  return EFI_UNSUPPORTED;\r
-}\r
-\r
-/**\r
-  Adds a record at the end of the performance measurement log\r
-  that records the start time of a performance measurement.\r
-\r
-  Adds a record to the end of the performance measurement log\r
-  that contains the Handle, Token, and Module.\r
-  The end time of the new record must be set to zero.\r
-  If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.\r
-  If TimeStamp is zero, the start time in the record is filled in with the value\r
-  read from the current time stamp.\r
-\r
-  @param  Handle                  Pointer to environment specific context used\r
-                                  to identify the component being measured.\r
-  @param  Token                   Pointer to a Null-terminated ASCII string\r
-                                  that identifies the component being measured.\r
-  @param  Module                  Pointer to a Null-terminated ASCII string\r
-                                  that identifies the module being measured.\r
-  @param  TimeStamp               64-bit time stamp.\r
-\r
-  @retval EFI_SUCCESS             The data was read correctly from the device.\r
-  @retval EFI_OUT_OF_RESOURCES    There are not enough resources to record the measurement.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-StartGauge (\r
-  IN CONST VOID   *Handle,  OPTIONAL\r
-  IN CONST CHAR8  *Token,   OPTIONAL\r
-  IN CONST CHAR8  *Module,  OPTIONAL\r
-  IN UINT64       TimeStamp\r
-  )\r
-{\r
-  return StartGaugeEx (Handle, Token, Module, TimeStamp, 0);\r
-}\r
-\r
-/**\r
-  Searches the performance measurement log from the beginning of the log\r
-  for the first matching record that contains a zero end time and fills in a valid end time.\r
-\r
-  Searches the performance measurement log from the beginning of the log\r
-  for the first record that matches Handle, Token, and Module and has an end time value of zero.\r
-  If the record can not be found then return EFI_NOT_FOUND.\r
-  If the record is found and TimeStamp is not zero,\r
-  then the end time in the record is filled in with the value specified by TimeStamp.\r
-  If the record is found and TimeStamp is zero, then the end time in the matching record\r
-  is filled in with the current time stamp value.\r
-\r
-  @param  Handle                  Pointer to environment specific context used\r
-                                  to identify the component being measured.\r
-  @param  Token                   Pointer to a Null-terminated ASCII string\r
-                                  that identifies the component being measured.\r
-  @param  Module                  Pointer to a Null-terminated ASCII string\r
-                                  that identifies the module being measured.\r
-  @param  TimeStamp               64-bit time stamp.\r
-\r
-  @retval EFI_SUCCESS             The end of  the measurement was recorded.\r
-  @retval EFI_NOT_FOUND           The specified measurement record could not be found.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-EndGauge (\r
-  IN CONST VOID   *Handle,  OPTIONAL\r
-  IN CONST CHAR8  *Token,   OPTIONAL\r
-  IN CONST CHAR8  *Module,  OPTIONAL\r
-  IN UINT64       TimeStamp\r
-  )\r
-{\r
-  return EndGaugeEx (Handle, Token, Module, TimeStamp, 0);\r
-}\r
-\r
-/**\r
-  Retrieves a previously logged performance measurement.\r
-  It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,\r
-  and then eliminate the Identifier.\r
-\r
-  !!! Not Support!!!\r
-\r
-  Retrieves the performance log entry from the performance log specified by LogEntryKey.\r
-  If it stands for a valid entry, then EFI_SUCCESS is returned and\r
-  GaugeDataEntry stores the pointer to that entry.\r
-\r
-  @param  LogEntryKey             The key for the previous performance measurement log entry.\r
-                                  If 0, then the first performance measurement log entry is retrieved.\r
-  @param  GaugeDataEntry          The indirect pointer to the gauge data entry specified by LogEntryKey\r
-                                  if the retrieval is successful.\r
-\r
-  @retval EFI_SUCCESS             The GuageDataEntry is successfully found based on LogEntryKey.\r
-  @retval EFI_NOT_FOUND           The LogEntryKey is the last entry (equals to the total entry number).\r
-  @retval EFI_INVALIDE_PARAMETER  The LogEntryKey is not a valid entry (greater than the total entry number).\r
-  @retval EFI_INVALIDE_PARAMETER  GaugeDataEntry is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-GetGauge (\r
-  IN  UINTN               LogEntryKey,\r
-  OUT GAUGE_DATA_ENTRY    **GaugeDataEntry\r
-  )\r
-{\r
-  return EFI_UNSUPPORTED;\r
-}\r
-\r
-\r
 /**\r
   SmmReadyToBoot protocol notification event handler.\r
 \r
@@ -938,16 +851,9 @@ InitializeSmmCorePerformanceLib (
   Handle = NULL;\r
   Status = gSmst->SmmInstallProtocolInterface (\r
                     &Handle,\r
-                    &gSmmPerformanceProtocolGuid,\r
-                    EFI_NATIVE_INTERFACE,\r
-                    &mPerformanceInterface\r
-                    );\r
-  ASSERT_EFI_ERROR (Status);\r
-  Status = gSmst->SmmInstallProtocolInterface (\r
-                    &Handle,\r
-                    &gSmmPerformanceExProtocolGuid,\r
+                    &gEdkiiSmmPerformanceMeasurementProtocolGuid,\r
                     EFI_NATIVE_INTERFACE,\r
-                    &mPerformanceExInterface\r
+                    &mPerformanceMeasurementInterface\r
                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
@@ -1027,6 +933,46 @@ SmmCorePerformanceLibConstructor (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Create performance record with event description and a timestamp.\r
+\r
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID.\r
+  @param Guid              - Pointer to a GUID.\r
+  @param String            - Pointer to a string describing the measurement.\r
+  @param TimeStamp         - 64-bit time stamp.\r
+  @param Address           - Pointer to a location in memory relevant to the measurement.\r
+  @param Identifier        - Performance identifier describing the type of measurement.\r
+  @param Attribute         - The attribute of the measurement. According to attribute can create a start\r
+                             record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,\r
+                             or a general record for other Perf macros.\r
+\r
+  @retval EFI_SUCCESS           - Successfully created performance record.\r
+  @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records.\r
+  @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL\r
+                                  pointer or invalid PerfId.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CreatePerformanceMeasurement(\r
+  IN CONST VOID                        *CallerIdentifier, OPTIONAL\r
+  IN CONST VOID                        *Guid,     OPTIONAL\r
+  IN CONST CHAR8                       *String,   OPTIONAL\r
+  IN       UINT64                      TimeStamp, OPTIONAL\r
+  IN       UINT64                      Address,   OPTIONAL\r
+  IN       UINT32                      Identifier,\r
+  IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute\r
+  )\r
+{\r
+  EFI_STATUS   Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  AcquireSpinLock (&mSmmFpdtLock);\r
+  Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute);\r
+  ReleaseSpinLock (&mSmmFpdtLock);\r
+  return Status;\r
+}\r
+\r
 /**\r
   Adds a record at the end of the performance measurement log\r
   that records the start time of a performance measurement.\r
@@ -1062,7 +1008,17 @@ StartPerformanceMeasurementEx (
   IN UINT32       Identifier\r
   )\r
 {\r
-  return (RETURN_STATUS) StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);\r
+  CONST CHAR8     *String;\r
+\r
+  if (Token != NULL) {\r
+    String = Token;\r
+  } else if (Module != NULL) {\r
+    String = Module;\r
+  } else {\r
+    String = NULL;\r
+  }\r
+\r
+  return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);\r
 }\r
 \r
 /**\r
@@ -1101,7 +1057,17 @@ EndPerformanceMeasurementEx (
   IN UINT32       Identifier\r
   )\r
 {\r
-  return (RETURN_STATUS) EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);\r
+  CONST CHAR8     *String;\r
+\r
+  if (Token != NULL) {\r
+    String = Token;\r
+  } else if (Module != NULL) {\r
+    String = Module;\r
+  } else {\r
+    String = NULL;\r
+  }\r
+\r
+  return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);\r
 }\r
 \r
 /**\r
@@ -1194,7 +1160,7 @@ StartPerformanceMeasurement (
   IN UINT64       TimeStamp\r
   )\r
 {\r
-  return StartGaugeEx (Handle, Token, Module, TimeStamp, 0);\r
+  return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);\r
 }\r
 \r
 /**\r
@@ -1230,7 +1196,7 @@ EndPerformanceMeasurement (
   IN UINT64       TimeStamp\r
   )\r
 {\r
-  return EndGaugeEx (Handle, Token, Module, TimeStamp, 0);\r
+  return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);\r
 }\r
 \r
 /**\r
@@ -1308,3 +1274,59 @@ PerformanceMeasurementEnabled (
 {\r
   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);\r
 }\r
+\r
+/**\r
+  Create performance record with event description and a timestamp.\r
+\r
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID\r
+  @param Guid              - Pointer to a GUID\r
+  @param String            - Pointer to a string describing the measurement\r
+  @param Address           - Pointer to a location in memory relevant to the measurement\r
+  @param Identifier        - Performance identifier describing the type of measurement\r
+\r
+  @retval RETURN_SUCCESS           - Successfully created performance record\r
+  @retval RETURN_OUT_OF_RESOURCES  - Ran out of space to store the records\r
+  @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL\r
+                                     pointer or invalid PerfId\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+LogPerformanceMeasurement (\r
+  IN CONST VOID   *CallerIdentifier,\r
+  IN CONST VOID   *Guid,    OPTIONAL\r
+  IN CONST CHAR8  *String,  OPTIONAL\r
+  IN UINT64       Address, OPTIONAL\r
+  IN UINT32       Identifier\r
+  )\r
+{\r
+  return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);\r
+}\r
+\r
+/**\r
+  Check whether the specified performance measurement can be logged.\r
+\r
+  This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set\r
+  and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.\r
+\r
+  @param Type        - Type of the performance measurement entry.\r
+\r
+  @retval TRUE         The performance measurement can be logged.\r
+  @retval FALSE        The performance measurement can NOT be logged.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LogPerformanceMeasurementEnabled (\r
+  IN  CONST UINTN        Type\r
+  )\r
+{\r
+  //\r
+  // When Performance measurement is enabled and the type is not filtered, the performance can be logged.\r
+  //\r
+  if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {\r
+    return TRUE;\r
+  }\r
+  return FALSE;\r
+}\r
+\r