<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>