diff options
-rw-r--r-- | src/Kconfig | 6 | ||||
-rw-r--r-- | src/arch/x86/Makefile.inc | 1 | ||||
-rw-r--r-- | src/arch/x86/acpi_bert_storage.c | 570 | ||||
-rw-r--r-- | src/arch/x86/include/arch/bert_storage.h | 143 |
4 files changed, 720 insertions, 0 deletions
diff --git a/src/Kconfig b/src/Kconfig index bce3e32884..ca75c0b4f0 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -586,6 +586,12 @@ config ACPI_NHLT help Build support for NHLT (non HD Audio) ACPI table generation. +config ACPI_BERT + bool + depends on HAVE_ACPI_TABLES + help + Build an ACPI Boot Error Record Table. + #These Options are here to avoid "undefined" warnings. #The actual selection and help texts are in the following menu. diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc index 584902a6a0..3e272dd8b6 100644 --- a/src/arch/x86/Makefile.inc +++ b/src/arch/x86/Makefile.inc @@ -292,6 +292,7 @@ ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpigen_dsm.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi_device.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi_pld.c ramstage-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.c +ramstage-$(CONFIG_ACPI_BERT) += acpi_bert_storage.c ramstage-y += boot.c ramstage-y += c_start.S ramstage-y += cbmem.c diff --git a/src/arch/x86/acpi_bert_storage.c b/src/arch/x86/acpi_bert_storage.c new file mode 100644 index 0000000000..82ecc5f59f --- /dev/null +++ b/src/arch/x86/acpi_bert_storage.c @@ -0,0 +1,570 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 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; 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 <bootstate.h> +#include <cbmem.h> +#include <console/console.h> +#include <cpu/x86/name.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/lapic.h> +#include <arch/acpi.h> +#include <arch/bert_storage.h> +#include <string.h> + +/* BERT region management: Allow the chipset to determine the specific + * location of the BERT region. We find that base and size, then manage + * the allocation of error information within it. + * + * Use simple static variables for managing the BERT region. This is a thin + * implementation; it is only created and consumed by coreboot, and only in + * a single stage, and we don't want its information to survive reboot or + * resume cycles. If the requirements change, consider using IMD to help + * manage the space. + */ +static int bert_region_broken; +static void *bert_region_base; +static size_t bert_region_size; +static size_t bert_region_used; + +/* Calculate the remaining space in the BERT region. This knowledge may help + * the caller prioritize the information to store. + */ +size_t bert_storage_remaining(void) +{ + return bert_region_broken ? 0 : bert_region_size - bert_region_used; +} + +int bert_errors_present(void) +{ + return bert_region_broken ? 0 : !!bert_region_used; +} + +void bert_errors_region(void **start, size_t *size) +{ + if (bert_region_broken) { + *start = NULL; + *size = 0; + return; + } + + /* No metadata, etc. with our region, so this is easy */ + *start = bert_region_base; + *size = bert_region_used; +} + +static void *bert_allocate_storage(size_t size) +{ + size_t alloc; + + if (bert_region_broken) + return NULL; + if (bert_region_used + size > bert_region_size) + return NULL; + + alloc = bert_region_used; + bert_region_used += size; + + return (void *)((u8 *)bert_region_base + alloc); +} + +/* Generic Error Status: Each Status represents a unique error event within + * the BERT errors region. Each event may have multiple errors associated + * with it. + */ + +/* Find the nth (1-based) Generic Data Structure attached to an Error Status */ +static void *acpi_hest_generic_data_nth( + acpi_generic_error_status_t *status, int num) +{ + acpi_hest_generic_data_v300_t *ptr; + size_t struct_size; + + if (!num || num > bert_entry_count(status)) + return NULL; + + ptr = (acpi_hest_generic_data_v300_t *)(status + 1); + while (--num) { + if (ptr->revision == HEST_GENERIC_ENTRY_V300) + struct_size = sizeof(acpi_hest_generic_data_v300_t); + else + struct_size = sizeof(acpi_hest_generic_data_t); + ptr = (acpi_hest_generic_data_v300_t *)( + (u8 *)ptr + + ptr->data_length + + struct_size); + } + return ptr; +} + +/* Update data_length for this Error Status, and final Data Entry it contains */ +static void revise_error_sizes(acpi_generic_error_status_t *status, size_t size) +{ + acpi_hest_generic_data_v300_t *entry; + int entries; + + if (!status) + return; + + entries = bert_entry_count(status); + entry = acpi_hest_generic_data_nth(status, entries); + status->data_length += size; + if (entry) + entry->data_length += size; +} + +/* Create space for a new BERT Generic Error Status Block, by finding the next + * available slot and moving the ending location. There is nothing to designate + * this as another Generic Error Status Block (e.g. no signature); only that it + * is within the BERT region. + * + * It is up to the caller to correctly fill the information, including status + * and error severity, and to update/maintain data offsets and lengths as + * entries are added. + */ +static acpi_generic_error_status_t *new_bert_status(void) +{ + acpi_generic_error_status_t *status; + + status = bert_allocate_storage(sizeof(*status)); + + if (!status) { + printk(BIOS_ERR, "Error: New BERT error entry would exceed available region\n"); + return NULL; + } + + status->error_severity = ACPI_GENERROR_SEV_NONE; + return status; +} + +/* Generic Error Data: Each Generic Error Status may contain zero or more + * Generic Error Data structures. The data structures describe particular + * error(s) associated with an event. The definition for the structure is + * found in the ACPI spec, however the data types and any accompanying data + * definitions are in the Common Platform Error Record appendix of the UEFI + * spec. + */ + +/* Create space for a new BERT Generic Data Entry. Update the count and + * data length in the parent Generic Error Status Block. Version 0x300 of + * the structure is used, and the timestamp is filled and marked precise + * (i.e. assumed close enough for reporting). + * + * It is up to the caller to fill the Section Type field and add the Common + * Platform Error Record type data as appropriate. In addition, the caller + * should update the error severity, and may optionally add FRU information + * or override any existing information. + */ +static acpi_hest_generic_data_v300_t *new_generic_error_entry( + acpi_generic_error_status_t *status) +{ + acpi_hest_generic_data_v300_t *entry; + + if (bert_entry_count(status) == GENERIC_ERR_STS_ENTRY_COUNT_MAX) { + printk(BIOS_ERR, "Error: New BERT error would exceed maximum entries\n"); + return NULL; + } + + entry = bert_allocate_storage(sizeof(*entry)); + if (!entry) { + printk(BIOS_ERR, "Error: New BERT error entry would exceed available region\n"); + return NULL; + } + + entry->revision = HEST_GENERIC_ENTRY_V300; + + entry->timestamp = cper_timestamp(CPER_TIMESTAMP_PRECISE); + entry->validation_bits |= ACPI_GENERROR_VALID_TIMESTAMP; + + status->data_length += sizeof(*entry); + bert_bump_entry_count(status); + + return entry; +} + +/* Find the size of a CPER error section w/o any add-ons */ +static size_t sizeof_error_section(guid_t *guid) +{ + if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_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 ... sizeof(structures not yet defined) */ + + printk(BIOS_ERR, "Error: Requested size of unrecognized CPER GUID\n"); + return 0; +} + +/* 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 + * of the error section. + */ +acpi_hest_generic_data_v300_t *bert_append_error_datasection( + acpi_generic_error_status_t *status, guid_t *guid) +{ + acpi_hest_generic_data_v300_t *entry; + void *sect; + size_t sect_size; + + sect_size = sizeof_error_section(guid); + if (!sect_size) + return NULL; /* Don't allocate structure if bad GUID passed */ + + if (sizeof(*entry) + sect_size > bert_storage_remaining()) + return NULL; + + entry = new_generic_error_entry(status); + if (!entry) + return NULL; + + /* error section immediately follows the Generic Error Data Entry */ + sect = bert_allocate_storage(sect_size); + if (!sect) + return NULL; + + revise_error_sizes(status, sect_size); + + guidcpy(&entry->section_type, guid); + return entry; +} + +/* Helper to append an ACPI Generic Error Data Entry plus a CPER Processor + * Generic Error Section. As many fields are populated as possible for the + * caller. + */ +acpi_hest_generic_data_v300_t *bert_append_genproc( + acpi_generic_error_status_t *status) +{ + acpi_hest_generic_data_v300_t *entry; + cper_proc_generic_error_section_t *ges; + + entry = bert_append_error_datasection(status, + &CPER_SEC_PROC_GENERIC_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; + + ges = section_of_acpientry(ges, entry); + + ges->proc_type = GENPROC_PROCTYPE_IA32X64; + ges->validation |= GENPROC_VALID_PROC_TYPE; + + ges->cpu_version = cpuid_eax(1); + ges->validation |= GENPROC_VALID_CPU_VERSION; + + fill_processor_name(ges->cpu_brand_string); + ges->validation |= GENPROC_VALID_CPU_BRAND; + + ges->proc_id = lapicid(); + ges->validation |= GENPROC_VALID_CPU_ID; + + return entry; +} + +/* Add a new IA32/X64 Processor Context Structure (Table 261), following any + * other contexts, to an existing Processor Error Section (Table 255). Contexts + * may only be added after the entire Processor Error Info array has been + * created. + * + * This function fills only the minimal amount of information required to parse + * or step through the contexts. The type is filled and PROC_CONTEXT_INFO_NUM + * is updated. + * + * type is one of: + * CPER_IA32X64_CTX_UNCL + * CPER_IA32X64_CTX_MSR + * CPER_IA32X64_CTX_32BIT_EX + * CPER_IA32X64_CTX_64BIT_EX + * CPER_IA32X64_CTX_FXSAVE + * CPER_IA32X64_CTX_32BIT_DBG + * CPER_IA32X64_CTX_64BIT_DBG + * CPER_IA32X64_CTX_MEMMAPPED + * num is the number of bytes eventually used to fill the context's register + * array, e.g. 4 MSRs * sizeof(msr_t) + * + * status and entry data_length values are updated. + */ +cper_ia32x64_context_t *new_cper_ia32x64_ctx( + acpi_generic_error_status_t *status, + cper_ia32x64_proc_error_section_t *x86err, int type, int num) +{ + size_t size; + cper_ia32x64_context_t *ctx; + static const char * const ctx_names[] = { + "Unclassified Data", + "MSR Registers", + "32-bit Mode Execution", + "64-bit Mode Execution", + "FXSAVE" + "32-bit Mode Debug" + "64-bit Mode Debug" + "Memory Mapped" + }; + + if (type > CPER_IA32X64_CTX_MEMMAPPED) + return NULL; + + if (cper_ia32x64_proc_num_ctxs(x86err) == I32X64SEC_VALID_CTXNUM_MAX) { + printk(BIOS_ERR, "Error: New IA32X64 %s context entry would exceed max allowable contexts\n", + ctx_names[type]); + return NULL; + } + + size = cper_ia32x64_ctx_sz_bytype(type, num); + ctx = bert_allocate_storage(size); + if (!ctx) { + printk(BIOS_ERR, "Error: New IA32X64 %s context entry would exceed available region\n", + ctx_names[type]); + return NULL; + } + + revise_error_sizes(status, size); + + ctx->type = type; + ctx->array_size = num; + cper_bump_ia32x64_ctx_count(x86err); + + return ctx; +} + +/* Add a new IA32/X64 Processor Error Information Structure (Table 256), + * following any other errors, to an existing Processor Error Section + * (Table 255). All error structures must be added before any contexts are + * added. + * + * This function fills only the minimal amount of information required to parse + * or step through the errors. The type is filled and PROC_ERR_INFO_NUM is + * updated. + */ +cper_ia32x64_proc_error_info_t *new_cper_ia32x64_check( + acpi_generic_error_status_t *status, + cper_ia32x64_proc_error_section_t *x86err, + enum cper_x86_check_type type) +{ + cper_ia32x64_proc_error_info_t *check; + static const char * const check_names[] = { + "cache", + "TLB", + "bus", + "MS" + }; + const guid_t check_guids[] = { + X86_PROCESSOR_CACHE_CHK_ERROR_GUID, + X86_PROCESSOR_TLB_CHK_ERROR_GUID, + X86_PROCESSOR_BUS_CHK_ERROR_GUID, + X86_PROCESSOR_MS_CHK_ERROR_GUID + }; + + if (type > X86_PROCESSOR_CHK_MAX) + return NULL; + + if (cper_ia32x64_proc_num_chks(x86err) == I32X64SEC_VALID_ERRNUM_MAX) { + printk(BIOS_ERR, "Error: New IA32X64 %s check entry would exceed max allowable errors\n", + check_names[type]); + return NULL; + } + + check = bert_allocate_storage(sizeof(*check)); + if (!check) { + printk(BIOS_ERR, "Error: New IA32X64 %s check entry would exceed available region\n", + check_names[type]); + return NULL; + } + + revise_error_sizes(status, sizeof(*check)); + + guidcpy(&check->type, &check_guids[type]); + cper_bump_ia32x64_chk_count(x86err); + + return check; +} + +/* Helper to append an ACPI Generic Error Data Entry plus a CPER IA32/X64 + * Processor Error Section. As many fields are populated as possible for the + * caller. + */ +acpi_hest_generic_data_v300_t *bert_append_ia32x64( + acpi_generic_error_status_t *status) +{ + acpi_hest_generic_data_v300_t *entry; + cper_ia32x64_proc_error_section_t *ipe; + struct cpuid_result id; + + entry = bert_append_error_datasection(status, + &CPER_SEC_PROC_IA32X64_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; + + ipe = section_of_acpientry(ipe, entry); + + ipe->apicid = lapicid(); + ipe->validation |= I32X64SEC_VALID_LAPIC; + + id = cpuid(1); + ipe->cpuid[0] = id.eax; + ipe->cpuid[1] = id.ebx; + ipe->cpuid[2] = id.ecx; + ipe->cpuid[3] = id.edx; + ipe->validation |= I32X64SEC_VALID_CPUID; + + return entry; +} + +static const char * const generic_error_types[] = { + "PROCESSOR_GENERIC", + "PROCESSOR_SPECIFIC_X86", + "PROCESSOR_SPECIFIC_ARM", + "PLATFORM_MEMORY", + "PLATFORM_MEMORY2", + "PCIE", + "FW_ERROR_RECORD", + "PCI_PCIX_BUS", + "PCI_DEVICE", + "DMAR_GENERIC", + "DIRECTED_IO_DMAR", + "IOMMU_DMAR", + "UNRECOGNIZED" +}; + +static const char *generic_error_name(guid_t *guid) +{ + if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID)) + return generic_error_types[0]; + if (!guidcmp(guid, &CPER_SEC_PROC_IA32X64_GUID)) + return generic_error_types[1]; + if (!guidcmp(guid, &CPER_SEC_PROC_ARM_GUID)) + return generic_error_types[2]; + if (!guidcmp(guid, &CPER_SEC_PLATFORM_MEM_GUID)) + return generic_error_types[3]; + if (!guidcmp(guid, &CPER_SEC_PLATFORM_MEM2_GUID)) + return generic_error_types[4]; + if (!guidcmp(guid, &CPER_SEC_PCIE_GUID)) + return generic_error_types[5]; + if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID)) + return generic_error_types[6]; + if (!guidcmp(guid, &CPER_SEC_PCI_X_BUS_GUID)) + return generic_error_types[7]; + if (!guidcmp(guid, &CPER_SEC_PCI_DEV_GUID)) + return generic_error_types[8]; + if (!guidcmp(guid, &CPER_SEC_DMAR_GENERIC_GUID)) + return generic_error_types[9]; + if (!guidcmp(guid, &CPER_SEC_DMAR_VT_GUID)) + return generic_error_types[10]; + if (!guidcmp(guid, &CPER_SEC_DMAR_IOMMU_GUID)) + return generic_error_types[11]; + return generic_error_types[12]; +} + +/* 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. + */ +acpi_generic_error_status_t *bert_new_event(guid_t *guid) +{ + size_t size; + acpi_generic_error_status_t *status; + acpi_hest_generic_data_v300_t *entry, *r; + + size = sizeof(*status); + size += sizeof(*entry); + size += sizeof_error_section(guid); + + if (size > bert_storage_remaining()) { + printk(BIOS_ERR, "Error: Not enough BERT region space to add event for type %s\n", + generic_error_name(guid)); + return NULL; + } + + status = new_bert_status(); + if (!status) + return NULL; + + 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); + /* else if other types not implemented */ + else + r = NULL; + + if (r) + return status; + return NULL; +} + +/* Helper to add an MSR context to an existing IA32/X64-type error entry */ +cper_ia32x64_context_t *cper_new_ia32x64_context_msr( + acpi_generic_error_status_t *status, + cper_ia32x64_proc_error_section_t *x86err, u32 addr, int num) +{ + cper_ia32x64_context_t *ctx; + int i; + msr_t *dest; + + ctx = new_cper_ia32x64_ctx(status, x86err, CPER_IA32X64_CTX_MSR, num); + if (!ctx) + return NULL; + + /* already filled ctx->type = CPER_IA32X64_CTX_MSR; */ + ctx->msr_addr = addr; + ctx->array_size = num * sizeof(msr_t); + + dest = (msr_t *)((u8 *)(ctx + 1)); /* point to the Register Array */ + + for (i = 0 ; i < num ; i++) + *(dest + i) = rdmsr(addr + i); + return ctx; +} + +/* The region must be in memory marked as reserved. If not implemented, + * skip generating the information in the region. + */ +__weak void bert_reserved_region(void **start, size_t *size) +{ + printk(BIOS_ERR, "Error: %s not implemented. BERT region generation disabled\n", + __func__); + *start = NULL; + *size = 0; +} + +static void bert_storage_setup(int unused) +{ + /* Always start with a blank bert region. Make sure nothing is + * maintained across reboots or resumes. + */ + bert_region_broken = 0; + bert_region_used = 0; + + bert_reserved_region(&bert_region_base, &bert_region_size); + + if (!bert_region_base || !bert_region_size) { + printk(BIOS_ERR, "Bug: Can't find/add BERT storage area\n"); + bert_region_broken = 1; + return; + } + + memset(bert_region_base, 0, bert_region_size); +} + +RAMSTAGE_CBMEM_INIT_HOOK(bert_storage_setup) diff --git a/src/arch/x86/include/arch/bert_storage.h b/src/arch/x86/include/arch/bert_storage.h new file mode 100644 index 0000000000..c96918c990 --- /dev/null +++ b/src/arch/x86/include/arch/bert_storage.h @@ -0,0 +1,143 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 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; 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. + */ + +#ifndef _BERT_STORAGE_H_ +#define _BERT_STORAGE_H_ + +#include <stdint.h> +#include <arch/acpi.h> + +/* Items in the BERT region + * + * * Each item begins with a Generic Error Status Block + * * Zero or more Generic Error Data Entries follow, and + * are associated with the Status Block + * * Each Generic Error Data Entry must be a certain type, + * as defined in the UEFI CPER appendix + * * Each type may allow zero or more additional sets of + * data, e.g. error descriptions, or processor contexts. + * + * In the example layout below, there are three BERT region + * entries. The first two are a single error. The third + * has two errors, with one providing a variable amount + * of additional information. + * + * +====================================================================+ + * | Generic Error | Generic Error | Platform Memory Error | + * | Status | Data Entry | | + * |====================================================================| + * | Generic Error | Generic Error | Generic Processor Error | + * | Status | Data Entry | | + * |====================================================================| + * | Generic Error | Generic Error | IA32/X64 Processor Error | + * | Status | Data Entry | +----------------------------+ + * | | | | Error Check Data | + * | | | +----------------------------+ + * | | | | MSR Context | + * | | | +----------------------------+ + * | | | | X64 Registers Context | + * | +-----------------+----+----------------------------+ + * | | Generic Error | PCI Express Error | + * | | Data Entry | | + * +--------------------------------------------------------------------+ + */ + +/* Get implementation-specific reserved area for generating BERT info */ +void bert_reserved_region(void **start, size_t *size); + +/* Get the region where BERT error structures have been constructed for + * generating the ACPI table + */ +void bert_errors_region(void **start, size_t *size); + +/* Get amount of available storage left for error info */ +size_t bert_storage_remaining(void); +/* Find if errors were added, a BERT region is present, and ACPI table needed */ +int bert_errors_present(void); + +/* Get the number of entries accociated with status */ +static inline size_t bert_entry_count(acpi_generic_error_status_t *status) +{ + return (status->block_status & GENERIC_ERR_STS_ENTRY_COUNT_MASK) + >> GENERIC_ERR_STS_ENTRY_COUNT_SHIFT; +} + +/* Increment the number of entries this status describes */ +static inline void bert_bump_entry_count(acpi_generic_error_status_t *status) +{ + int count; + + count = bert_entry_count(status) + 1; + status->block_status &= ~GENERIC_ERR_STS_ENTRY_COUNT_MASK; + status->block_status |= count << GENERIC_ERR_STS_ENTRY_COUNT_SHIFT; +} + +/* Find the address of the first Generic Data structure from its status entry */ +static inline acpi_hest_generic_data_v300_t *acpi_hest_generic_data3( + acpi_generic_error_status_t *status) +{ + return (acpi_hest_generic_data_v300_t *) + ((u8 *)status + sizeof(*status)); +} + +/* Find the address of a Generic Data structure's CPER error record section */ +#define section_of_acpientry(A, B) ((typeof(A))((u8 *)(B) + sizeof(*(B)))) + + +/* Add a context to an existing IA32/X64-type error entry */ +cper_ia32x64_context_t *new_cper_ia32x64_ctx( + acpi_generic_error_status_t *status, + cper_ia32x64_proc_error_section_t *x86err, int type, int num); + +/* Helper to add an MSR context to an existing IA32/X64-type error entry */ +cper_ia32x64_context_t *cper_new_ia32x64_context_msr( + acpi_generic_error_status_t *status, + cper_ia32x64_proc_error_section_t *x86err, u32 addr, int num); + +/* Add check info to an existing IA32/X64-type error entry */ +cper_ia32x64_proc_error_info_t *new_cper_ia32x64_check( + acpi_generic_error_status_t *status, + cper_ia32x64_proc_error_section_t *x86err, + enum cper_x86_check_type type); + +/* 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 + * of the error section. + */ +acpi_hest_generic_data_v300_t *bert_append_error_datasection( + acpi_generic_error_status_t *status, guid_t *guid); + +/* Helper to append an ACPI Generic Error Data Entry plus a CPER Processor + * Generic Error Section. As many fields are populated as possible for the + * caller. + */ +acpi_hest_generic_data_v300_t *bert_append_genproc( + acpi_generic_error_status_t *status); + +/* Helper to append an ACPI Generic Error Data Entry plus a CPER IA32/X64 + * Processor Error Section. As many fields are populated as possible for the + * caller. + */ +acpi_hest_generic_data_v300_t *bert_append_ia32x64( + 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. + */ +acpi_generic_error_status_t *bert_new_event(guid_t *guid); + +#endif /* _BERT_STORAGE_H_ */ |