Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/86539?usp=email )
Change subject: arch/x86/acpi_bert: Add spinlock ......................................................................
arch/x86/acpi_bert: Add spinlock
The code may be called in parallel from MPinit. Add a spinlock to protect critical functions allocating and checking if enough space is available.
Prevents using the same region for multiple entries and prevents overallocation and possibly corrupting CBMEM.
TEST: Booted on amd/birman+ generating ACPI BERT tables.
Change-Id: Iab484149ef00797e1846441fb93407fe05ac8abb Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/arch/x86/acpi_bert_storage.c 1 file changed, 23 insertions(+), 4 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/39/86539/1
diff --git a/src/arch/x86/acpi_bert_storage.c b/src/arch/x86/acpi_bert_storage.c index 62c0441..ce45984 100644 --- a/src/arch/x86/acpi_bert_storage.c +++ b/src/arch/x86/acpi_bert_storage.c @@ -9,6 +9,7 @@ #include <acpi/acpi.h> #include <arch/bert_storage.h> #include <string.h> +#include <smp/spinlock.h> #include <types.h>
/* BERT region management: Allow the chipset to determine the specific @@ -26,12 +27,20 @@ static size_t bert_region_size; static size_t bert_region_used;
+DECLARE_SPIN_LOCK(acpi_bert_lock) + /* 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; + size_t ret; + + spin_lock(&acpi_bert_lock); + ret = bert_region_broken ? 0 : bert_region_size - bert_region_used; + spin_unlock(&acpi_bert_lock); + + return ret; }
bool bert_errors_present(void) @@ -48,23 +57,33 @@ }
/* No metadata, etc. with our region, so this is easy */ + spin_lock(&acpi_bert_lock); *start = bert_region_base; *size = bert_region_used; + spin_unlock(&acpi_bert_lock); }
static void *bert_allocate_storage(size_t size) { size_t alloc; + void *ret = NULL; + + spin_lock(&acpi_bert_lock);
if (bert_region_broken) - return NULL; + goto out; if (bert_region_used + size > bert_region_size) - return NULL; + goto out;
alloc = bert_region_used; bert_region_used += size;
- return (void *)((u8 *)bert_region_base + alloc); + ret = (void *)((u8 *)bert_region_base + alloc); + +out: + spin_unlock(&acpi_bert_lock); + + return ret; }
/* Generic Error Status: Each Status represents a unique error event within