Allow coreboot to initialize CMOS if checksum is invalid.

If a file "cmos.default", type "cmos default"(0xaa) is in CBFS,
a wrong checksum leads to coreboot rewriting the first 128 bytes
(except for clock data) with the data in cmos.default, then
reboots the system so every component of coreboot works with the
same set of values.

Signed-off-by: Patrick Georgi <patrick.georgi@secunet.com>
Acked-by: Stefan Reinauer <stepan@coreboot.org>


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@6253 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
diff --git a/src/arch/x86/Kconfig b/src/arch/x86/Kconfig
index 28a65b6..aacc098 100644
--- a/src/arch/x86/Kconfig
+++ b/src/arch/x86/Kconfig
@@ -91,6 +91,13 @@
 config BOOTBLOCK_NORTHBRIDGE_INIT
 	string
 
+config HAVE_CMOS_DEFAULT
+	def_bool n
+
+config CMOS_DEFAULT_FILE
+	string
+	depends on HAVE_CMOS_DEFAULT
+
 config BOOTBLOCK_SOUTHBRIDGE_INIT
 	string
 
diff --git a/src/mainboard/getac/p470/cmos.layout b/src/mainboard/getac/p470/cmos.layout
index 73ea031..f86e479 100644
--- a/src/mainboard/getac/p470/cmos.layout
+++ b/src/mainboard/getac/p470/cmos.layout
@@ -92,7 +92,8 @@
 # coreboot config options: bootloader
 416        512       s       0        boot_devices
 928          8       h       0        boot_default
-#936         48       r       0        unused
+936          1       e       8        cmos_defaults_loaded
+#937         47       r       0        unused
 
 # coreboot config options: check sums
 984         16       h       0        check_sum
@@ -136,6 +137,8 @@
 7     0     Disable
 7     1     Enable
 7     2     Keep
+8     0     No
+8     1     Yes
 
 # -----------------------------------------------------------------
 checksums
diff --git a/src/mainboard/kontron/986lcd-m/cmos.layout b/src/mainboard/kontron/986lcd-m/cmos.layout
index a61a9de..6f26479 100644
--- a/src/mainboard/kontron/986lcd-m/cmos.layout
+++ b/src/mainboard/kontron/986lcd-m/cmos.layout
@@ -90,7 +90,8 @@
 # coreboot config options: bootloader
 416        512       s       0        boot_devices
 928          8       h       0        boot_default
-#936         12       r       0        unused
+936          1       e       11       cmos_defaults_loaded
+#937         11       r       0        unused
 
 # coreboot config options: mainboard specific options
 948          2       e       8        cpufan_cruise_control
@@ -187,6 +188,8 @@
 #10    13     69/156
 #10    14     72/161
 #10    15     75/167
+11    0     No
+11    1     Yes
 # -----------------------------------------------------------------
 checksums
 
diff --git a/src/mainboard/roda/rk886ex/cmos.layout b/src/mainboard/roda/rk886ex/cmos.layout
index 4dc9112..475823d 100644
--- a/src/mainboard/roda/rk886ex/cmos.layout
+++ b/src/mainboard/roda/rk886ex/cmos.layout
@@ -92,7 +92,8 @@
 # coreboot config options: bootloader
 416        512       s       0        boot_devices
 928          8       h       0        boot_default
-#936         48       r       0        unused
+936          1       e       8        cmos_defaults_loaded
+#937         47       r       0        unused
 
 # coreboot config options: check sums
 984         16       h       0        check_sum
@@ -136,6 +137,8 @@
 7     0     Disable
 7     1     Enable
 7     2     Keep
+8     0     No
+8     1     Yes
 
 # -----------------------------------------------------------------
 checksums
diff --git a/src/pc80/Makefile.inc b/src/pc80/Makefile.inc
index d32dfe9..0dc78bb 100644
--- a/src/pc80/Makefile.inc
+++ b/src/pc80/Makefile.inc
@@ -10,3 +10,8 @@
 
 $(obj)/pc80/mc146818rtc.ramstage.o : $(OPTION_TABLE_H)
 $(obj)/pc80/mc146818rtc_early.romstage.o : $(OPTION_TABLE_H)
