Marshall Dawson has uploaded this change for review. ( https://review.coreboot.org/28480
Change subject: NOT_FOR_MERGE: Add code to dump BERT region contents ......................................................................
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); }