<p>Marshall Dawson has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/28470">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">arch/x86: Add BERT region support functions<br><br>Add code for generating the region pointed to in an ACPI Boot Error<br>Record Table.<br><br>The BERT region must be reported as Reserved to the OSPM, so this<br>code calls out to a system-specific region locator.  cbmem is<br>reported as type 16 and is not usable for the BERT region.<br><br>Events reported via BERT are Generic Error Data, and are constructed<br>as follows (see ACPI and UEFI specs for reference):<br> * Each event begins with a Generic Error Status Block, which may<br>   contain zero or more Generic Data Entries<br> * Each Generic Data Entry is identifiable by its Section Type field,<br>   and the data structures associated are also in the UEFI spec.<br>     * The GUIDs are listed in the Section Type field of the CPER<br>       Section Descriptor structure.  BERT doesn't use this structure<br>       but simply uses its GUIDs.<br>     * Data structures used in the Generic Data Entry are named as<br>       Error Sections in the UEFI spec.<br>         * Some sections may optionally include a variable number of<br>           additional structures, e.g. an IA32/X64 processor error<br>           can report error information as well as machine contexts.<br><br>It is worth noting that the Linux kernel (as of v4.4) does not attempt<br>to parse IA32/X64 sections, and opts to hexdump them instead.<br><br>BUG=b:65446699<br>TEST=inspect BERT region, and dmesg, on full patch stack.  Use test<br>     data plus a failing Grunt system.<br><br>Change-Id: I54826981639b5647a8ca33b8b55ff097681402b9<br>Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com><br>---<br>M src/Kconfig<br>M src/arch/x86/Makefile.inc<br>A src/arch/x86/acpi_bert_storage.c<br>A src/arch/x86/include/arch/bert_storage.h<br>4 files changed, 716 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/70/28470/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/Kconfig b/src/Kconfig</span><br><span>index bce3e32..ca75c0b 100644</span><br><span>--- a/src/Kconfig</span><br><span>+++ b/src/Kconfig</span><br><span>@@ -586,6 +586,12 @@</span><br><span>      help</span><br><span>           Build support for NHLT (non HD Audio) ACPI table generation.</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+config ACPI_BERT</span><br><span style="color: hsl(120, 100%, 40%);">+  bool</span><br><span style="color: hsl(120, 100%, 40%);">+  depends on HAVE_ACPI_TABLES</span><br><span style="color: hsl(120, 100%, 40%);">+   help</span><br><span style="color: hsl(120, 100%, 40%);">+    Build an ACPI Boot Error Record Table.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #These Options are here to avoid "undefined" warnings.</span><br><span> #The actual selection and help texts are in the following menu.</span><br><span> </span><br><span>diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc</span><br><span>index 1d9ee4d..3c4bc1f 100644</span><br><span>--- a/src/arch/x86/Makefile.inc</span><br><span>+++ b/src/arch/x86/Makefile.inc</span><br><span>@@ -291,6 +291,7 @@</span><br><span> ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi_device.c</span><br><span> ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi_pld.c</span><br><span> ramstage-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.c</span><br><span style="color: hsl(120, 100%, 40%);">+ramstage-$(CONFIG_ACPI_BERT) += acpi_bert_storage.c</span><br><span> ramstage-y += boot.c</span><br><span> ramstage-y += c_start.S</span><br><span> ramstage-y += cbmem.c</span><br><span>diff --git a/src/arch/x86/acpi_bert_storage.c b/src/arch/x86/acpi_bert_storage.c</span><br><span>new file mode 100644</span><br><span>index 0000000..826c14c</span><br><span>--- /dev/null</span><br><span>+++ b/src/arch/x86/acpi_bert_storage.c</span><br><span>@@ -0,0 +1,542 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * This file is part of the coreboot project.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright 2015 Google Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; version 2 of the License.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <bootstate.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <cbmem.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <console/console.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <cpu/x86/name.h> /* todo: support on other architectures */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <cpu/x86/msr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <cpu/x86/lapic.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arch/acpi.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arch/bert_storage.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* BERT region management:  Allow the chipset to determine the specific</span><br><span style="color: hsl(120, 100%, 40%);">+ * location of the BERT region.  We find that base and size, then manage</span><br><span style="color: hsl(120, 100%, 40%);">+ * the allocation of error information within it.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Use simple static variables for managing the BERT region.  This is a thin</span><br><span style="color: hsl(120, 100%, 40%);">+ * implementation; it is only created and consumed by coreboot, and only in</span><br><span style="color: hsl(120, 100%, 40%);">+ * a single stage, and we don't want its information to survive reboot or</span><br><span style="color: hsl(120, 100%, 40%);">+ * resume cycles.  If the requirements change, consider using IMD to help</span><br><span style="color: hsl(120, 100%, 40%);">+ * manage the space.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int bert_region_broken;</span><br><span style="color: hsl(120, 100%, 40%);">+static void *bert_region_base;</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t bert_region_size;</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t bert_region_used;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Calculate the remaining space in the BERT region.  This knowledge may help</span><br><span style="color: hsl(120, 100%, 40%);">+ * the caller prioritize the information to store.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+size_t bert_storage_remaining(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return bert_region_broken ? 0 : bert_region_size - bert_region_used;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int bert_errors_present(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return bert_region_broken ? 0 : !!bert_region_used;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void bert_errors_region(void **start, size_t *size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (bert_region_broken) {</span><br><span style="color: hsl(120, 100%, 40%);">+             *start = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                *size = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* No metadata, etc. with our region, so this is easy */</span><br><span style="color: hsl(120, 100%, 40%);">+      *start = bert_region_base;</span><br><span style="color: hsl(120, 100%, 40%);">+    *size = bert_region_used;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *bert_allocate_storage(size_t size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    size_t alloc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bert_region_broken)</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (bert_region_used + size > bert_region_size)</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        alloc = bert_region_used;</span><br><span style="color: hsl(120, 100%, 40%);">+     bert_region_used += size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return (void *)((u8 *)bert_region_base + alloc);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Generic Error Status:  Each Status represents a unique error event within</span><br><span style="color: hsl(120, 100%, 40%);">+ * the BERT errors region.  Each event may have multiple errors associated</span><br><span style="color: hsl(120, 100%, 40%);">+ * with it.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Update data_length for this Error Status, and final Data Entry it contains */</span><br><span style="color: hsl(120, 100%, 40%);">+static void revise_error_sizes(acpi_generic_error_status_t *status, size_t size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    acpi_hest_generic_data_v300_t *entry;</span><br><span style="color: hsl(120, 100%, 40%);">+ int entries;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!status)</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     entries = bert_entry_count(status);</span><br><span style="color: hsl(120, 100%, 40%);">+   entry = acpi_hest_generic_data_nth(status, entries);</span><br><span style="color: hsl(120, 100%, 40%);">+  status->data_length += size;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (entry)</span><br><span style="color: hsl(120, 100%, 40%);">+            entry->data_length += size;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Create space for a new BERT Generic Error Status Block, by finding the next</span><br><span style="color: hsl(120, 100%, 40%);">+ * available slot and moving the ending location.  There is nothing to designate</span><br><span style="color: hsl(120, 100%, 40%);">+ * this as another Generic Error Status Block (e.g. no signature); only that it</span><br><span style="color: hsl(120, 100%, 40%);">+ * is within the BERT region.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * It is up to the caller to correctly fill the information, including status</span><br><span style="color: hsl(120, 100%, 40%);">+ * and error severity, and to update/maintain data offsets and lengths as</span><br><span style="color: hsl(120, 100%, 40%);">+ * entries are added.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static acpi_generic_error_status_t *new_bert_status(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ acpi_generic_error_status_t *status;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        status = bert_allocate_storage(sizeof(*status));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!status) {</span><br><span style="color: hsl(120, 100%, 40%);">+                printk(BIOS_ERR, "Error: New BERT error entry would exceed available region\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   status->error_severity = ACPI_GENERROR_SEV_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+   return status;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Generic Error Data:  Each Generic Error Status may contain zero or more</span><br><span style="color: hsl(120, 100%, 40%);">+ * Generic Error Data structures.  The data structures describe particular</span><br><span style="color: hsl(120, 100%, 40%);">+ * error(s) associated with an event.  The definition for the structure is</span><br><span style="color: hsl(120, 100%, 40%);">+ * found in the ACPI spec, however the data types and any accompanying data</span><br><span style="color: hsl(120, 100%, 40%);">+ * definitions are in the Common Platform Error Record appendix of the UEFI</span><br><span style="color: hsl(120, 100%, 40%);">+ * spec.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Create space for a new BERT Generic Data Entry.  Update the count and</span><br><span style="color: hsl(120, 100%, 40%);">+ * data length in the parent Generic Error Status Block.  Version 0x300 of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the structure is used, and the timestamp is filled and marked precise</span><br><span style="color: hsl(120, 100%, 40%);">+ * (i.e. assumed close enough for reporting).</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * It is up to the caller to fill the Section Type field and add the Common</span><br><span style="color: hsl(120, 100%, 40%);">+ * Platform Error Record type data as appropriate.  In addition, the caller</span><br><span style="color: hsl(120, 100%, 40%);">+ * should update the error severity, and may optionally add FRU information</span><br><span style="color: hsl(120, 100%, 40%);">+ * or override any existing information.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static acpi_hest_generic_data_v300_t *new_generic_error_entry(</span><br><span style="color: hsl(120, 100%, 40%);">+           acpi_generic_error_status_t *status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       acpi_hest_generic_data_v300_t *entry;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bert_entry_count(status) == GENERIC_ERR_STS_ENTRY_COUNT_MAX) {</span><br><span style="color: hsl(120, 100%, 40%);">+            printk(BIOS_ERR, "Error: New BERT error would exceed maximum entries\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   entry = bert_allocate_storage(sizeof(*entry));</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "Error: New BERT error entry would exceed available region\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   entry->revision = HEST_GENERIC_ENTRY_V300;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       entry->timestamp = cper_timestamp(CPER_TIMESTAMP_PRECISE);</span><br><span style="color: hsl(120, 100%, 40%);">+ entry->validation_bits |= ACPI_GENERROR_VALID_TIMESTAMP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ status->data_length += sizeof(*entry);</span><br><span style="color: hsl(120, 100%, 40%);">+     bert_bump_entry_count(status);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return entry;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Find the size of a CPER error section w/o any add-ons */</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t sizeof_error_section(guid_t *guid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+          return sizeof(cper_proc_generic_error_section_t);</span><br><span style="color: hsl(120, 100%, 40%);">+     else if (!guidcmp(guid, &CPER_SEC_PROC_IA32X64_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+             return sizeof(cper_ia32x64_proc_error_section_t);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* else if ... sizeof(structures not yet defined) */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        printk(BIOS_ERR, "Error: requested size of unrecognized CPER GUID\n");</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Append a new ACPI Generic Error Data Entry plus CPER Error Section to an</span><br><span style="color: hsl(120, 100%, 40%);">+ * existing ACPI Generic Error Status Block.  The caller is responsible for</span><br><span style="color: hsl(120, 100%, 40%);">+ * the setting the status and entry severity, as well as populating all fields</span><br><span style="color: hsl(120, 100%, 40%);">+ * of the error section.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+acpi_hest_generic_data_v300_t *bert_append_error_datasection(</span><br><span style="color: hsl(120, 100%, 40%);">+                acpi_generic_error_status_t *status, guid_t *guid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ acpi_hest_generic_data_v300_t *entry;</span><br><span style="color: hsl(120, 100%, 40%);">+ void *sect;</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t sect_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sect_size = sizeof_error_section(guid);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!sect_size)</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL; /* Don't allocate structure if bad GUID passed */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (sizeof(*entry) + sect_size > bert_storage_remaining())</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        entry = new_generic_error_entry(status);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!entry)</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* error section immediately follows the Generic Error Data Entry */</span><br><span style="color: hsl(120, 100%, 40%);">+  sect = bert_allocate_storage(sect_size);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!sect)</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        revise_error_sizes(status, sect_size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      guidcpy(&entry->section_type, guid);</span><br><span style="color: hsl(120, 100%, 40%);">+   return entry;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper to append an ACPI Generic Error Data Entry plus a CPER Processor</span><br><span style="color: hsl(120, 100%, 40%);">+ * Generic Error Section.  As many fields are populated as possible for the</span><br><span style="color: hsl(120, 100%, 40%);">+ * caller.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+acpi_hest_generic_data_v300_t *bert_append_genproc(</span><br><span style="color: hsl(120, 100%, 40%);">+             acpi_generic_error_status_t *status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       acpi_hest_generic_data_v300_t *entry;</span><br><span style="color: hsl(120, 100%, 40%);">+ cper_proc_generic_error_section_t *ges;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     entry = bert_append_error_datasection(status,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 &CPER_SEC_PROC_GENERIC_GUID);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!entry)</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        status->block_status |= GENERIC_ERR_STS_UNCORRECTABLE_VALID;</span><br><span style="color: hsl(120, 100%, 40%);">+       status->error_severity = ACPI_GENERROR_SEV_FATAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        entry->error_severity = ACPI_GENERROR_SEV_FATAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ges = section_of_acpientry(ges, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ges->proc_type = GENPROC_PROCTYPE_IA32X64;</span><br><span style="color: hsl(120, 100%, 40%);">+ ges->validation |= GENPROC_VALID_PROC_TYPE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ges->cpu_version = cpuid_eax(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   ges->validation |= GENPROC_VALID_CPU_VERSION;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    fill_processor_name(ges->cpu_brand_string);</span><br><span style="color: hsl(120, 100%, 40%);">+        ges->validation |= GENPROC_VALID_CPU_BRAND;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ges->proc_id = lapicid();</span><br><span style="color: hsl(120, 100%, 40%);">+  ges->validation |= GENPROC_VALID_CPU_ID;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return entry;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Add a new IA32/X64 Processor Context Structure (Table 261), following any</span><br><span style="color: hsl(120, 100%, 40%);">+ * other contexts, to an existing Processor Error Section (Table 255).  Contexts</span><br><span style="color: hsl(120, 100%, 40%);">+ * may only be added after the entire Processor Error Info array has been</span><br><span style="color: hsl(120, 100%, 40%);">+ * created.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function fills only the minimal amount of information required to parse</span><br><span style="color: hsl(120, 100%, 40%);">+ * or step through the contexts.  The type is filled and PROC_CONTEXT_INFO_NUM</span><br><span style="color: hsl(120, 100%, 40%);">+ * is updated.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * type is one of:</span><br><span style="color: hsl(120, 100%, 40%);">+ *   CPER_IA32X64_CTX_UNCL</span><br><span style="color: hsl(120, 100%, 40%);">+ *   CPER_IA32X64_CTX_MSR</span><br><span style="color: hsl(120, 100%, 40%);">+ *   CPER_IA32X64_CTX_32BIT_EX</span><br><span style="color: hsl(120, 100%, 40%);">+ *   CPER_IA32X64_CTX_64BIT_EX</span><br><span style="color: hsl(120, 100%, 40%);">+ *   CPER_IA32X64_CTX_FXSAVE</span><br><span style="color: hsl(120, 100%, 40%);">+ *   CPER_IA32X64_CTX_32BIT_DBG</span><br><span style="color: hsl(120, 100%, 40%);">+ *   CPER_IA32X64_CTX_64BIT_DBG</span><br><span style="color: hsl(120, 100%, 40%);">+ *   CPER_IA32X64_CTX_MEMMAPPED</span><br><span style="color: hsl(120, 100%, 40%);">+ * num is the number of bytes eventually used to fill the context's register</span><br><span style="color: hsl(120, 100%, 40%);">+ *   array, e.g. 4 MSRs * sizeof(msr_t)</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * status and entry data_length values are updated.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+cper_ia32x64_context_t *new_cper_ia32x64_ctx(</span><br><span style="color: hsl(120, 100%, 40%);">+               acpi_generic_error_status_t *status,</span><br><span style="color: hsl(120, 100%, 40%);">+          cper_ia32x64_proc_error_section_t *x86err, int type, int num)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      size_t size;</span><br><span style="color: hsl(120, 100%, 40%);">+  cper_ia32x64_context_t *ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+  static const char * const ctx_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                     "Unclassified Data",</span><br><span style="color: hsl(120, 100%, 40%);">+                        "MSR Registers",</span><br><span style="color: hsl(120, 100%, 40%);">+                    "32-bit Mode Execution",</span><br><span style="color: hsl(120, 100%, 40%);">+                    "64-bit Mode Execution",</span><br><span style="color: hsl(120, 100%, 40%);">+                    "FXSAVE"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "32-bit Mode Debug"</span><br><span style="color: hsl(120, 100%, 40%);">+                 "64-bit Mode Debug"</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Memory Mapped"</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (type > CPER_IA32X64_CTX_MEMMAPPED)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (cper_ia32x64_proc_num_ctxs(x86err) == I32X64SEC_VALID_CTXNUM_MAX) {</span><br><span style="color: hsl(120, 100%, 40%);">+               printk(BIOS_ERR, "Error: New IA32X64 %s context entry would exceed max allowable contexts\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               ctx_names[type]);</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   size = cper_ia32x64_ctx_sz_bytype(type, num);</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx = bert_allocate_storage(size);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ctx) {</span><br><span style="color: hsl(120, 100%, 40%);">+           printk(BIOS_ERR, "Error: New IA32X64 %s context entry would exceed available region\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             ctx_names[type]);</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   revise_error_sizes(status, size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ctx->type = type;</span><br><span style="color: hsl(120, 100%, 40%);">+  ctx->array_size = num;</span><br><span style="color: hsl(120, 100%, 40%);">+     cper_bump_ia32x64_ctx_count(x86err);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Add a new IA32/X64 Processor Error Information Structure (Table 256),</span><br><span style="color: hsl(120, 100%, 40%);">+ * following any other errors, to an existing Processor Error Section</span><br><span style="color: hsl(120, 100%, 40%);">+ * (Table 255).  All error structures must be added before any contexts are</span><br><span style="color: hsl(120, 100%, 40%);">+ * added.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function fills only the minimal amount of information required to parse</span><br><span style="color: hsl(120, 100%, 40%);">+ * or step through the errors.  The type is filled and PROC_ERR_INFO_NUM is</span><br><span style="color: hsl(120, 100%, 40%);">+ * updated.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+cper_ia32x64_proc_error_info_t *new_cper_ia32x64_check(</span><br><span style="color: hsl(120, 100%, 40%);">+                acpi_generic_error_status_t *status,</span><br><span style="color: hsl(120, 100%, 40%);">+          cper_ia32x64_proc_error_section_t *x86err,</span><br><span style="color: hsl(120, 100%, 40%);">+            enum cper_x86_check_type type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     cper_ia32x64_proc_error_info_t *check;</span><br><span style="color: hsl(120, 100%, 40%);">+        static const char * const check_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                   "cache",</span><br><span style="color: hsl(120, 100%, 40%);">+                    "TLB",</span><br><span style="color: hsl(120, 100%, 40%);">+                      "bus",</span><br><span style="color: hsl(120, 100%, 40%);">+                      "MS"</span><br><span style="color: hsl(120, 100%, 40%);">+        };</span><br><span style="color: hsl(120, 100%, 40%);">+    const guid_t check_guids[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        X86_PROCESSOR_CACHE_CHK_ERROR_GUID,</span><br><span style="color: hsl(120, 100%, 40%);">+                   X86_PROCESSOR_TLB_CHK_ERROR_GUID,</span><br><span style="color: hsl(120, 100%, 40%);">+                     X86_PROCESSOR_BUS_CHK_ERROR_GUID,</span><br><span style="color: hsl(120, 100%, 40%);">+                     X86_PROCESSOR_MS_CHK_ERROR_GUID</span><br><span style="color: hsl(120, 100%, 40%);">+       };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (type > 3)</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (cper_ia32x64_proc_num_chks(x86err) == I32X64SEC_VALID_ERRNUM_MAX) {</span><br><span style="color: hsl(120, 100%, 40%);">+               printk(BIOS_ERR, "Error: New IA32X64 %s check entry would exceed max allowable errors\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           check_names[type]);</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   check = bert_allocate_storage(sizeof(*check));</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!check) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "Error: New IA32X64 %s check entry would exceed available region\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               check_names[type]);</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   revise_error_sizes(status, sizeof(*check));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ guidcpy(&check->type, &check_guids[type]);</span><br><span style="color: hsl(120, 100%, 40%);">+ cper_bump_ia32x64_chk_count(x86err);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return check;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper to append an ACPI Generic Error Data Entry plus a CPER IA32/X64</span><br><span style="color: hsl(120, 100%, 40%);">+ * Processor Error Section.  As many fields are populated as possible for the</span><br><span style="color: hsl(120, 100%, 40%);">+ * caller.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+acpi_hest_generic_data_v300_t *bert_append_ia32x64(</span><br><span style="color: hsl(120, 100%, 40%);">+                                    acpi_generic_error_status_t *status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       acpi_hest_generic_data_v300_t *entry;</span><br><span style="color: hsl(120, 100%, 40%);">+ cper_ia32x64_proc_error_section_t *ipe;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     entry = bert_append_error_datasection(status,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 &CPER_SEC_PROC_IA32X64_GUID);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!entry)</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        status->block_status |= GENERIC_ERR_STS_UNCORRECTABLE_VALID;</span><br><span style="color: hsl(120, 100%, 40%);">+       status->error_severity = ACPI_GENERROR_SEV_FATAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        entry->error_severity = ACPI_GENERROR_SEV_FATAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ipe = section_of_acpientry(ipe, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ipe->apicid = lapicid();</span><br><span style="color: hsl(120, 100%, 40%);">+   ipe->validation |= I32X64SEC_VALID_LAPIC;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ipe->cpuid[0] = cpuid_eax(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      ipe->cpuid[1] = cpuid_ebx(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      ipe->cpuid[2] = cpuid_ecx(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      ipe->cpuid[3] = cpuid_edx(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      ipe->validation |= I32X64SEC_VALID_CPUID;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return entry;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char * const generic_error_types[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       "PROCESSOR_GENERIC",</span><br><span style="color: hsl(120, 100%, 40%);">+        "PROCESSOR_SPECIFIC_X86",</span><br><span style="color: hsl(120, 100%, 40%);">+   "PROCESSOR_SPECIFIC_ARM",</span><br><span style="color: hsl(120, 100%, 40%);">+   "PLATFORM_MEMORY",</span><br><span style="color: hsl(120, 100%, 40%);">+  "PLATFORM_MEMORY2",</span><br><span style="color: hsl(120, 100%, 40%);">+ "PCIE",</span><br><span style="color: hsl(120, 100%, 40%);">+     "FW_ERROR_RECORD",</span><br><span style="color: hsl(120, 100%, 40%);">+  "PCI_PCIX_BUS",</span><br><span style="color: hsl(120, 100%, 40%);">+     "PCI_DEVICE",</span><br><span style="color: hsl(120, 100%, 40%);">+       "DMAR_GENERIC",</span><br><span style="color: hsl(120, 100%, 40%);">+     "DIRECTED_IO_DMAR",</span><br><span style="color: hsl(120, 100%, 40%);">+ "IOMMU_DMAR",</span><br><span style="color: hsl(120, 100%, 40%);">+       "UNRECOGNIZED"</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *generic_error_name(guid_t *guid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+          return generic_error_types[0];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PROC_IA32X64_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+          return generic_error_types[1];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PROC_ARM_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+              return generic_error_types[2];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PLATFORM_MEM_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+          return generic_error_types[3];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PLATFORM_MEM2_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+         return generic_error_types[4];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PCIE_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+          return generic_error_types[5];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+                return generic_error_types[6];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PCI_X_BUS_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+             return generic_error_types[7];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PCI_DEV_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+               return generic_error_types[8];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_DMAR_GENERIC_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+          return generic_error_types[9];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_DMAR_VT_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+               return generic_error_types[10];</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!guidcmp(guid, &CPER_SEC_DMAR_IOMMU_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+            return generic_error_types[11];</span><br><span style="color: hsl(120, 100%, 40%);">+       return generic_error_types[12];</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Add a new event to the BERT region.  An event consists of an ACPI Error</span><br><span style="color: hsl(120, 100%, 40%);">+ * Status Block, a Generic Error Data Entry, and an associated CPER Error</span><br><span style="color: hsl(120, 100%, 40%);">+ * Section.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+acpi_generic_error_status_t *bert_new_event(guid_t *guid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t size;</span><br><span style="color: hsl(120, 100%, 40%);">+  acpi_generic_error_status_t *status;</span><br><span style="color: hsl(120, 100%, 40%);">+  acpi_hest_generic_data_v300_t *entry, *r;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   size = sizeof(*status);</span><br><span style="color: hsl(120, 100%, 40%);">+       size += sizeof(*entry);</span><br><span style="color: hsl(120, 100%, 40%);">+       size += sizeof_error_section(guid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (size > bert_storage_remaining()) {</span><br><span style="color: hsl(120, 100%, 40%);">+             printk(BIOS_ERR, "Error: Not enough BERT region space to add event for type %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          generic_error_name(guid));</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   status = new_bert_status();</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!status)</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+          r = bert_append_genproc(status);</span><br><span style="color: hsl(120, 100%, 40%);">+      else if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))</span><br><span style="color: hsl(120, 100%, 40%);">+             r = bert_append_ia32x64(status);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* else if other types not implemented */</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          r = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (r)</span><br><span style="color: hsl(120, 100%, 40%);">+                return status;</span><br><span style="color: hsl(120, 100%, 40%);">+        return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper to add an MSR context to an existing IA32/X64-type error entry */</span><br><span style="color: hsl(120, 100%, 40%);">+cper_ia32x64_context_t *cper_new_ia32x64_context_msr(</span><br><span style="color: hsl(120, 100%, 40%);">+         acpi_generic_error_status_t *status,</span><br><span style="color: hsl(120, 100%, 40%);">+          cper_ia32x64_proc_error_section_t *x86err, u32 addr, int num)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      cper_ia32x64_context_t *ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        msr_t *dest;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ctx = new_cper_ia32x64_ctx(status, x86err, CPER_IA32X64_CTX_MSR, num);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* already filled ctx->type = CPER_IA32X64_CTX_MSR; */</span><br><span style="color: hsl(120, 100%, 40%);">+     ctx->msr_addr = addr;</span><br><span style="color: hsl(120, 100%, 40%);">+      ctx->array_size = num * sizeof(msr_t);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   dest = (msr_t *)((u8 *)(ctx + 1)); /* point to the Register Array */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0 ; i < num ; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                *(dest + i) = rdmsr(addr + i);</span><br><span style="color: hsl(120, 100%, 40%);">+        return ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* The region must be in memory marked as reserved.  If not implemented,</span><br><span style="color: hsl(120, 100%, 40%);">+ * skip generating the information in the region.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+__weak void bert_reserved_region(void **start, size_t *size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   *start = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        *size = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void bert_storage_setup(int unused)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Always start with a blank bert region.  Make sure nothing is</span><br><span style="color: hsl(120, 100%, 40%);">+        * maintained across reboots or resumes.</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+   bert_region_broken = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       bert_region_used = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       bert_reserved_region(&bert_region_base, &bert_region_size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!bert_region_base || !bert_region_size) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printk(BIOS_ERR, "Bug: Can't find/add BERT storage area\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            bert_region_broken = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   memset(bert_region_base, 0, bert_region_size);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+RAMSTAGE_CBMEM_INIT_HOOK(bert_storage_setup)</span><br><span>diff --git a/src/arch/x86/include/arch/bert_storage.h b/src/arch/x86/include/arch/bert_storage.h</span><br><span>new file mode 100644</span><br><span>index 0000000..9d5b2da</span><br><span>--- /dev/null</span><br><span>+++ b/src/arch/x86/include/arch/bert_storage.h</span><br><span>@@ -0,0 +1,167 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * This file is part of the coreboot project.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2018 Advanced Micro Devices, Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; version 2 of the License.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef _BERT_STORAGE_H_</span><br><span style="color: hsl(120, 100%, 40%);">+#define _BERT_STORAGE_H_</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arch/acpi.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Items in the BERT region</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  * Each item begins with a Generic Error Status Block</span><br><span style="color: hsl(120, 100%, 40%);">+ *  * Zero or more Generic Error Data Entries follow, and</span><br><span style="color: hsl(120, 100%, 40%);">+ *    are associated with the Status Block</span><br><span style="color: hsl(120, 100%, 40%);">+ *  * Each Generic Error Data Entry must be a certain type,</span><br><span style="color: hsl(120, 100%, 40%);">+ *    as defined in the UEFI CPER appendix</span><br><span style="color: hsl(120, 100%, 40%);">+ *  * Each type may allow zero or more additional sets of</span><br><span style="color: hsl(120, 100%, 40%);">+ *    data, e.g. error descriptions, or processor contexts.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * In the example layout below, there are three BERT region</span><br><span style="color: hsl(120, 100%, 40%);">+ * entries.  The first two are a single error.  The third</span><br><span style="color: hsl(120, 100%, 40%);">+ * has two errors, with one providing a variable amount</span><br><span style="color: hsl(120, 100%, 40%);">+ * of additional information.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * +====================================================================+</span><br><span style="color: hsl(120, 100%, 40%);">+ * | Generic Error  | Generic Error   | Platform Memory Error           |</span><br><span style="color: hsl(120, 100%, 40%);">+ * | Status         | Data Entry      |                                 |</span><br><span style="color: hsl(120, 100%, 40%);">+ * |====================================================================|</span><br><span style="color: hsl(120, 100%, 40%);">+ * | Generic Error  | Generic Error   | Generic Processor Error         |</span><br><span style="color: hsl(120, 100%, 40%);">+ * | Status         | Data Entry      |                                 |</span><br><span style="color: hsl(120, 100%, 40%);">+ * |====================================================================|</span><br><span style="color: hsl(120, 100%, 40%);">+ * | Generic Error  | Generic Error   | IA32/X64 Processor Error        |</span><br><span style="color: hsl(120, 100%, 40%);">+ * | Status         | Data Entry      |    +----------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+ * |                |                 |    | Error Check Data           |</span><br><span style="color: hsl(120, 100%, 40%);">+ * |                |                 |    +----------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+ * |                |                 |    | MSR Context                |</span><br><span style="color: hsl(120, 100%, 40%);">+ * |                |                 |    +----------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+ * |                |                 |    | X64 Registers Context      |</span><br><span style="color: hsl(120, 100%, 40%);">+ * |                +-----------------+----+----------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+ * |                | Generic Error   | PCI Express Error               |</span><br><span style="color: hsl(120, 100%, 40%);">+ * |                | Data Entry      |                                 |</span><br><span style="color: hsl(120, 100%, 40%);">+ * +--------------------------------------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Get implementation-specific reserved area for generating BERT info */</span><br><span style="color: hsl(120, 100%, 40%);">+void bert_reserved_region(void **start, size_t *size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Get the region where BERT error structures have been constructed for</span><br><span style="color: hsl(120, 100%, 40%);">+ * generating the ACPI table</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void bert_errors_region(void **start, size_t *size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Get amount of available storage left for error info */</span><br><span style="color: hsl(120, 100%, 40%);">+size_t bert_storage_remaining(void);</span><br><span style="color: hsl(120, 100%, 40%);">+/* Find if errors were added, a BERT region is present, and ACPI table needed */</span><br><span style="color: hsl(120, 100%, 40%);">+int bert_errors_present(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Get the number of entries accociated with status */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline size_t bert_entry_count(acpi_generic_error_status_t *status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return (status->block_status & GENERIC_ERR_STS_ENTRY_COUNT_MASK)</span><br><span style="color: hsl(120, 100%, 40%);">+                               >> GENERIC_ERR_STS_ENTRY_COUNT_SHIFT;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Increment the number of entries this status describes */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void bert_bump_entry_count(acpi_generic_error_status_t *status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int count;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  count = bert_entry_count(status) + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ status->block_status &= ~GENERIC_ERR_STS_ENTRY_COUNT_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+     status->block_status |= count << GENERIC_ERR_STS_ENTRY_COUNT_SHIFT;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Find the nth (1-based) Generic Data Structure attached to an Error Status */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void *acpi_hest_generic_data_nth(</span><br><span style="color: hsl(120, 100%, 40%);">+           acpi_generic_error_status_t *status, int num)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      acpi_hest_generic_data_v300_t *ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t struct_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!num || num > bert_entry_count(status))</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ptr = (acpi_hest_generic_data_v300_t *)(status + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+  while (--num) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (ptr->revision == HEST_GENERIC_ENTRY_V300)</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct_size = sizeof(acpi_hest_generic_data_v300_t);</span><br><span style="color: hsl(120, 100%, 40%);">+          else</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct_size = sizeof(acpi_hest_generic_data_t);</span><br><span style="color: hsl(120, 100%, 40%);">+               ptr = (acpi_hest_generic_data_v300_t *)(</span><br><span style="color: hsl(120, 100%, 40%);">+                              (u8 *)ptr</span><br><span style="color: hsl(120, 100%, 40%);">+                             + ptr->data_length</span><br><span style="color: hsl(120, 100%, 40%);">+                         + struct_size);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Find the address of the first Generic Data structure from its status entry */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline acpi_hest_generic_data_v300_t *acpi_hest_generic_data3(</span><br><span style="color: hsl(120, 100%, 40%);">+             acpi_generic_error_status_t *status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return (acpi_hest_generic_data_v300_t *)</span><br><span style="color: hsl(120, 100%, 40%);">+                      ((u8 *)status + sizeof(*status));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Find the address of a Generic Data structure's CPER error record section */</span><br><span style="color: hsl(120, 100%, 40%);">+#define section_of_acpientry(A, B) ((typeof(A))((u8 *)(B) + sizeof(*(B))))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Add a context to an existing IA32/X64-type error entry */</span><br><span style="color: hsl(120, 100%, 40%);">+cper_ia32x64_context_t *new_cper_ia32x64_ctx(</span><br><span style="color: hsl(120, 100%, 40%);">+               acpi_generic_error_status_t *status,</span><br><span style="color: hsl(120, 100%, 40%);">+          cper_ia32x64_proc_error_section_t *x86err, int type, int num);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper to add an MSR context to an existing IA32/X64-type error entry */</span><br><span style="color: hsl(120, 100%, 40%);">+cper_ia32x64_context_t *cper_new_ia32x64_context_msr(</span><br><span style="color: hsl(120, 100%, 40%);">+          acpi_generic_error_status_t *status,</span><br><span style="color: hsl(120, 100%, 40%);">+          cper_ia32x64_proc_error_section_t *x86err, u32 addr, int num);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Add check info to an existing IA32/X64-type error entry */</span><br><span style="color: hsl(120, 100%, 40%);">+cper_ia32x64_proc_error_info_t *new_cper_ia32x64_check(</span><br><span style="color: hsl(120, 100%, 40%);">+              acpi_generic_error_status_t *status,</span><br><span style="color: hsl(120, 100%, 40%);">+          cper_ia32x64_proc_error_section_t *x86err,</span><br><span style="color: hsl(120, 100%, 40%);">+            enum cper_x86_check_type type);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Append a new ACPI Generic Error Data Entry plus CPER Error Section to an</span><br><span style="color: hsl(120, 100%, 40%);">+ * existing ACPI Generic Error Status Block.  The caller is responsible for</span><br><span style="color: hsl(120, 100%, 40%);">+ * the setting the status and entry severity, as well as populating all fields</span><br><span style="color: hsl(120, 100%, 40%);">+ * of the error section.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+acpi_hest_generic_data_v300_t *bert_append_error_datasection(</span><br><span style="color: hsl(120, 100%, 40%);">+             acpi_generic_error_status_t *status, guid_t *guid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper to append an ACPI Generic Error Data Entry plus a CPER Processor</span><br><span style="color: hsl(120, 100%, 40%);">+ * Generic Error Section.  As many fields are populated as possible for the</span><br><span style="color: hsl(120, 100%, 40%);">+ * caller.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+acpi_hest_generic_data_v300_t *bert_append_genproc(</span><br><span style="color: hsl(120, 100%, 40%);">+                                  acpi_generic_error_status_t *status);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Helper to append an ACPI Generic Error Data Entry plus a CPER IA32/X64</span><br><span style="color: hsl(120, 100%, 40%);">+ * Processor Error Section.  As many fields are populated as possible for the</span><br><span style="color: hsl(120, 100%, 40%);">+ * caller.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+acpi_hest_generic_data_v300_t *bert_append_ia32x64(</span><br><span style="color: hsl(120, 100%, 40%);">+                                       acpi_generic_error_status_t *status);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Add a new event to the BERT region.  An event consists of an ACPI Error</span><br><span style="color: hsl(120, 100%, 40%);">+ * Status Block, a Generic Error Data Entry, and an associated CPER Error</span><br><span style="color: hsl(120, 100%, 40%);">+ * Section.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+acpi_generic_error_status_t *bert_new_event(guid_t *guid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* _BERT_STORAGE_H_ */</span><br><span></span><br></pre><p>To view, visit <a href="https://review.coreboot.org/28470">change 28470</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://review.coreboot.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://review.coreboot.org/28470"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I54826981639b5647a8ca33b8b55ff097681402b9 </div>
<div style="display:none"> Gerrit-Change-Number: 28470 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Marshall Dawson <marshalldawson3rd@gmail.com> </div>