Add CCIX PER section support.
diff --git a/cper-parse.c b/cper-parse.c
index 6c743a1..a9c7bdc 100644
--- a/cper-parse.c
+++ b/cper-parse.c
@@ -21,6 +21,7 @@
 #include "sections/cper-section-dmar-generic.h"
 #include "sections/cper-section-dmar-vtd.h"
 #include "sections/cper-section-dmar-iommu.h"
+#include "sections/cper-section-ccix-per.h"
 
 //Private pre-definitions.
 json_object* cper_header_to_ir(EFI_COMMON_ERROR_RECORD_HEADER* header);
@@ -239,29 +240,31 @@
     char* section_type_readable = "Unknown";
     if (guid_equal(&section_descriptor->SectionType, &gEfiProcessorGenericErrorSectionGuid))
         section_type_readable = "Processor Generic";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiIa32X64ProcessorErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiIa32X64ProcessorErrorSectionGuid))
         section_type_readable = "IA32/X64";
     //todo: Why does IPF have an overly long GUID?
     // if (guid_equal(&section_descriptor->SectionType, &gEfiIpfProcessorErrorSectionGuid))
     //     section_type_readable = "IPF";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiArmProcessorErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiArmProcessorErrorSectionGuid))
         section_type_readable = "ARM";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiPlatformMemoryErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiPlatformMemoryErrorSectionGuid))
         section_type_readable = "Platform Memory";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiPcieErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiPcieErrorSectionGuid))
         section_type_readable = "PCIe";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiFirmwareErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiFirmwareErrorSectionGuid))
         section_type_readable = "Firmware Error Record Reference";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiPciBusErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiPciBusErrorSectionGuid))
         section_type_readable = "PCI/PCI-X Bus";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiPciDevErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiPciDevErrorSectionGuid))
         section_type_readable = "PCI Component/Device";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiDMArGenericErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiDMArGenericErrorSectionGuid))
         section_type_readable = "DMAr Generic";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiDirectedIoDMArErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiDirectedIoDMArErrorSectionGuid))
         section_type_readable = "Intel VT for Directed I/O specific DMAr section";
-    if (guid_equal(&section_descriptor->SectionType, &gEfiIommuDMArErrorSectionGuid))
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiIommuDMArErrorSectionGuid))
         section_type_readable = "IOMMU specific DMAr section";
+    else if (guid_equal(&section_descriptor->SectionType, &gEfiCcixPerLogErrorSectionGuid))
+        section_type_readable = "CCIX PER Log Error";
 
     //todo: How do you determine if this is a CXL component event?
     // if (guid_equal(&section_descriptor->SectionType, &gEfiProcessorGenericErrorSectionGuid))
@@ -333,6 +336,8 @@
         result = cper_section_dmar_vtd_to_ir(section, descriptor);
     else if (guid_equal(&descriptor->SectionType, &gEfiIommuDMArErrorSectionGuid))
         result = cper_section_dmar_iommu_to_ir(section, descriptor);
