]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
MdeModulePkg: Update performance library instances
[mirror_edk2.git] / MdeModulePkg / Library / PeiPerformanceLib / PeiPerformanceLib.c
index f770a35a995d7a8f8a399f4dd4f1a38244b7cfac..cd1b0e34ef7e0d2b0e740dfa61276e14e33585b1 100644 (file)
@@ -23,6 +23,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <PiPei.h>\r
 \r
 #include <Guid/ExtendedFirmwarePerformance.h>\r
+#include <Guid/PerformanceMeasurement.h>\r
 \r
 #include <Library/PerformanceLib.h>\r
 #include <Library/DebugLib.h>\r
@@ -33,7 +34,85 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/BaseMemoryLib.h>\r
 \r
 #define  STRING_SIZE            (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))\r
-#define  MAX_RECORD_SIZE        (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE)\r
+#define  PEI_MAX_RECORD_SIZE    (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + STRING_SIZE)\r
+\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
+  @param  PeiPerformanceLogHeader   Pointer to the header of the PEI Performance records in the GUID Hob.\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
+  IN OUT FPDT_PEI_EXT_PERF_HEADER  **PeiPerformanceLogHeader\r
+)\r
+{\r
+  UINT16                                PeiPerformanceLogEntries;\r
+  UINTN                                 PeiPerformanceSize;\r
+  UINT8                                 *PeiFirmwarePerformance;\r
+  EFI_HOB_GUID_TYPE                     *GuidHob;\r
+\r
+  //\r
+  // Get the number of PeiPerformanceLogEntries form PCD.\r
+  //\r
+  PeiPerformanceLogEntries = (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ?\r
+                                       PcdGet16 (PcdMaxPeiPerformanceLogEntries16) :\r
+                                       PcdGet8 (PcdMaxPeiPerformanceLogEntries));\r
+\r
+  //\r
+  // Create GUID HOB Data.\r
+  //\r
+  GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid);\r
+  PeiFirmwarePerformance = NULL;\r
+  while (GuidHob != NULL) {\r
+    //\r
+    // PEI Performance HOB was found, then return the existing one.\r
+    //\r
+    PeiFirmwarePerformance  = (UINT8*)GET_GUID_HOB_DATA (GuidHob);\r
+    *PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance;\r
+    if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize > (UINTN)(PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE)) {\r
+      (*PeiPerformanceLogHeader)->HobIsFull = TRUE;\r
+    }\r
+    if (!(*PeiPerformanceLogHeader)->HobIsFull && (*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize <= (UINTN)(PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE)) {\r
+      FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER) + (*PeiPerformanceLogHeader)->SizeOfAllEntries);\r
+      break;\r
+    }\r
+    //\r
+    // Previous HOB is used, then find next one.\r
+    //\r
+    GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob));\r
+  }\r
+\r
+  if (GuidHob == NULL) {\r
+    //\r
+    // PEI Performance HOB was not found, then build one.\r
+    //\r
+    PeiPerformanceSize      = sizeof (FPDT_PEI_EXT_PERF_HEADER) +\r
+                              PEI_MAX_RECORD_SIZE * PeiPerformanceLogEntries;\r
+    PeiFirmwarePerformance  = (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize);\r
+    if (PeiFirmwarePerformance != NULL) {\r
+      ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize);\r
+      (*PeiPerformanceLogHeader) = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance;\r
+      FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER));\r
+    }\r
+  }\r
+\r
+  if (PeiFirmwarePerformance == NULL) {\r
+    //\r
+    // there is no enough resource to store performance data\r
+    //\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
 Check whether the Token is a known one which is uesed by core.\r
@@ -100,248 +179,193 @@ 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 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
+GetFpdtRecordId (\r
+  IN BOOLEAN                 Attribute,\r
   IN CONST VOID              *Handle,\r
-  IN CONST CHAR8             *Token,\r
-  IN CONST CHAR8             *Module,\r
-  OUT FPDT_BASIC_RECORD_INFO *RecordInfo\r
+  IN CONST CHAR8             *String,\r
+  OUT UINT16                 *ProgressID\r
   )\r
 {\r
-  UINTN     StringSize;\r
-  UINT16    RecordType;\r
-\r
-  RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
-\r
   //\r
   // Get the ProgressID based on the Token.\r
   // When PcdEdkiiFpdtStringRecordEnableOnly is TRUE, all records are with type of FPDT_DYNAMIC_STRING_EVENT_TYPE.\r
   //\r
-  if (Token != NULL) {\r
-    if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) {               // "LoadImage:"\r
-      if (IsStart) {\r
-        RecordInfo->ProgressID = MODULE_LOADIMAGE_START_ID;\r
+  if (String != NULL) {\r
+    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
-      if(!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
-        RecordType = FPDT_GUID_QWORD_EVENT_TYPE;\r
-      }\r
-    } else if (AsciiStrCmp (Token, SEC_TOK) == 0 ||               // "SEC"\r
-               AsciiStrCmp (Token, PEI_TOK) == 0) {               // "PEI"\r
-      if (IsStart) {\r
-        RecordInfo->ProgressID = PERF_CROSSMODULE_START_ID;\r
+    } else if (AsciiStrCmp (String, SEC_TOK) == 0 ||               // "SEC"\r
+               AsciiStrCmp (String, PEI_TOK) == 0) {               // "PEI"\r
+      if (Attribute == PerfStartEntry) {\r
+        *ProgressID = PERF_CROSSMODULE_START_ID;\r
       } else {\r
-        RecordInfo->ProgressID = PERF_CROSSMODULE_END_ID;\r
+        *ProgressID = PERF_CROSSMODULE_END_ID;\r
       }\r
-    } else if (AsciiStrCmp (Token, PEIM_TOK) == 0) {              // "PEIM"\r
-      if (IsStart) {\r
-        RecordInfo->ProgressID = MODULE_START_ID;\r
+    } else if (AsciiStrCmp (String, PEIM_TOK) == 0) {              // "PEIM"\r
+      if (Attribute == PerfStartEntry) {\r
+        *ProgressID = MODULE_START_ID;\r
       } else {\r
-        RecordInfo->ProgressID = MODULE_END_ID;\r
-      }\r
-      if(!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
-        RecordType = FPDT_GUID_EVENT_TYPE;\r
+        *ProgressID = MODULE_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 (Module != NULL || Handle != 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
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  //\r
-  // Get the Guid and string.\r
-  //\r
-  if(PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\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
+  return EFI_SUCCESS;\r
+}\r
 \r
-    case FPDT_GUID_QWORD_EVENT_TYPE:\r
-      RecordInfo->RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);\r
-      break;\r
+/**\r
+  Copies the string from Source into Destination and updates Length with the\r
+  size of the string.\r
 \r
-    case FPDT_DYNAMIC_STRING_EVENT_TYPE:\r
-      if (Token != NULL) {\r
-        StringSize = AsciiStrSize (Token);\r
-      } else if (Module != NULL) {\r
-        StringSize = AsciiStrSize (Module);\r
-      } else {\r
-        StringSize = STRING_SIZE;\r
-      }\r
-      RecordInfo->RecordSize  = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize);\r
-      break;\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
-    default:\r
-      //\r
-      // Other type is unsupported in PEI phase yet, return EFI_UNSUPPORTED\r
-      //\r
-      return EFI_UNSUPPORTED;\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
+  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
-  RecordInfo->Type = RecordType;\r
-  return EFI_SUCCESS;\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
 /**\r
   Convert PEI performance log to FPDT String boot record.\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
-\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
+  @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
 **/\r
 EFI_STATUS\r
-InsertPeiFpdtMeasurement (\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
-  EFI_HOB_GUID_TYPE                     *GuidHob;\r
-  UINTN                                 PeiPerformanceSize;\r
-  UINT8                                 *PeiFirmwarePerformance;\r
-  FPDT_PEI_EXT_PERF_HEADER              *PeiPerformanceLogHeader;\r
   FPDT_RECORD_PTR                       FpdtRecordPtr;\r
-  FPDT_BASIC_RECORD_INFO                RecordInfo;\r
   CONST VOID                            *ModuleGuid;\r
-  UINTN                                 DestMax;\r
-  UINTN                                 StrLength;\r
   CONST CHAR8                           *StringPtr;\r
   EFI_STATUS                            Status;\r
-  UINT16                                PeiPerformanceLogEntries;\r
   UINT64                                TimeStamp;\r
+  FPDT_PEI_EXT_PERF_HEADER              *PeiPerformanceLogHeader;\r
 \r
   StringPtr = NULL;\r
   FpdtRecordPtr.RecordHeader = NULL;\r
   PeiPerformanceLogHeader = NULL;\r
 \r
   //\r
-  // Get record info (type, size, ProgressID and Module Guid).\r
-  //\r
-  Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo);\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 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
+  // 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
-  //\r
-  // Get the number of PeiPerformanceLogEntries form PCD.\r
-  //\r
-  PeiPerformanceLogEntries = (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ?\r
-                                       PcdGet16 (PcdMaxPeiPerformanceLogEntries16) :\r
-                                       PcdGet8 (PcdMaxPeiPerformanceLogEntries));\r
-\r
-  //\r
-  // Create GUID HOB Data.\r
-  //\r
-  GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid);\r
-  PeiFirmwarePerformance = NULL;\r
-  while (GuidHob != NULL) {\r
-    //\r
-    // PEI Performance HOB was found, then return the existing one.\r
-    //\r
-    PeiFirmwarePerformance  = (UINT8*)GET_GUID_HOB_DATA (GuidHob);\r
-    PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance;\r
-    if (!PeiPerformanceLogHeader->HobIsFull && PeiPerformanceLogHeader->SizeOfAllEntries + RecordInfo.RecordSize > PeiPerformanceLogEntries * MAX_RECORD_SIZE) {\r
-      PeiPerformanceLogHeader->HobIsFull = TRUE;\r
-    }\r
-    if (!PeiPerformanceLogHeader->HobIsFull && PeiPerformanceLogHeader->SizeOfAllEntries + RecordInfo.RecordSize <= PeiPerformanceLogEntries * MAX_RECORD_SIZE) {\r
-      FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER) + PeiPerformanceLogHeader->SizeOfAllEntries);\r
-      break;\r
-    }\r
-    //\r
-    // Previous HOB is used, then find next one.\r
-    //\r
-    GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob));\r
-  }\r
-\r
-  if (GuidHob == NULL) {\r
+  if (Attribute != PerfEntry) {\r
     //\r
-    // PEI Performance HOB was not found, then build one.\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
-    PeiPerformanceSize      = sizeof (FPDT_PEI_EXT_PERF_HEADER) +\r
-                              MAX_RECORD_SIZE * PeiPerformanceLogEntries;\r
-    PeiFirmwarePerformance  = (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize);\r
-    if (PeiFirmwarePerformance != NULL) {\r
-      ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize);\r
+    if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {\r
+      return EFI_UNSUPPORTED;\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
+    } else if (PerfId == 0) {\r
+      Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &PerfId);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
     }\r
-    PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance;\r
-    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER));\r
   }\r
 \r
-  if (PeiFirmwarePerformance == NULL) {\r
-    //\r
-    // there is no enough resource to store performance data\r
-    //\r
-    return EFI_OUT_OF_RESOURCES;\r
+  //\r
+  // 2. Get the buffer to store the FPDT record.\r
+  //\r
+  Status = GetFpdtRecordPtr (PEI_MAX_RECORD_SIZE, &FpdtRecordPtr, &PeiPerformanceLogHeader);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
   //\r
-  // Get the TimeStamp.\r
+  // Get the TimeStamp.\r
   //\r
   if (Ticker == 0) {\r
     Ticker    = GetPerformanceCounter ();\r
@@ -353,70 +377,138 @@ InsertPeiFpdtMeasurement (
   }\r
 \r
   //\r
-  // Get the ModuleGuid.\r
+  // 4.Get the ModuleGuid.\r
   //\r
-  if (Handle != NULL) {\r
-    ModuleGuid = Handle;\r
+  if (CallerIdentifier != NULL) {\r
+    ModuleGuid = CallerIdentifier;\r
   } else {\r
     ModuleGuid = &gEfiCallerIdGuid;\r
   }\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 (EFI_GUID));\r
-    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;\r
+  //\r
+  // 5. Fill in the FPDT record according to different Performance Identifier.\r
+  //\r
+  switch (PerfId) {\r
+  case MODULE_START_ID:\r
+  case MODULE_END_ID:\r
+    StringPtr = PEIM_TOK;\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 (EFI_GUID));\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
-    PeiPerformanceLogHeader->LoadImageCount++;\r
-    FpdtRecordPtr.GuidQwordEvent->Qword           = PeiPerformanceLogHeader->LoadImageCount;\r
-    CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, ModuleGuid, sizeof (EFI_GUID));\r
-    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;\r
+  case MODULE_LOADIMAGE_START_ID:\r
+  case MODULE_LOADIMAGE_END_ID:\r
+    StringPtr = LOAD_IMAGE_TOK;\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
+      if (PerfId == MODULE_LOADIMAGE_START_ID) {\r
+        PeiPerformanceLogHeader->LoadImageCount++;\r
+      }\r
+      FpdtRecordPtr.GuidQwordEvent->Qword           = PeiPerformanceLogHeader->LoadImageCount;\r
+      CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, ModuleGuid, sizeof (EFI_GUID));\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 (EFI_GUID));\r
-    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;\r
-\r
-    if (Token != NULL) {\r
-      StringPtr                     = Token;\r
-    } else if (Module != NULL) {\r
-      StringPtr                     = Module;\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 && AsciiStrLen (String) != 0) {\r
+      StringPtr = String;\r
+    } else {\r
+      StringPtr = "unknown name";\r
     }\r