+
+cbfs-files-$(CONFIG_HAVE_CMOS_DEFAULT) += $(CONFIG_CMOS_DEFAULT_FILE)
+$(CONFIG_CMOS_DEFAULT_FILE)-name := cmos.default
+$(CONFIG_CMOS_DEFAULT_FILE)-type := 0xaa
+
diff --git a/src/pc80/mc146818rtc_early.c b/src/pc80/mc146818rtc_early.c
index d09d6b9..10de0bc 100644
--- a/src/pc80/mc146818rtc_early.c
+++ b/src/pc80/mc146818rtc_early.c
@@ -1,5 +1,6 @@
 #include <pc80/mc146818rtc.h>
 #include <fallback.h>
+#include <cbfs.h>
 #if CONFIG_USE_OPTION_TABLE
 #include "option_table.h"
 #endif
@@ -11,11 +12,18 @@
 #error "CONFIG_MAX_REBOOT_CNT too high"
 #endif
 
+#include <console/loglevel.h>
+
+int do_printk(int msg_level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+#define printk_warning(fmt, arg...) do_printk(BIOS_WARNING ,fmt, ##arg)
+#define printk_debug(fmt, arg...) do_printk(BIOS_DEBUG ,fmt, ##arg)
+
 static int cmos_error(void)
 {
 	unsigned char reg_d;
 	/* See if the cmos error condition has been flagged */
 	reg_d = cmos_read(RTC_REG_D);
+	printk_debug("CMOS_REG_D(VRT): %x\n", reg_d & RTC_VRT);
 	return (reg_d & RTC_VRT) == 0;
 }
 
@@ -35,6 +43,7 @@
 	old_sum = cmos_read(LB_CKS_LOC) << 8;
 	old_sum |=  cmos_read(LB_CKS_LOC+1);
 
+	printk_debug("CMOS checksum: old = %lx, new=%lx\n", old_sum, sum);
 	return sum == old_sum;
 #else
 	return 0;
@@ -51,9 +60,26 @@
 
 static inline int do_normal_boot(void)
 {
+	char *cmos_default = cbfs_find_file("cmos.default", 0xaa);
 	unsigned char byte;
+	int i;
 
 	if (cmos_error() || !cmos_chksum_valid()) {
+		if (cmos_default) {
+			printk_warning("WARNING - CMOS CORRUPTED. RESTORING DEFAULTS.\n");
+			/* First 14 bytes are reserved for
+			   RTC and ignored by nvramtool, too.
+			   Only 128 bytes: 128+ requires cmos configuration and
+			   contains only suspend-to-ram data, which isn't part
+			   of the recovery procedure. */
+			for (i = 14; i < 128; i++) {
+				cmos_write(cmos_default[i], i);
+			}
+			/* Now reboot to run with default cmos. */
+			outb(0x06, 0xcf9);
+			for (;;) asm("hlt"); /* Wait for reset! */
+		}
+
 		/* There are no impossible values, no checksums so just
 		 * trust whatever value we have in the the cmos,
 		 * but clear the fallback bit.
diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h
index 0d33710..6fb9edd 100644
--- a/util/cbfstool/cbfs.h
+++ b/util/cbfstool/cbfs.h
@@ -76,6 +76,7 @@
 #define CBFS_COMPONENT_VSA        0x51
 #define CBFS_COMPONENT_MBI        0x52
 #define CBFS_COMPONENT_MICROCODE  0x53
+#define CBFS_COMPONENT_CMOS_DEFAULT 0xaa
 
 /* The deleted type is chosen to be a value
  * that can be written in a FLASH from all other
diff --git a/util/cbfstool/common.c b/util/cbfstool/common.c
index a42585b..0fb0200 100644
--- a/util/cbfstool/common.c
+++ b/util/cbfstool/common.c
@@ -145,6 +145,7 @@
 	{CBFS_COMPONENT_VSA, "vsa"},
 	{CBFS_COMPONENT_MBI, "mbi"},
 	{CBFS_COMPONENT_MICROCODE, "microcode"},
+	{CBFS_COMPONENT_CMOS_DEFAULT, "cmos default"},
 	{CBFS_COMPONENT_DELETED, "deleted"},
 	{CBFS_COMPONENT_NULL, "null"}
 };