Marshall Dawson has uploaded this change for review.

View Change

NOT_FOR_MERGE: Add code to dump BERT region contents

Has been useful for development and debug.

Change-Id: I8ecf920499a662db34a332e9df05e4ee2383b6d4
Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com>
---
M src/soc/amd/stoneyridge/Makefile.inc
A src/soc/amd/stoneyridge/bertdump.c
M src/soc/amd/stoneyridge/finalize.c
3 files changed, 474 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/80/28480/1
diff --git a/src/soc/amd/stoneyridge/Makefile.inc b/src/soc/amd/stoneyridge/Makefile.inc
index a8db2c2..45e8aa3 100644
--- a/src/soc/amd/stoneyridge/Makefile.inc
+++ b/src/soc/amd/stoneyridge/Makefile.inc
@@ -37,6 +37,8 @@
subdirs-y += ../../../cpu/x86/pae
subdirs-y += ../../../cpu/x86/smm

+ramstage-y += bertdump.c
+
bootblock-$(CONFIG_STONEYRIDGE_UART) += uart.c
bootblock-y += BiosCallOuts.c
bootblock-y += bootblock/bootblock.c
diff --git a/src/soc/amd/stoneyridge/bertdump.c b/src/soc/amd/stoneyridge/bertdump.c
new file mode 100644
index 0000000..187ca24
--- /dev/null
+++ b/src/soc/amd/stoneyridge/bertdump.c
@@ -0,0 +1,465 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/acpi.h>
+#include <cpu/amd/amdfam15.h>
+#include <soc/cpu.h>
+#include <console/console.h>
+#include <lib.h>
+#include <commonlib/helpers.h>
+#include <arch/bert_storage.h>
+#include <cper.h>
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+//
+//
+// Table checker code
+//
+//
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+static void print_guid(guid_t guid)
+{
+ u8 *g = (u8 *)&guid;
+ printk(0, "{{0x%02x%02x%02x%02x, 0x%02x%02x, 0x%02x%02x, {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}\n",
+ g[3], g[2], g[1], g[0],
+ g[5], g[4],
+ g[7], g[6],
+ g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]);
+}
+
+// Status and Error Data structures have idential Error Severity definitions
+static const char *acpi_severity[] = {
+ "Recoverable",
+ "Fatal",
+ "Corrected",
+ "None",
+ "you did something wrong"
+};
+
+static const char *acpi_sev(u32 sev)
+{
+ if (sev > 3)
+ return acpi_severity[4];
+ return acpi_severity[sev];
+}
+
+static void x86_chkprint_with_valid(u64 check, u64 valid)
+{
+
+ if (check & 0xffff & ~valid) /* validation bits are 15:0 */
+ printk(0, " e * Invalid bits %llx\n", check & ~valid);
+ if (valid & X86_PROC_CHK_XACT_MASK)
+ printk(0, " e Transaction Type = %llx %s\n", check & X86_PROC_CHK_XACT_MASK >> X86_PROC_CHK_XACT_SH,
+ check & X86_PROC_CHK_XACT_MASK ? "V" : "");
+ if (valid & X86_PROC_CHK_OPERATION_VALID)
+ printk(0, " e Operation = %llx %s\n", check & X86_PROC_CHK_OPER_MASK >> X86_PROC_CHK_OPER_SH,
+ check & X86_PROC_CHK_OPERATION_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_LEVEL_VALID)
+ printk(0, " e Cache Level = %llx %s\n", check & X86_PROC_CHK_LEVEL_MASK >> X86_PROC_CHK_LEVEL_SH,
+ check & X86_PROC_CHK_LEVEL_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_CONTEXT_CORPT_VALID)
+ printk(0, " e Context Corrupt = %x %s\n", !!(check & X86_PROC_CHK_CTX_CORRUPT),
+ check & X86_PROC_CHK_CONTEXT_CORPT_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_UNCORRECTED_VALID)
+ printk(0, " e Uncorrected = %x %s\n", !!(check & X86_PROC_CHK_UNCORRECTED),
+ check & X86_PROC_CHK_UNCORRECTED_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_PRECISE_IP_VALID)
+ printk(0, " e Precise IP = %x %s\n", !!(check & X86_PROC_CHK_PRECISE_IP),
+ check & X86_PROC_CHK_PRECISE_IP_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_RESTARTABLE_VALID)
+ printk(0, " e Restartable IP = %x %s\n", !!(check & X86_PROC_CHK_RESTARTABLE_IP),
+ check & X86_PROC_CHK_RESTARTABLE_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_OVERFLOW_VALID)
+ printk(0, " e Overflow = %x %s\n", !!(check & X86_PROC_CHK_OVERFLOW),
+ check & X86_PROC_CHK_OVERFLOW_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_PART_TYPE_VALID)
+ printk(0, " e Participation Type = %llx %s\n", check & X86_PROC_CHK_PARTIC_MASK >> X86_PROC_CHK_PARTIC_SH,
+ check & X86_PROC_CHK_PART_TYPE_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_TIMEOUT)
+ printk(0, " e Time Out = %x %s\n", !!(check & X86_PROC_CHK_OVERFLOW),
+ check & X86_PROC_CHK_TIMEOUT ? "V" : "");
+ if (valid & X86_PROC_CHK_ADDR_SPACE_VALID)
+ printk(0, " e Address Space = %llx %s\n", check & X86_PROC_CHK_PARTIC_MASK >> X86_PROC_CHK_PARTIC_SH,
+ check & X86_PROC_CHK_ADDR_SPACE_VALID ? "V" : "");
+}
+
+static void x86_mschkprint_with_valid(u64 check, u64 valid)
+{
+ if (check & 0xffff & ~valid) /* validation bits are 15:0 */
+ printk(0, " e * Invalid bits %llx\n", check & ~valid);
+ if (valid & X86_PROC_CHK_XACT_MASK)
+ printk(0, " e Transaction Type = %llx %s\n", check & X86_PROC_MS_CHK_XACT_MASK >> X86_PROC_MS_CHK_XACT_SH,
+ check & X86_PROC_CHK_XACT_MASK ? "V" : "");
+ if (valid & X86_PROC_CHK_UNCORRECTED_VALID)
+ printk(0, " e Uncorrected = %x %s\n", !!(check & X86_PROC_MS_CHK_UNCORRECTED),
+ check & X86_PROC_CHK_UNCORRECTED_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_PRECISE_IP_VALID)
+ printk(0, " e Precise IP = %x %s\n", !!(check & X86_PROC_MS_CHK_PRECISE_IP),
+ check & X86_PROC_CHK_PRECISE_IP_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_RESTARTABLE_VALID)
+ printk(0, " e Restartable IP = %x %s\n", !!(check & X86_PROC_MS_CHK_RESTARTABLE_IP),
+ check & X86_PROC_CHK_RESTARTABLE_VALID ? "V" : "");
+ if (valid & X86_PROC_CHK_OVERFLOW_VALID)
+ printk(0, " e Overflow = %x %s\n", !!(check & X86_PROC_MS_CHK_OVERFLOW),
+ check & X86_PROC_CHK_OVERFLOW_VALID ? "V" : "");
+}
+
+static const char *check_guid_names[] = {
+ "CACHE_CHK_ERROR_GUID",
+ "TLB_CHK_ERROR_GUID",
+ "BUS_CHK_ERROR_GUID",
+ "MS_CHK_ERROR_GUID",
+ "you did something wrong"
+};
+
+static const char *check_guid_name(guid_t type)
+{
+
+ if (!guidcmp(&type, &X86_PROCESSOR_CACHE_CHK_ERROR_GUID))
+ return check_guid_names[0];
+ if (!guidcmp(&type, &X86_PROCESSOR_TLB_CHK_ERROR_GUID))
+ return check_guid_names[1];
+ if (!guidcmp(&type, &X86_PROCESSOR_BUS_CHK_ERROR_GUID))
+ return check_guid_names[2];
+ if (!guidcmp(&type, &X86_PROCESSOR_MS_CHK_ERROR_GUID))
+ return check_guid_names[3];
+
+ return check_guid_names[4];
+}
+
+static size_t parse_x86_error_info(cper_ia32x64_proc_error_info_t *err)
+{
+ printk(0, " ___ CPER IA32/x64 Processor Error (Check) Information @0x%p - 0x%p (size 0x%zx) ___\n", err, err + 1, sizeof(*err));
+ printk(0, " e Structure Type GUID = %s\n", check_guid_name(err->type));
+ printk(0, " e Structure Type = ");
+ print_guid(err->type);
+ printk(0, " e Validation Bits = %llx\n", err->validation);
+ if (!guidcmp(&err->type, &X86_PROCESSOR_CACHE_CHK_ERROR_GUID))
+ x86_chkprint_with_valid(err->check_info, X86_PROC_CHK_XACT_TYPE_VALID | X86_PROC_CHK_OPERATION_VALID
+ | X86_PROC_CHK_LEVEL_VALID | X86_PROC_CHK_CONTEXT_CORPT_VALID
+ | X86_PROC_CHK_UNCORRECTED_VALID | X86_PROC_CHK_PRECISE_IP_VALID
+ | X86_PROC_CHK_RESTARTABLE_VALID | X86_PROC_CHK_OVERFLOW_VALID);
+ else if (!guidcmp(&err->type, &X86_PROCESSOR_TLB_CHK_ERROR_GUID))
+ x86_chkprint_with_valid(err->check_info, X86_PROC_CHK_XACT_TYPE_VALID | X86_PROC_CHK_OPERATION_VALID
+ | X86_PROC_CHK_LEVEL_VALID | X86_PROC_CHK_CONTEXT_CORPT_VALID
+ | X86_PROC_CHK_UNCORRECTED_VALID | X86_PROC_CHK_PRECISE_IP_VALID
+ | X86_PROC_CHK_RESTARTABLE_VALID | X86_PROC_CHK_OVERFLOW_VALID);
+ else if (!guidcmp(&err->type, &X86_PROCESSOR_BUS_CHK_ERROR_GUID))
+ x86_chkprint_with_valid(err->check_info, X86_PROC_CHK_XACT_TYPE_VALID | X86_PROC_CHK_OPERATION_VALID
+ | X86_PROC_CHK_LEVEL_VALID | X86_PROC_CHK_CONTEXT_CORPT_VALID
+ | X86_PROC_CHK_UNCORRECTED_VALID | X86_PROC_CHK_PRECISE_IP_VALID
+ | X86_PROC_CHK_RESTARTABLE_VALID | X86_PROC_CHK_OVERFLOW_VALID
+ | X86_PROC_CHK_PART_TYPE_VALID | X86_PROC_CHK_TIMEOUT_VALID
+ | X86_PROC_CHK_ADDR_SPACE_VALID);
+ else if (!guidcmp(&err->type, &X86_PROCESSOR_MS_CHK_ERROR_GUID))
+ x86_mschkprint_with_valid(err->check_info, X86_PROC_CHK_XACT_TYPE_VALID | X86_PROC_CHK_OPERATION_VALID
+ | X86_PROC_CHK_LEVEL_VALID | X86_PROC_CHK_CONTEXT_CORPT_VALID
+ | X86_PROC_CHK_UNCORRECTED_VALID | X86_PROC_CHK_PRECISE_IP_VALID);
+ else
+ printk(0, " e INVALID CHECK TYPE!\n");
+ printk(0, " eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n");
+ return sizeof(*err);
+}
+
+static const char *context_names[] = {
+ "Unclassified data",
+ "MSR Registers",
+ "32-bit mode execution registers",
+ "64-bit mode execution registers",
+ "FXSAVE context",
+ "32-bit mode debug registers",
+ "64-bit mode debug registers",
+ "Memory mapped registers",
+ "you did something wrong"
+};
+
+static const char *context_name(int type)
+{
+ switch (type) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return context_names[type];
+ default:
+ return context_names[8];
+ }
+}
+
+static size_t parse_x86_context_info(cper_ia32x64_context_t *ctx)
+{
+ printk(0, " ___ CPER IA32/x64 Processor Context Information @0x%p - 0x%p (size 0x%zx) ___\n", ctx,
+ (u8 *)ctx + ALIGN_UP(sizeof(*ctx) + ctx->array_size, 16),
+ ALIGN_UP(sizeof(*ctx) + ctx->array_size, 16));
+ printk(0, " t Context Type = %x %s\n", ctx->type, context_name(ctx->type));
+ printk(0, " t Array Size = %x\n", ctx->array_size);
+ printk(0, " t MSR Address = %x\n", ctx->msr_addr);
+ printk(0, " t MM Address = %llx\n", ctx->mmap_addr);
+
+ int i;
+ u64 *array = (u64 *)(ctx + 1);
+ printk(0, " t Data Array\n");
+
+ int array_size = ctx->array_size / sizeof(u64);
+ for (i = 0 ; i < array_size ; i++)
+ printk(0, " t %08x_%08x\n", (u32)(*(array + i) >> 32), (u32)*(array + i));
+
+ printk(0, " ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt\n");
+ return ALIGN_UP(sizeof(*ctx) + ctx->array_size, 16);
+}
+
+static size_t parse_cper_structure_x86(cper_ia32x64_proc_error_section_t *ia32)
+{
+ int i;
+ int errs = (ia32->validation & I32X64SEC_VALID_ERRNUM_MASK) >> I32X64SEC_VALID_ERRNUM_SH;
+ int ctxs = (ia32->validation & I32X64SEC_VALID_CTXNUM_MASK) >> I32X64SEC_VALID_CTXNUM_SH;
+
+ printk(0, " ___ CPER IA32/x64 Processor Error @0x%p sizeof(proc error section struct) is 0x%zx/%zd) ___\n", ia32, sizeof(*ia32), sizeof(*ia32));
+ printk(0, " x Validation Bits = %llx\n", ia32->validation);
+ printk(0, " x errors = %d\n", errs);
+ printk(0, " x contexts = %d\n", ctxs);
+ printk(0, " x Processor APIC ID = %llx %s\n", ia32->apicid, ia32->validation & I32X64SEC_VALID_LAPIC ? "V" : "");
+ printk(0, " x Processor CPUID = EAX = %x %s\n", (u32)ia32->cpuid[0], ia32->validation & I32X64SEC_VALID_CPUID ? "V" : "");
+ printk(0, " x EBX = %x\n", (u32)ia32->cpuid[1]);
+ printk(0, " x ECX = %x\n", (u32)ia32->cpuid[2]);
+ printk(0, " x EDX = %x\n", (u32)ia32->cpuid[3]);
+
+ uintptr_t adder = sizeof(*ia32);
+ for (i = 0 ; i < errs ; i++)
+ adder += parse_x86_error_info((cper_ia32x64_proc_error_info_t *)((u8 *)ia32 + adder));
+
+ for (i = 0 ; i < ctxs ; i++)
+ adder += parse_x86_context_info((cper_ia32x64_context_t *)((u8 *)ia32 + adder));
+
+ return adder;
+}
+
+static size_t parse_cper_structure_generic(cper_proc_generic_error_section_t *gen)
+{
+ printk(0, " ___ CPER Generic Processor Error @0x%p sizeof(generic error struct) is 0x%zx/%zd\n", gen, sizeof(*gen), sizeof(*gen));
+ printk(0, " c Validation Bits = %llx\n", gen->validation);
+ printk(0, " c Processor Type = %x %s\n", gen->proc_type, gen->validation & GENPROC_VALID_PROC_TYPE ? "V" : "");
+ printk(0, " c Processor ISA = %x %s\n", gen->proc_isa, gen->validation & GENPROC_VALID_PROC_ISA ? "V" : "");
+ printk(0, " c Processor Error Type = %x %s\n", gen->error_type, gen->validation & GENPROC_VALID_PROC_ERR_TYPE ? "V" : "");
+ printk(0, " c Operation = %x %s\n", gen->operation, gen->validation & GENPROC_VALID_OPERATION ? "V" : "");
+ printk(0, " c Flags = %x %s\n", gen->flags, gen->validation & GENPROC_VALID_FLAGS ? "V" : "");
+ printk(0, " c Level = %x %s\n", gen->level, gen->validation & GENPROC_VALID_LEVEL ? "V" : "");
+ printk(0, " c CPU Version Info = %llx %s\n", gen->cpu_version, gen->validation & GENPROC_VALID_CPU_VERSION ? "V" : "");
+ printk(0, " c CPU Brand String = %s %s\n", gen->cpu_brand_string, gen->validation & GENPROC_VALID_CPU_BRAND ? "V" : "");
+ printk(0, " c Processor ID = %llx %s\n", gen->proc_id, gen->validation & GENPROC_VALID_CPU_ID ? "V" : "");
+ printk(0, " c Target Address = %llx %s\n", gen->target_addr, gen->validation & GENPROC_VALID_TGT_ADDR ? "V" : "");
+ printk(0, " c Requestor Identifier = %llx %s\n", gen->requestor_id, gen->validation & GENPROC_VALID_REQR_ID ? "V" : "");
+ printk(0, " c Responder Identifier = %llx %s\n", gen->responder_id, gen->validation & GENPROC_VALID_RSPR_ID ? "V" : "");
+ printk(0, " c Instruction IP = %llx %s\n", gen->instruction_ip, gen->validation & GENPROC_VALID_INSTR_IP ? "V" : "");
+ printk(0, " cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n");
+
+ return sizeof(*gen);
+}
+
+static size_t parse_cper_structure(void *st, guid_t type)
+{
+ if (!guidcmp(&type, &CPER_SEC_PROC_GENERIC_GUID))
+ return parse_cper_structure_generic(st);
+ else if (!guidcmp(&type, &CPER_SEC_PROC_IA32X64_GUID))
+ return parse_cper_structure_x86(st);
+ // else if...
+
+ printk(0, "Error, you asked me to parse type for ");
+ print_guid(type);
+ return 0;
+}
+
+static size_t entry382_size(void *e382)
+{
+ acpi_hest_generic_data_t *entry = (acpi_hest_generic_data_t *)e382;
+
+ if (entry->revision == HEST_GENERIC_ENTRY_V300)
+ return sizeof(acpi_hest_generic_data_v300_t) + entry->data_length;
+ else
+ return sizeof(acpi_hest_generic_data_t) + entry->data_length;
+}
+
+static const char *guids382[] = {
+ "PROCESSOR_GENERIC",
+ "PROCESSOR_SPECIFIC_X86_GUID",
+ "PROCESSOR_SPECIFIC_ARM_GUID",
+ "PLATFORM_MEMORY_GUID",
+ "PLATFORM_MEMORY2_GUID",
+ "PCIE_GUID",
+ "FW_ERROR_RECORD_GUID",
+ "PCI_PCIX_BUS_GUID",
+ "PCI_DEVICE_GUID",
+ "DMAR_GENERIC_GUID",
+ "DIRECTED_IO_DMAR_GUID",
+ "IOMMU_DMAR_GUID",
+ "you did something wrong"
+};
+
+static const char *guid382_name(guid_t guid)
+{
+ if(!guidcmp(&guid, &CPER_SEC_PROC_GENERIC_GUID))
+ return guids382[0];
+ if(!guidcmp(&guid, &CPER_SEC_PROC_IA32X64_GUID))
+ return guids382[1];
+ if(!guidcmp(&guid, &CPER_SEC_PROC_ARM_GUID))
+ return guids382[2];
+ if(!guidcmp(&guid, &CPER_SEC_PLATFORM_MEM_GUID))
+ return guids382[3];
+ if(!guidcmp(&guid, &CPER_SEC_PLATFORM_MEM2_GUID))
+ return guids382[4];
+ if(!guidcmp(&guid, &CPER_SEC_PCIE_GUID))
+ return guids382[5];
+ if(!guidcmp(&guid, &CPER_SEC_FW_ERR_REC_REF_GUID))
+ return guids382[6];
+ if(!guidcmp(&guid, &CPER_SEC_PCI_X_BUS_GUID))
+ return guids382[7];
+ if(!guidcmp(&guid, &CPER_SEC_PCI_DEV_GUID))
+ return guids382[8];
+ if(!guidcmp(&guid, &CPER_SEC_DMAR_GENERIC_GUID))
+ return guids382[9];
+ if(!guidcmp(&guid, &CPER_SEC_DMAR_VT_GUID))
+ return guids382[10];
+ if(!guidcmp(&guid, &CPER_SEC_DMAR_IOMMU_GUID))
+ return guids382[11];
+ return guids382[12];
+}
+
+static void parse_382_data(acpi_hest_generic_data_v300_t *entry, size_t size)
+{
+ size_t offset = 0;
+
+ while (size > offset) {
+ printk(0, " ___ 382 found @0x%p sizeof(%s) = 0x%zx/%zd ___\n", entry, entry->revision == 0x300 ? "v3" : "old-type",
+ entry->revision == 0x300 ? sizeof(acpi_hest_generic_data_v300_t) : sizeof(acpi_hest_generic_data_t),
+ entry->revision == 0x300 ? sizeof(acpi_hest_generic_data_v300_t) : sizeof(acpi_hest_generic_data_t));
+ printk(0, " 3 Section Type GUID = %s\n", guid382_name(entry->section_type));
+ printk(0, " 3 Section Type = ");
+ print_guid(entry->section_type);
+ printk(0, " 3 Severity = %x: %s\n", entry->error_severity, acpi_sev(entry->error_severity));
+ printk(0, " 3 Revision = %x\n", entry->revision);
+ printk(0, " 3 Validation = %x\n", entry->validation_bits);
+ printk(0, " 3 Flags = %x\n", entry->flags);
+ printk(0, " 3 Error Data Length = %x\n", entry->data_length);
+ printk(0, " 3 FRU ID = <todo> %s\n", entry->validation_bits & ACPI_GENERROR_VALID_FRUID ? "V" : "");
+ printk(0, " 3 FRU text = <todo> %s\n", entry->validation_bits & ACPI_GENERROR_VALID_FRUID_TEXT ? "V" : "");
+ if (entry->revision == HEST_GENERIC_ENTRY_V300) {
+ /* I can cheat on x300 because I know only diff is timestamp */
+ printk(0, " 3 Timestamp = %02x, %02x%02x/%02x/%02x %02x:%02x:%02x %s\n",
+ entry->timestamp.precise,
+ entry->timestamp.century, entry->timestamp.year,
+ entry->timestamp.month, entry->timestamp.day,
+ entry->timestamp.hour, entry->timestamp.min, entry->timestamp.sec,
+ entry->validation_bits & ACPI_GENERROR_VALID_TIMESTAMP ? "V" : "");
+ }
+ printk(0, " 333333333333333333333333333333333333333333333333333333333\n");
+
+ /* each table-382 entry should contain 0 or 1 cper structure at its end */
+ if (entry->data_length) {
+ if (entry->revision == HEST_GENERIC_ENTRY_V300)
+ parse_cper_structure((void *)(entry + 1), entry->section_type);
+ else /* maybe I did this right? */
+ parse_cper_structure((void *)((u8 *)entry + sizeof(acpi_hest_generic_data_t)), entry->section_type);
+ }
+
+ offset += entry382_size(entry);
+ entry = (acpi_hest_generic_data_v300_t *)((u8 *)entry + entry382_size(entry));
+ }
+}
+
+static size_t bert_entry_size(acpi_generic_error_status_t *bert_data)
+{
+ size_t size = sizeof(*bert_data);
+
+ if (bert_data->raw_data_length)
+ size += bert_data->raw_data_offset + bert_data->data_length;
+ else
+ size += bert_data->data_length;
+
+ return size;
+}
+
+static acpi_hest_generic_data_v300_t *ptr382_from_bert_entry(acpi_generic_error_status_t *bert_data)
+{
+ if (bert_data->data_length)
+ return (acpi_hest_generic_data_v300_t *)((u8 *)bert_data + sizeof(*bert_data));
+ else
+ return (acpi_hest_generic_data_v300_t *)NULL;
+}
+
+static u8 *ptr_raw_from_bert_entry(acpi_generic_error_status_t *bert_data)
+{
+ if (bert_data->raw_data_length)
+ return (u8 *)bert_data + bert_data->raw_data_offset;
+ else
+ return (u8 *)NULL;
+}
+
+void parse_bert_region(void);
+void parse_bert_region(void)
+{
+ acpi_generic_error_status_t *bert_base;
+ size_t size;
+ bert_errors_region((void **)&bert_base, &size);
+
+ acpi_generic_error_status_t *bert_data = bert_base;
+ size_t offset = 0;
+ acpi_hest_generic_data_v300_t *gen382;
+ u8 *raw;
+ int entries;
+
+ printk(0, "***** BERT storage at 0x%p - 0x%p (%zd) *****\n", bert_base, (u8 *)bert_base + size, size);
+
+ while(offset < size) {
+ entries = (bert_data->block_status & GENERIC_ERR_STS_ENTRY_COUNT_MASK) >> GENERIC_ERR_STS_ENTRY_COUNT_SHIFT;
+ printk(0, " ___ BERT entry @0x%p - (sizeof(status)=0x%zx/%zd) ___\n", bert_data, sizeof(*bert_data), sizeof(*bert_data));
+ printk(0, " b Block Status = %x\n", bert_data->block_status);
+ printk(0, " b severity =%s%s%s%s\n",
+ bert_data->block_status & BIT(0) ? " uncorrectable" : "",
+ bert_data->block_status & BIT(1) ? " correctable" : "",
+ bert_data->block_status & BIT(2) ? " mult-uncorrected" : "",
+ bert_data->block_status & BIT(3) ? " mult-corrected" : "");
+ printk(0, " b count = %x\n", entries);
+ printk(0, " b Raw Data Offset = %x\n", bert_data->raw_data_offset);
+ printk(0, " b Raw Data Length = %x\n", bert_data->raw_data_length);
+ printk(0, " b Data Length = %x\n", bert_data->data_length);
+ printk(0, " b Error Severity = %x: %s\n", bert_data->error_severity, acpi_sev(bert_data->error_severity));
+ if (bert_data->data_length && bert_data->data_length < sizeof(acpi_hest_generic_data_v300_t))
+ printk(0, " b ERROR: data length not large enough: %d < %zd\n",
+ bert_data->data_length, sizeof(acpi_hest_generic_data_v300_t));
+ if (bert_data->raw_data_length && bert_data->raw_data_offset < sizeof(*bert_data) + bert_data->data_length)
+ printk(0, " b ERROR: raw data offset is bad: %d < %zd + %d\n",
+ bert_data->raw_data_offset, sizeof(*bert_data), bert_data->data_length);
+ printk(0, " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n");
+
+ /* can have zero or more data entries, of type 382 and/or of raw */
+ gen382 = ptr382_from_bert_entry(bert_data); // todo: this only handles a single 382 entry
+ if (gen382)
+ parse_382_data(gen382, bert_data->data_length);
+
+ raw = ptr_raw_from_bert_entry(bert_data);
+ if (raw)
+ printk(0, "todo: dump raw data\n");
+
+ offset += bert_entry_size(bert_data);
+ bert_data = (acpi_generic_error_status_t *)((u8 *)bert_data + offset);
+ }
+}
diff --git a/src/soc/amd/stoneyridge/finalize.c b/src/soc/amd/stoneyridge/finalize.c
index 21d203c..25cfee9 100644
--- a/src/soc/amd/stoneyridge/finalize.c
+++ b/src/soc/amd/stoneyridge/finalize.c
@@ -49,10 +49,17 @@
printk(BIOS_WARNING, "Failed to finalize all cores\n");
}

+void parse_bert_region(void); // todo: remove me
+
static void soc_finalize(void *unused)
{
finalize_cores();

+ /* In the event the region got misplaced and SMM_LOCKed, this is a
+ * good place to see that.
+ */
+ parse_bert_region();
+
post_code(POST_OS_BOOT);
}


To view, visit change 28480. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8ecf920499a662db34a332e9df05e4ee2383b6d4
Gerrit-Change-Number: 28480
Gerrit-PatchSet: 1
Gerrit-Owner: Marshall Dawson <marshalldawson3rd@gmail.com>