-    if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) {\r
-      DestMax                       = (RecordInfo.RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8);\r
-      StrLength                     = AsciiStrLen (StringPtr);\r
-      if (StrLength >= DestMax) {\r
-        StrLength                   = DestMax -1;\r
-      }\r
-      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength);\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, ModuleGuid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));\r
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));\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
+    if (String != NULL && AsciiStrLen (String) != 0) {\r
+      StringPtr = String;\r
     } else {\r
-      AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name");\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 (EFI_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 PEI phase, return EFI_ABORTED\r
-    //\r
-    return EFI_UNSUPPORTED;\r
+    if (Attribute != PerfEntry) {\r
+     if (String != NULL && AsciiStrLen (String) != 0) {\r
+       StringPtr = String;\r
+     } else {\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
+  // 5.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.\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
+    if (Guid != NULL) {\r
+      //\r
+      // Cache the event guid in string event record.\r
+      //\r
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (EFI_GUID));\r
+    } else {\r
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof (EFI_GUID));\r
+    }\r
+    CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);\r
   }\r
 \r
+  //\r
+  // 6. Update the length of the used buffer after fill in the record.\r
+  //\r
+  PeiPerformanceLogHeader->SizeOfAllEntries += FpdtRecordPtr.RecordHeader->Length;\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -454,7 +546,18 @@ StartPerformanceMeasurementEx (
   IN UINT32       Identifier\r
   )\r
 {\r
-  return InsertPeiFpdtMeasurement (TRUE, 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)InsertFpdtRecord (Handle, NULL, String, TimeStamp, 0, (UINT16)Identifier, PerfStartEntry);\r
+\r
 }\r
 \r
 /**\r
@@ -489,7 +592,17 @@ EndPerformanceMeasurementEx (
   IN UINT32       Identifier\r
   )\r
 {\r
-  return InsertPeiFpdtMeasurement (FALSE, 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)InsertFpdtRecord (Handle, NULL, String, TimeStamp, 0, (UINT16)Identifier, PerfEndEntry);\r
 }\r
 \r
 /**\r
@@ -582,7 +695,7 @@ StartPerformanceMeasurement (
   IN UINT64       TimeStamp\r
   )\r
 {\r
-  return InsertPeiFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, 0);\r
+  return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);\r
 }\r
 \r
 /**\r
@@ -614,7 +727,7 @@ EndPerformanceMeasurement (
   IN UINT64       TimeStamp\r
   )\r
 {\r
-  return InsertPeiFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, 0);\r
+  return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);\r
 }\r
 \r
 /**\r
@@ -692,3 +805,58 @@ 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)InsertFpdtRecord (CallerIdentifier, Guid, String, 0, Address, (UINT16)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