From 522e0dbdaa46dde5363ad4c50a11938ae2f17a0d Mon Sep 17 00:00:00 2001 From: Francois Toguo Date: Thu, 21 Jan 2021 09:55:19 -0800 Subject: [PATCH] acpi: Add support for reporting CrashLog in BERT table Crash Data are collected and sent to the OS via the ACPI BERT. BUG=None TEST=Built, and BERT successfully generated in the crashLog flow. Signed-off-by: Francois Toguo Change-Id: I00e390d735d61beac2e89a726e39119d9b06b3df Signed-off-by: Nikunj A. Dadhania Reviewed-on: https://review.coreboot.org/c/coreboot/+/49799 Tested-by: build bot (Jenkins) Reviewed-by: Tim Wawrzynczak --- src/acpi/acpi.c | 23 ++++++++++ src/arch/x86/acpi_bert_storage.c | 46 +++++++++++++++++++ src/arch/x86/include/arch/bert_storage.h | 6 +++ src/commonlib/include/commonlib/cbmem_id.h | 6 +++ src/include/acpi/acpi.h | 4 ++ src/include/cper.h | 13 ++++++ .../intel/common/block/systemagent/memmap.c | 11 +++++ 7 files changed, 109 insertions(+) diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index 05ada084ab..fc1368990e 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -1331,6 +1331,14 @@ unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t return lpi_desc->header.length; } +/* BERT helpers */ +bool __weak acpi_is_boot_error_src_present(void) +{ + return false; +} + +__weak void acpi_soc_fill_bert(acpi_bert_t *bert, void **region, size_t *length) {} + unsigned long __weak fw_cfg_acpi_tables(unsigned long start) { return 0; @@ -1352,6 +1360,7 @@ unsigned long write_acpi_tables(unsigned long start) acpi_tpm2_t *tpm2; acpi_madt_t *madt; acpi_lpit_t *lpit; + acpi_bert_t *bert; struct device *dev; unsigned long fw; size_t slic_size, dsdt_size; @@ -1573,6 +1582,20 @@ unsigned long write_acpi_tables(unsigned long start) current = acpi_align_current(current); + if (acpi_is_boot_error_src_present()) { + void *region; + size_t size; + printk(BIOS_DEBUG, "ACPI: * BERT\n"); + bert = (acpi_bert_t *) current; + acpi_soc_fill_bert(bert, ®ion, &size); + acpi_write_bert(bert, (uintptr_t)region, size); + if (bert->header.length >= sizeof(acpi_bert_t)) { + current += bert->header.length; + acpi_add_table(rsdp, bert); + } + current = acpi_align_current(current); + } + printk(BIOS_DEBUG, "current = %lx\n", current); for (dev = all_devices; dev; dev = dev->next) { diff --git a/src/arch/x86/acpi_bert_storage.c b/src/arch/x86/acpi_bert_storage.c index de56291ac4..ec31917444 100644 --- a/src/arch/x86/acpi_bert_storage.c +++ b/src/arch/x86/acpi_bert_storage.c @@ -106,6 +106,7 @@ static void revise_error_sizes(acpi_generic_error_status_t *status, size_t size) entries = bert_entry_count(status); entry = acpi_hest_generic_data_nth(status, entries); status->data_length += size; + status->raw_data_length += size; if (entry) entry->data_length += size; } @@ -174,6 +175,7 @@ static acpi_hest_generic_data_v300_t *new_generic_error_entry( entry->validation_bits |= ACPI_GENERROR_VALID_TIMESTAMP; status->data_length += sizeof(*entry); + status->raw_data_length += sizeof(*entry); bert_bump_entry_count(status); return entry; @@ -186,12 +188,52 @@ static size_t sizeof_error_section(guid_t *guid) return sizeof(cper_proc_generic_error_section_t); else if (!guidcmp(guid, &CPER_SEC_PROC_IA32X64_GUID)) return sizeof(cper_ia32x64_proc_error_section_t); + else if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID)) + return sizeof(cper_fw_err_rec_section_t); /* else if ... sizeof(structures not yet defined) */ printk(BIOS_ERR, "Error: Requested size of unrecognized CPER GUID\n"); return 0; } +void *new_cper_fw_error_crashlog(acpi_generic_error_status_t *status, size_t cl_size) +{ + void *cl_data = bert_allocate_storage(cl_size); + if (!cl_data) { + printk(BIOS_ERR, "Error: Crashlog entry (size %lu) would exceed available region\n", + cl_size); + return NULL; + } + + revise_error_sizes(status, cl_size); + + return cl_data; +} + +/* Helper to append an ACPI Generic Error Data Entry per crashlog data */ +acpi_hest_generic_data_v300_t *bert_append_fw_err(acpi_generic_error_status_t *status) +{ + acpi_hest_generic_data_v300_t *entry; + cper_fw_err_rec_section_t *fw_err; + + entry = bert_append_error_datasection(status, &CPER_SEC_FW_ERR_REC_REF_GUID); + if (!entry) + return NULL; + + status->block_status |= GENERIC_ERR_STS_UNCORRECTABLE_VALID; + status->error_severity = ACPI_GENERROR_SEV_FATAL; + entry->error_severity = ACPI_GENERROR_SEV_FATAL; + + fw_err = section_of_acpientry(fw_err, entry); + + fw_err->record_type = CRASHLOG_RECORD_TYPE; + fw_err->revision = CRASHLOG_FW_ERR_REV; + fw_err->record_id = 0; + guidcpy(&fw_err->record_guid, &FW_ERR_RECORD_ID_CRASHLOG_GUID); + + return entry; +} + /* Append a new ACPI Generic Error Data Entry plus CPER Error Section to an * existing ACPI Generic Error Status Block. The caller is responsible for * the setting the status and entry severity, as well as populating all fields @@ -486,10 +528,14 @@ acpi_generic_error_status_t *bert_new_event(guid_t *guid) if (!status) return NULL; + status->raw_data_length = sizeof(*status); + if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID)) r = bert_append_genproc(status); else if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID)) r = bert_append_ia32x64(status); + if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID)) + r = bert_append_fw_err(status); /* else if other types not implemented */ else r = NULL; diff --git a/src/arch/x86/include/arch/bert_storage.h b/src/arch/x86/include/arch/bert_storage.h index 060e1a43f2..0d373e10b4 100644 --- a/src/arch/x86/include/arch/bert_storage.h +++ b/src/arch/x86/include/arch/bert_storage.h @@ -41,6 +41,9 @@ * +--------------------------------------------------------------------+ */ +#define CRASHLOG_RECORD_TYPE 0x2 +#define CRASHLOG_FW_ERR_REV 0x2 + /* Get implementation-specific reserved area for generating BERT info */ void bert_reserved_region(void **start, size_t *size); @@ -120,6 +123,9 @@ acpi_hest_generic_data_v300_t *bert_append_genproc( acpi_hest_generic_data_v300_t *bert_append_ia32x64( acpi_generic_error_status_t *status); +void *new_cper_fw_error_crashlog(acpi_generic_error_status_t *status, size_t cl_size); +acpi_hest_generic_data_v300_t *bert_append_fw_err(acpi_generic_error_status_t *status); + /* Add a new event to the BERT region. An event consists of an ACPI Error * Status Block, a Generic Error Data Entry, and an associated CPER Error * Section. diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h index f58d7b11c2..ae644de27c 100644 --- a/src/commonlib/include/commonlib/cbmem_id.h +++ b/src/commonlib/include/commonlib/cbmem_id.h @@ -4,6 +4,7 @@ #define _CBMEM_ID_H_ #define CBMEM_ID_ACPI 0x41435049 +#define CBMEM_ID_ACPI_BERT 0x42455254 #define CBMEM_ID_ACPI_GNVS 0x474e5653 #define CBMEM_ID_ACPI_UCSI 0x55435349 #define CBMEM_ID_AFTER_CAR 0xc4787a93 @@ -14,6 +15,7 @@ #define CBMEM_ID_CBTABLE_FWD 0x43425443 #define CBMEM_ID_CB_EARLY_DRAM 0x4544524D #define CBMEM_ID_CONSOLE 0x434f4e53 +#define CBMEM_ID_CPU_CRASHLOG 0x4350555f #define CBMEM_ID_COVERAGE 0x47434f56 #define CBMEM_ID_EHCI_DEBUG 0xe4c1deb9 #define CBMEM_ID_ELOG 0x454c4f47 @@ -31,6 +33,7 @@ #define CBMEM_ID_MMC_STATUS 0x4d4d4353 #define CBMEM_ID_MPTABLE 0x534d5054 #define CBMEM_ID_MRCDATA 0x4d524344 +#define CBMEM_ID_PMC_CRASHLOG 0x504d435f #define CBMEM_ID_VAR_MRCDATA 0x4d524345 #define CBMEM_ID_MTC 0xcb31d31c #define CBMEM_ID_NONE 0x00000000 @@ -76,6 +79,7 @@ #define CBMEM_ID_TO_NAME_TABLE \ { CBMEM_ID_ACPI, "ACPI " }, \ + { CBMEM_ID_ACPI_BERT, "ACPI BERT " }, \ { CBMEM_ID_ACPI_GNVS, "ACPI GNVS " }, \ { CBMEM_ID_ACPI_UCSI, "ACPI UCSI " }, \ { CBMEM_ID_AGESA_RUNTIME, "AGESA RSVD " }, \ @@ -87,6 +91,7 @@ { CBMEM_ID_CB_EARLY_DRAM, "EARLY DRAM USAGE" }, \ { CBMEM_ID_CONSOLE, "CONSOLE " }, \ { CBMEM_ID_COVERAGE, "COVERAGE " }, \ + { CBMEM_ID_CPU_CRASHLOG, "CPU CRASHLOG"}, \ { CBMEM_ID_EHCI_DEBUG, "USBDEBUG " }, \ { CBMEM_ID_ELOG, "ELOG " }, \ { CBMEM_ID_FREESPACE, "FREE SPACE " }, \ @@ -101,6 +106,7 @@ { CBMEM_ID_MMC_STATUS, "MMC STATUS " }, \ { CBMEM_ID_MPTABLE, "SMP TABLE " }, \ { CBMEM_ID_MRCDATA, "MRC DATA " }, \ + { CBMEM_ID_PMC_CRASHLOG, "PMC CRASHLOG"}, \ { CBMEM_ID_VAR_MRCDATA, "VARMRC DATA" }, \ { CBMEM_ID_MTC, "MTC " }, \ { CBMEM_ID_PIRQ, "IRQ TABLE " }, \ diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h index fa24902331..058c0d0217 100644 --- a/src/include/acpi/acpi.h +++ b/src/include/acpi/acpi.h @@ -1075,6 +1075,10 @@ unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, void acpi_create_lpit(acpi_lpit_t *lpit); unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid); +/* For crashlog. */ +bool acpi_is_boot_error_src_present(void); +void acpi_soc_fill_bert(acpi_bert_t *bert, void **region, size_t *length); + /* For ACPI S3 support. */ void __noreturn acpi_resume(void *wake_vec); void mainboard_suspend_resume(void); diff --git a/src/include/cper.h b/src/include/cper.h index b6d182e8ea..020ac41c77 100644 --- a/src/include/cper.h +++ b/src/include/cper.h @@ -370,6 +370,19 @@ typedef struct cper_ia32x64_ctx_x64state { u16 tr; } cper_ia32x64_ctx_x64state_t; +#define FW_ERR_RECORD_ID_CRASHLOG_GUID \ + GUID_INIT(0x8f87f311, 0xc998, 0x4d9e, \ + 0xa0, 0xc4, 0x60, 0x65, 0x51, 0x8c, 0x4f, 0x6d) + +/* Firmware Error Record Reference, UEFI v2.8 sec N.2.10 */ +typedef struct cper_fw_err_rec_section { + u8 record_type; + u8 revision; + u8 reserved[6]; + u64 record_id; + guid_t record_guid; +} cper_fw_err_rec_section_t; + static inline cper_timestamp_t cper_timestamp(int precise) { cper_timestamp_t ts; diff --git a/src/soc/intel/common/block/systemagent/memmap.c b/src/soc/intel/common/block/systemagent/memmap.c index 86ca4e1b84..ce842e850f 100644 --- a/src/soc/intel/common/block/systemagent/memmap.c +++ b/src/soc/intel/common/block/systemagent/memmap.c @@ -7,6 +7,7 @@ #include #include #include +#include #include /* @@ -49,12 +50,22 @@ * +---------------------------+ 0 */ +#define BERT_REGION_MAX_SIZE 0x10000 + void smm_region(uintptr_t *start, size_t *size) { *start = sa_get_tseg_base(); *size = sa_get_tseg_size(); } +void bert_reserved_region(void **start, size_t *size) +{ + *start = cbmem_add(CBMEM_ID_ACPI_BERT, BERT_REGION_MAX_SIZE); + *size = BERT_REGION_MAX_SIZE; + + printk(BIOS_DEBUG, "Reserving BERT start %lx, size %lx\n", (uintptr_t)*start, *size); +} + void fill_postcar_frame(struct postcar_frame *pcf) { /* FSP does not seem to bother w.r.t. alignment when asked to place cbmem_top() */