Add initial IPF support.
diff --git a/sections/cper-section-ipf.c b/sections/cper-section-ipf.c
index 0cbfb6b..c0781f8 100644
--- a/sections/cper-section-ipf.c
+++ b/sections/cper-section-ipf.c
@@ -10,8 +10,99 @@
 #include "../cper-utils.h"
 #include "cper-section-ipf.h"
 
+json_object* cper_ipf_mod_error_read_array(EFI_IPF_MOD_ERROR_INFO** cur_error, int num_to_read);
+json_object* cper_ipf_mod_error_to_ir(EFI_IPF_MOD_ERROR_INFO* mod_error);
+
 //Converts a single Intel IPF error CPER section into JSON IR.
 json_object* cper_section_ipf_to_ir(void* section, EFI_ERROR_SECTION_DESCRIPTOR* descriptor)
 {
-    //... todo ...
+    EFI_IPF_ERROR_INFO_HEADER* ipf_error = (EFI_IPF_ERROR_INFO_HEADER*)section;
+    json_object* section_ir = json_object_new_object();
+
+    //Validation bits.
+    json_object* validation = json_object_new_object();
+    json_object_object_add(validation, "errorMapValid", json_object_new_boolean(ipf_error->ValidBits.ProcErrorMapValid));
+    json_object_object_add(validation, "stateParameterValid", json_object_new_boolean(ipf_error->ValidBits.ProcErrorMapValid));
+    json_object_object_add(validation, "crLIDValid", json_object_new_boolean(ipf_error->ValidBits.ProcCrLidValid));
+    json_object_object_add(validation, "psiStaticStructValid", json_object_new_boolean(ipf_error->ValidBits.PsiStaticStructValid));
+    json_object_object_add(validation, "cpuInfoValid", json_object_new_boolean(ipf_error->ValidBits.CpuIdInfoValid));
+    json_object_object_add(section_ir, "validationBits", validation);
+
+    //Numbers of various variable length segments.
+    json_object_object_add(section_ir, "cacheCheckNum", json_object_new_uint64(ipf_error->ValidBits.CacheCheckNum));
+    json_object_object_add(section_ir, "tlbCheckNum", json_object_new_uint64(ipf_error->ValidBits.TlbCheckNum));
+    json_object_object_add(section_ir, "busCheckNum", json_object_new_uint64(ipf_error->ValidBits.BusCheckNum));
+    json_object_object_add(section_ir, "regFileCheckNum", json_object_new_uint64(ipf_error->ValidBits.RegFileCheckNum));
+    json_object_object_add(section_ir, "msCheckNum", json_object_new_uint64(ipf_error->ValidBits.MsCheckNum));
+
+    //Process error map, state params/CR LID.
+    json_object_object_add(section_ir, "procErrorMap", json_object_new_uint64(ipf_error->ProcErrorMap));
+    json_object_object_add(section_ir, "procStateParameter", json_object_new_uint64(ipf_error->ProcStateParameter));
+    json_object_object_add(section_ir, "procCRLID", json_object_new_uint64(ipf_error->ProcCrLid));
+
+    //Read cache, TLB, bus, register file, MS errors.
+    EFI_IPF_MOD_ERROR_INFO* cur_error = (EFI_IPF_MOD_ERROR_INFO*)(ipf_error + 1);
+    json_object_object_add(section_ir, "cacheErrors", cper_ipf_mod_error_read_array(&cur_error, ipf_error->ValidBits.CacheCheckNum));
+    json_object_object_add(section_ir, "tlbErrors", cper_ipf_mod_error_read_array(&cur_error, ipf_error->ValidBits.TlbCheckNum));
+    json_object_object_add(section_ir, "busErrors", cper_ipf_mod_error_read_array(&cur_error, ipf_error->ValidBits.BusCheckNum));
+    json_object_object_add(section_ir, "regFileErrors", cper_ipf_mod_error_read_array(&cur_error, ipf_error->ValidBits.RegFileCheckNum));
+    json_object_object_add(section_ir, "msErrors", cper_ipf_mod_error_read_array(&cur_error, ipf_error->ValidBits.MsCheckNum));
+    
+    //CPU ID information.
+    EFI_IPF_CPU_INFO* cpu_info = (EFI_IPF_CPU_INFO*)cur_error;
+    //todo: find out how this is represented
+
+    //Processor static information.
+    EFI_IPF_PSI_STATIC* psi_static = (EFI_IPF_PSI_STATIC*)(cpu_info + 1);
+    json_object* psi_static_ir = json_object_new_object();
+    
+    //PSI validation bits.
+    json_object* psi_validation = bitfield_to_ir(psi_static->ValidBits, 6, IPF_PSI_STATIC_INFO_VALID_BITFIELD_NAMES);
+    json_object_object_add(psi_static_ir, "validationBits", psi_validation);
+
+    //PSI minimal state save info.
+    //todo: structure min save state area as in Intel Itanium Architecture Software Developer's Manual.
+
+    //BRs, CRs, ARs, RRs, FRs.
+    json_object_object_add(psi_static_ir, "brs", uint64_array_to_ir_array(psi_static->Brs, 8));
+    json_object_object_add(psi_static_ir, "crs", uint64_array_to_ir_array(psi_static->Crs, 128));
+    json_object_object_add(psi_static_ir, "ars", uint64_array_to_ir_array(psi_static->Ars, 128));
+    json_object_object_add(psi_static_ir, "rrs", uint64_array_to_ir_array(psi_static->Rrs, 8));
+    json_object_object_add(psi_static_ir, "frs", uint64_array_to_ir_array(psi_static->Frs, 256));
+    json_object_object_add(section_ir, "psiStaticInfo", psi_static_ir);
+
+    return section_ir;
+}
+
+//Reads a continuous stream of CPER IPF mod errors beginning from the given pointer, for n entries.
+//Returns an array containing all read entries as JSON IR.
+json_object* cper_ipf_mod_error_read_array(EFI_IPF_MOD_ERROR_INFO** cur_error, int num_to_read)
+{
+    json_object* error_array = json_object_new_array();
+    for (int i=0; i<num_to_read; i++)
+    {
+        json_object_array_add(error_array, cper_ipf_mod_error_to_ir(*cur_error));
+        *cur_error = *cur_error + 1;
+    }
+
+    return error_array;
+}
+
+//Converts a single CPER IPF mod error info structure into JSON IR.
+json_object* cper_ipf_mod_error_to_ir(EFI_IPF_MOD_ERROR_INFO* mod_error)
+{
+    json_object* mod_error_ir = json_object_new_object();
+    
+    //Validation bits.
+    json_object* validation = bitfield_to_ir(mod_error->ValidBits, 5, IPF_MOD_ERROR_VALID_BITFIELD_NAMES);
+    json_object_object_add(mod_error_ir, "validationBits", validation);
+
+    //Numeric fields.
+    json_object_object_add(mod_error_ir, "modCheckInfo", json_object_new_uint64(mod_error->ModCheckInfo));
+    json_object_object_add(mod_error_ir, "modTargetID", json_object_new_uint64(mod_error->ModTargetId));
+    json_object_object_add(mod_error_ir, "modRequestorID", json_object_new_uint64(mod_error->ModRequestorId));
+    json_object_object_add(mod_error_ir, "modResponderID", json_object_new_uint64(mod_error->ModResponderId));
+    json_object_object_add(mod_error_ir, "modPreciseIP", json_object_new_uint64(mod_error->ModPreciseIp));
+
+    return mod_error_ir;
 }
