Add support for NVIDIA CPERs

Support Nvidia CPER entries.

Change-Id: Iea9bde181ead55ad99cdb2a341501bf48e1d82a8
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/sections/cper-section-nvidia.c b/sections/cper-section-nvidia.c
new file mode 100644
index 0000000..f0ccec6
--- /dev/null
+++ b/sections/cper-section-nvidia.c
@@ -0,0 +1,100 @@
+/**
+ * Describes functions for converting NVIDIA CPER sections from binary and JSON format
+ * into an intermediate format.
+ **/
+
+#include <stdio.h>
+#include <string.h>
+#include <json.h>
+#include "../edk/Cper.h"
+#include "../cper-utils.h"
+#include "cper-section-nvidia.h"
+
+//Converts a single NVIDIA CPER section into JSON IR.
+json_object *cper_section_nvidia_to_ir(void *section)
+{
+	EFI_NVIDIA_ERROR_DATA *nvidia_error = (EFI_NVIDIA_ERROR_DATA *)section;
+	json_object *section_ir = json_object_new_object();
+
+	//Signature.
+	json_object_object_add(section_ir, "signature",
+			       json_object_new_string(nvidia_error->Signature));
+
+	//Fields.
+	json_object_object_add(section_ir, "errorType",
+			       json_object_new_int(nvidia_error->ErrorType));
+	json_object_object_add(
+		section_ir, "errorInstance",
+		json_object_new_int(nvidia_error->ErrorInstance));
+	json_object_object_add(section_ir, "severity",
+			       json_object_new_int(nvidia_error->Severity));
+	json_object_object_add(section_ir, "socket",
+			       json_object_new_int(nvidia_error->Socket));
+	json_object_object_add(section_ir, "numberRegs",
+			       json_object_new_int(nvidia_error->NumberRegs));
+	json_object_object_add(
+		section_ir, "instanceBase",
+		json_object_new_uint64(nvidia_error->InstanceBase));
+
+	// Registers (Address Value pairs).
+	json_object *regarr = json_object_new_array();
+	UINT64 *regPtr = &nvidia_error->InstanceBase;
+	for (int i = 0; i < nvidia_error->NumberRegs; i++) {
+		json_object *reg = json_object_new_object();
+		json_object_object_add(reg, "address",
+				       json_object_new_uint64(*++regPtr));
+		json_object_object_add(reg, "value",
+				       json_object_new_uint64(*++regPtr));
+		json_object_array_add(regarr, reg);
+	}
+	json_object_object_add(section_ir, "registers", regarr);
+
+	return section_ir;
+}
+
+//Converts a single NVIDIA CPER-JSON section into CPER binary, outputting to the given stream.
+void ir_section_nvidia_to_cper(json_object *section, FILE *out)
+{
+	json_object *regarr = json_object_object_get(section, "registers");
+	int numRegs = json_object_array_length(regarr);
+
+	size_t section_sz =
+		sizeof(EFI_NVIDIA_ERROR_DATA) + (numRegs * 2 * sizeof(UINT64));
+	EFI_NVIDIA_ERROR_DATA *section_cper =
+		(EFI_NVIDIA_ERROR_DATA *)calloc(1, section_sz);
+
+	//Signature.
+	strncpy(section_cper->Signature,
+		json_object_get_string(
+			json_object_object_get(section, "signature")),
+		sizeof(section_cper->Signature));
+
+	//Fields.
+	section_cper->ErrorType = json_object_get_int(
+		json_object_object_get(section, "errorType"));
+	section_cper->ErrorInstance = json_object_get_int(
+		json_object_object_get(section, "errorInstance"));
+	section_cper->Severity = json_object_get_int(
+		json_object_object_get(section, "severity"));
+	section_cper->Socket =
+		json_object_get_int(json_object_object_get(section, "socket"));
+	section_cper->NumberRegs = json_object_get_int(
+		json_object_object_get(section, "numberRegs"));
+	section_cper->InstanceBase = json_object_get_uint64(
+		json_object_object_get(section, "instanceBase"));
+
+	// Registers (Address Value pairs).
+	UINT64 *regPtr = &section_cper->InstanceBase;
+	for (int i = 0; i < numRegs; i++) {
+		json_object *reg = json_object_array_get_idx(regarr, i);
+		*++regPtr = json_object_get_uint64(
+			json_object_object_get(reg, "address"));
+		*++regPtr = json_object_get_uint64(
+			json_object_object_get(reg, "value"));
+	}
+
+	//Write to stream, free resources.
+	fwrite(section_cper, section_sz, 1, out);
+	fflush(out);
+	free(section_cper);
+}
diff --git a/sections/cper-section-nvidia.h b/sections/cper-section-nvidia.h
new file mode 100644
index 0000000..973c3af
--- /dev/null
+++ b/sections/cper-section-nvidia.h
@@ -0,0 +1,10 @@
+#ifndef CPER_SECTION_NVIDIA_H
+#define CPER_SECTION_NVIDIA_H
+
+#include <json.h>
+#include "../edk/Cper.h"
+
+json_object *cper_section_nvidia_to_ir(void *section);
+void ir_section_nvidia_to_cper(json_object *section, FILE *out);
+
+#endif
diff --git a/sections/cper-section.c b/sections/cper-section.c
index 9352800..1845118 100644
--- a/sections/cper-section.c
+++ b/sections/cper-section.c
@@ -20,6 +20,7 @@
 #include "cper-section-ccix-per.h"
 #include "cper-section-cxl-protocol.h"
 #include "cper-section-cxl-component.h"
+#include "cper-section-nvidia.h"
 
 //Definitions of all sections available to the CPER parser.
 CPER_SECTION_DEFINITION section_definitions[] = {
@@ -69,6 +70,8 @@
 	  cper_section_cxl_component_to_ir, ir_section_cxl_component_to_cper },
 	{ &gEfiCxlMldPortErrorSectionGuid, "CXL MLD Port Component Error",
 	  cper_section_cxl_component_to_ir, ir_section_cxl_component_to_cper },
+	{ &gEfiNvidiaErrorSectionGuid, "NVIDIA", cper_section_nvidia_to_ir,
+	  ir_section_nvidia_to_cper },
 };
 const size_t section_definitions_len =
 	sizeof(section_definitions) / sizeof(CPER_SECTION_DEFINITION);