acpi: Add support for reporting CrashLog in BERT table

Crash Data are collected and sent to the OS via the ACPI BERT.

BUG=None
TEST=Built, and BERT successfully generated in the crashLog flow.

Signed-off-by: Francois Toguo <francois.toguo.fotso@intel.com>
Change-Id: I00e390d735d61beac2e89a726e39119d9b06b3df
Signed-off-by: Nikunj A. Dadhania <nikunj.dadhania@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/49799
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
diff --git a/src/arch/x86/acpi_bert_storage.c b/src/arch/x86/acpi_bert_storage.c
index de56291..ec31917 100644
--- a/src/arch/x86/acpi_bert_storage.c
+++ b/src/arch/x86/acpi_bert_storage.c
@@ -106,6 +106,7 @@
 	entries = bert_entry_count(status);
 	entry = acpi_hest_generic_data_nth(status, entries);
 	status->data_length += size;
+	status->raw_data_length += size;
 	if (entry)
 		entry->data_length += size;
 }
@@ -174,6 +175,7 @@
 	entry->validation_bits |= ACPI_GENERROR_VALID_TIMESTAMP;
 
 	status->data_length += sizeof(*entry);
+	status->raw_data_length += sizeof(*entry);
 	bert_bump_entry_count(status);
 
 	return entry;
@@ -186,12 +188,52 @@
 		return sizeof(cper_proc_generic_error_section_t);
 	else if (!guidcmp(guid, &CPER_SEC_PROC_IA32X64_GUID))
 		return sizeof(cper_ia32x64_proc_error_section_t);
+	else if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID))
+		return sizeof(cper_fw_err_rec_section_t);
 	/* else if ... sizeof(structures not yet defined) */
 
 	printk(BIOS_ERR, "Error: Requested size of unrecognized CPER GUID\n");
 	return 0;
 }
 
+void *new_cper_fw_error_crashlog(acpi_generic_error_status_t *status, size_t cl_size)
+{
+	void *cl_data = bert_allocate_storage(cl_size);
+	if (!cl_data) {
+		printk(BIOS_ERR, "Error: Crashlog entry (size %lu) would exceed available region\n",
+			cl_size);
+		return NULL;
+	}
+
+	revise_error_sizes(status, cl_size);
+
+	return cl_data;
+}
+
+/* Helper to append an ACPI Generic Error Data Entry per crashlog data */
+acpi_hest_generic_data_v300_t *bert_append_fw_err(acpi_generic_error_status_t *status)
+{
+	acpi_hest_generic_data_v300_t *entry;
+	cper_fw_err_rec_section_t *fw_err;
+
+	entry = bert_append_error_datasection(status, &CPER_SEC_FW_ERR_REC_REF_GUID);
+	if (!entry)
+		return NULL;
+
+	status->block_status |= GENERIC_ERR_STS_UNCORRECTABLE_VALID;
+	status->error_severity = ACPI_GENERROR_SEV_FATAL;
+	entry->error_severity = ACPI_GENERROR_SEV_FATAL;
+
+	fw_err = section_of_acpientry(fw_err, entry);
+
+	fw_err->record_type = CRASHLOG_RECORD_TYPE;
+	fw_err->revision = CRASHLOG_FW_ERR_REV;
+	fw_err->record_id = 0;
+	guidcpy(&fw_err->record_guid, &FW_ERR_RECORD_ID_CRASHLOG_GUID);
+
+	return entry;
+}
+
 /* Append a new ACPI Generic Error Data Entry plus CPER Error Section to an
  * existing ACPI Generic Error Status Block.  The caller is responsible for
  * the setting the status and entry severity, as well as populating all fields
@@ -486,10 +528,14 @@
 	if (!status)
 		return NULL;
 
+	status->raw_data_length = sizeof(*status);
+
 	if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))
 		r = bert_append_genproc(status);
 	else if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))
 		r = bert_append_ia32x64(status);
+	if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID))
+		r = bert_append_fw_err(status);
 	/* else if other types not implemented */
 	else
 		r = NULL;