\ No newline at end of file
diff --git a/sections/cper-section-ipf.h b/sections/cper-section-ipf.h
index 8083ff0..2ba4182 100644
--- a/sections/cper-section-ipf.h
+++ b/sections/cper-section-ipf.h
@@ -4,6 +4,11 @@
 #include "json.h"
 #include "../edk/Cper.h"
 
+#define IPF_MOD_ERROR_VALID_BITFIELD_NAMES (const char*[]) {"checkInfoValid", "requestorIdentifierValid", \
+    "responderIdentifierValid", "targetIdentifierValid", "preciseIPValid"}
+#define IPF_PSI_STATIC_INFO_VALID_BITFIELD_NAMES (const char*[]) {"minstateValid", "brValid", "crValid", \
+    "arValid", "rrValid", "frValid"}
+
 ///
 /// IPF Error Record Section
 /// Defined as according to B.2.3 of the ItaniumTM Processor Family System Abstraction Layer (SAL) Specification.
@@ -33,7 +38,7 @@
     UINT64 ValidBits;
     UINT64 ModCheckInfo;
     UINT64 ModTargetId;
-    UINT64 ModRequestorId;
+    UINT64 ModRequestorId; //todo: Which way around are these? Spec has a typo
     UINT64 ModResponderId;
     UINT64 ModPreciseIp;
 } EFI_IPF_MOD_ERROR_INFO;
@@ -41,13 +46,17 @@
 typedef struct {
     UINT8 CpuIdInfo[40];
     UINT8 Reserved1[8];
+} EFI_IPF_CPU_INFO;
+
+typedef struct {
     UINT64 ValidBits;
     UINT8 MinimalSaveStateInfo[1024];
-    UINT8 Brs[64];
-    UINT8 Crs[1024];
-    UINT8 Rrs[64];
-    UINT8 Frs[2048];
-} EFI_IPF_ERROR_INFO_FOOTER;
+    UINT64 Brs[8];
+    UINT64 Crs[128];
+    UINT64 Ars[128];
+    UINT64 Rrs[8];
+    UINT64 Frs[256];
+} EFI_IPF_PSI_STATIC;
 
 json_object* cper_section_ipf_to_ir(void* section, EFI_ERROR_SECTION_DESCRIPTOR* descriptor);