cmos post: Guard with spinlock

The CMOS post code storage mechanism does back-to-back
CMOS reads and writes that may be interleaved during
CPU bringup, leading to corruption of the log or of other
parts of CMOS.

Change-Id: I704813cc917a659fe034b71c2ff9eb9b80f7c949
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/58102
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/4227
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Duncan Laurie 2013-06-10 09:53:33 -07:00 committed by Stefan Reinauer
parent 35bd3fedfe
commit e807c34a5e
2 changed files with 26 additions and 3 deletions

View File

@ -1,6 +1,8 @@
#ifndef ARCH_SMP_SPINLOCK_H #ifndef ARCH_SMP_SPINLOCK_H
#define ARCH_SMP_SPINLOCK_H #define ARCH_SMP_SPINLOCK_H
#ifndef __PRE_RAM__
/* /*
* Your basic SMP spinlocks, allowing only a single CPU anywhere * Your basic SMP spinlocks, allowing only a single CPU anywhere
*/ */
@ -61,4 +63,16 @@ static inline __attribute__((always_inline)) void cpu_relax(void)
__asm__ __volatile__("rep;nop": : :"memory"); __asm__ __volatile__("rep;nop": : :"memory");
} }
#else /* !__PRE_RAM__ */
#define DECLARE_SPIN_LOCK(x)
#define barrier() do {} while(0)
#define spin_is_locked(lock) 0
#define spin_unlock_wait(lock) do {} while(0)
#define spin_lock(lock) do {} while(0)
#define spin_unlock(lock) do {} while(0)
#define cpu_relax() do {} while(0)
#endif /* !__PRE_RAM__ */
#endif /* ARCH_SMP_SPINLOCK_H */ #endif /* ARCH_SMP_SPINLOCK_H */

View File

@ -23,6 +23,7 @@
#include <console/console.h> #include <console/console.h>
#if CONFIG_CMOS_POST #if CONFIG_CMOS_POST
#include <pc80/mc146818rtc.h> #include <pc80/mc146818rtc.h>
#include <smp/spinlock.h>
#endif #endif
#include <elog.h> #include <elog.h>
@ -44,10 +45,14 @@ void __attribute__((weak)) mainboard_post(uint8_t value)
#if CONFIG_CMOS_POST #if CONFIG_CMOS_POST
DECLARE_SPIN_LOCK(cmos_post_lock)
#if !defined(__PRE_RAM__) #if !defined(__PRE_RAM__)
void cmos_post_log(void) void cmos_post_log(void)
{ {
u8 code; u8 code = 0;
spin_lock(&cmos_post_lock);
/* Get post code from other bank */ /* Get post code from other bank */
switch (cmos_read(CMOS_POST_BANK_OFFSET)) { switch (cmos_read(CMOS_POST_BANK_OFFSET)) {
@ -57,10 +62,10 @@ void cmos_post_log(void)
case CMOS_POST_BANK_1_MAGIC: case CMOS_POST_BANK_1_MAGIC:
code = cmos_read(CMOS_POST_BANK_0_OFFSET); code = cmos_read(CMOS_POST_BANK_0_OFFSET);
break; break;
default:
return;
} }
spin_unlock(&cmos_post_lock);
/* Check last post code in previous boot against normal list */ /* Check last post code in previous boot against normal list */
switch (code) { switch (code) {
case POST_OS_BOOT: case POST_OS_BOOT:
@ -80,6 +85,8 @@ void cmos_post_log(void)
static void cmos_post_code(u8 value) static void cmos_post_code(u8 value)
{ {
spin_lock(&cmos_post_lock);
switch (cmos_read(CMOS_POST_BANK_OFFSET)) { switch (cmos_read(CMOS_POST_BANK_OFFSET)) {
case CMOS_POST_BANK_0_MAGIC: case CMOS_POST_BANK_0_MAGIC:
cmos_write(value, CMOS_POST_BANK_0_OFFSET); cmos_write(value, CMOS_POST_BANK_0_OFFSET);
@ -88,6 +95,8 @@ static void cmos_post_code(u8 value)
cmos_write(value, CMOS_POST_BANK_1_OFFSET); cmos_write(value, CMOS_POST_BANK_1_OFFSET);
break; break;
} }
spin_unlock(&cmos_post_lock);
} }
#endif /* CONFIG_CMOS_POST */ #endif /* CONFIG_CMOS_POST */