+    else if (guid_equal(&descriptor->SectionType, &gEfiCcixPerLogErrorSectionGuid))
+        result = cper_section_ccix_per_to_ir(section, descriptor);
     else
     {
         //Failed read, unknown GUID.
diff --git a/edk/Cper.c b/edk/Cper.c
index d11dfdd..dfed1ae 100644
--- a/edk/Cper.c
+++ b/edk/Cper.c
@@ -35,6 +35,7 @@
 EFI_GUID gEfiDMArGenericErrorSectionGuid    = { 0x5b51fef7, 0xc79d, 0x4434, { 0x8f, 0x1b, 0xaa, 0x62, 0xde, 0x3e, 0x2c, 0x64 }};
 EFI_GUID gEfiDirectedIoDMArErrorSectionGuid = { 0x71761d37, 0x32b2, 0x45cd, { 0xa7, 0xd0, 0xb0, 0xfe, 0xdd, 0x93, 0xe8, 0xcf }};
 EFI_GUID gEfiIommuDMArErrorSectionGuid      = { 0x036f84e1, 0x7f37, 0x428c, { 0xa7, 0x9e, 0x57, 0x5f, 0xdf, 0xaa, 0x84, 0xec }};
+EFI_GUID gEfiCcixPerLogErrorSectionGuid     = { 0x91335EF6, 0xEBFB, 0x4478, {0xA6, 0xA6, 0x88, 0xB7, 0x28, 0xCF, 0x75, 0xD7 }};
 
 //IA32/x64 error segment GUIDs.
 EFI_GUID gEfiIa32x64ErrorTypeCacheCheckGuid = { 0xA55701F5, 0xE3EF, 0x43de, {0xAC, 0x72, 0x24, 0x9B, 0x57, 0x3F, 0xAD, 0x2C } };
diff --git a/edk/Cper.h b/edk/Cper.h
index 4eb470d..a2e2fb6 100644
--- a/edk/Cper.h
+++ b/edk/Cper.h
@@ -1265,7 +1265,7 @@
 extern EFI_GUID   gEfiDMArGenericErrorSectionGuid;

 extern EFI_GUID   gEfiDirectedIoDMArErrorSectionGuid;

 extern EFI_GUID   gEfiIommuDMArErrorSectionGuid;

-

+extern EFI_GUID   gEfiCcixPerLogErrorSectionGuid;

 #pragma pack()

 

 #if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)

diff --git a/sections/cper-section-ccix-per.c b/sections/cper-section-ccix-per.c
new file mode 100644
index 0000000..ae8a797
--- /dev/null
+++ b/sections/cper-section-ccix-per.c
@@ -0,0 +1,35 @@
+/**
+ * Describes functions for converting CCIX PER log CPER sections from binary and JSON format
+ * into an intermediate format.
+ * 
+ * Author: Lawrence.Tang@arm.com
+ **/
+#include <stdio.h>
+#include "json.h"
+#include "../edk/Cper.h"
+#include "../cper-utils.h"
+#include "cper-section-ccix-per.h"
+
+//Converts a single CCIX PER log CPER section into JSON IR.
+json_object* cper_section_ccix_per_to_ir(void* section, EFI_ERROR_SECTION_DESCRIPTOR* descriptor)
+{
+    EFI_CCIX_PER_LOG_DATA* ccix_error = (EFI_CCIX_PER_LOG_DATA*)section;
+    json_object* section_ir = json_object_new_object();
+
+    //Length (bytes) for the entire structure.
+    json_object_object_add(section_ir, "length", json_object_new_uint64(ccix_error->Length));
+
+    //Validation bits.
+    json_object* validation = bitfield_to_ir(ccix_error->ValidBits, 3, CCIX_PER_ERROR_VALID_BITFIELD_NAMES);
+    json_object_object_add(section_ir, "validationBits", validation);
+
+    //CCIX source/port IDs.
+    json_object_object_add(section_ir, "ccixSourceID", json_object_new_int(ccix_error->CcixSourceId));
+    json_object_object_add(section_ir, "ccixPortID", json_object_new_int(ccix_error->CcixPortId));
+    
+    //CCIX PER Log.
+    //todo: implement as described in Section 7.3.2 of CCIX Base Specification (Rev 1.0)
+    //the PER Log structure notes the number of DWORDs in the record.
+
+    return section_ir;
+}
\ No newline at end of file
diff --git a/sections/cper-section-ccix-per.h b/sections/cper-section-ccix-per.h
new file mode 100644
index 0000000..1f01368
--- /dev/null
+++ b/sections/cper-section-ccix-per.h
@@ -0,0 +1,22 @@
+#ifndef CPER_SECTION_CCIX_PER_H
+#define CPER_SECTION_CCIX_PER_H
+
+#include "json.h"
+#include "../edk/Cper.h"
+
+#define CCIX_PER_ERROR_VALID_BITFIELD_NAMES (const char*[]) {"ccixSourceIDValid", "ccixPortIDValid", "ccixPERLogValid"}
+
+///
+/// CCIX PER Log Error Section
+///
+typedef struct {
+    UINT32 Length;
+    UINT64 ValidBits;
+    UINT8 CcixSourceId;
+    UINT8 CcixPortId;
+    UINT16 Reserved;
+} EFI_CCIX_PER_LOG_DATA;
+
+json_object* cper_section_ccix_per_to_ir(void* section, EFI_ERROR_SECTION_DESCRIPTOR* descriptor);
+
+#endif
\ No newline at end of file