summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Kconfig3
-rw-r--r--src/drivers/pc80/mc146818rtc_early.c56
-rw-r--r--src/include/pc80/mc146818rtc.h2
-rw-r--r--src/lib/fallback_boot.c25
4 files changed, 49 insertions, 37 deletions
diff --git a/src/Kconfig b/src/Kconfig
index 79d5994bb2..865f7f5c5b 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -268,9 +268,12 @@ config BOOTBLOCK_SOURCE
config SKIP_MAX_REBOOT_CNT_CLEAR
bool "Do not clear reboot count after successful boot"
default n
+ depends on BOOTBLOCK_NORMAL
help
Do not clear the reboot count immediately after successful boot.
Set to allow the payload to control normal/fallback image recovery.
+ Note that it is the responsibility of the payload to reset the
+ normal boot bit to 1 after each successsful boot.
config UPDATE_IMAGE
bool "Update existing coreboot.rom image"
diff --git a/src/drivers/pc80/mc146818rtc_early.c b/src/drivers/pc80/mc146818rtc_early.c
index 421af2f92f..268cfc2fe6 100644
--- a/src/drivers/pc80/mc146818rtc_early.c
+++ b/src/drivers/pc80/mc146818rtc_early.c
@@ -41,12 +41,24 @@ static int cmos_chksum_valid(void)
#endif
}
+static inline __attribute__((unused)) int boot_count(uint8_t rtc_byte)
+{
+ return rtc_byte >> 4;
+}
-static inline __attribute__((unused)) int last_boot_normal(void)
+static inline __attribute__((unused)) uint8_t increment_boot_count(uint8_t rtc_byte)
{
- unsigned char byte;
- byte = cmos_read(RTC_BOOT_BYTE);
- return (byte & (1 << 1));
+ return rtc_byte + (1 << 4);
+}
+
+static inline __attribute__((unused)) uint8_t boot_set_fallback(uint8_t rtc_byte)
+{
+ return rtc_byte & ~RTC_BOOT_NORMAL;
+}
+
+static inline __attribute__((unused)) int boot_use_normal(uint8_t rtc_byte)
+{
+ return rtc_byte & RTC_BOOT_NORMAL;
}
static inline __attribute__((unused)) int do_normal_boot(void)
@@ -54,42 +66,32 @@ static inline __attribute__((unused)) int do_normal_boot(void)
unsigned char byte;
if (cmos_error() || !cmos_chksum_valid()) {
- /* There are no impossible values, no checksums so just
- * trust whatever value we have in the the cmos,
- * but clear the fallback bit.
+ /* Invalid CMOS checksum detected!
+ * Force fallback boot...
*/
byte = cmos_read(RTC_BOOT_BYTE);
- byte &= 0x0c;
- byte |= CONFIG_MAX_REBOOT_CNT << 4;
+ byte &= boot_set_fallback(byte) & 0x0f;
+ byte |= 0xf << 4;
cmos_write(byte, RTC_BOOT_BYTE);
}
/* The RTC_BOOT_BYTE is now o.k. see where to go. */
byte = cmos_read(RTC_BOOT_BYTE);
- if (!IS_ENABLED(CONFIG_SKIP_MAX_REBOOT_CNT_CLEAR))
- /* Are we in normal mode? */
- if (byte & 1)
- byte &= 0x0f; /* yes, clear the boot count */
-
- /* Properly set the last boot flag */
- byte &= 0xfc;
- if ((byte >> 4) < CONFIG_MAX_REBOOT_CNT) {
- byte |= (1<<1);
- }
-
- /* Are we already at the max count? */
- if ((byte >> 4) < CONFIG_MAX_REBOOT_CNT) {
- byte += 1 << 4; /* No, add 1 to the count */
- }
- else {
- byte &= 0xfc; /* Yes, put in fallback mode */
+ /* Are we attempting to boot normally? */
+ if (boot_use_normal(byte)) {
+ /* Are we already at the max count? */
+ if (boot_count(byte) < CONFIG_MAX_REBOOT_CNT)
+ byte = increment_boot_count(byte);
+ else
+ byte = boot_set_fallback(byte);
}
/* Save the boot byte */
cmos_write(byte, RTC_BOOT_BYTE);
- return (byte & (1<<1));
+ /* Return selected code path for this boot attempt */
+ return boot_use_normal(byte);
}
unsigned read_option_lowlevel(unsigned start, unsigned size, unsigned def)
diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h
index 0e15273fc4..38f2ad085c 100644
--- a/src/include/pc80/mc146818rtc.h
+++ b/src/include/pc80/mc146818rtc.h
@@ -25,6 +25,8 @@
**********************************************************************/
#define RTC_FREQ_SELECT RTC_REG_A
+#define RTC_BOOT_NORMAL 0x1
+
/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
* reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
* totaling to a max high interval of 2.228 ms.
diff --git a/src/lib/fallback_boot.c b/src/lib/fallback_boot.c
index 74572df323..203071fc8a 100644
--- a/src/lib/fallback_boot.c
+++ b/src/lib/fallback_boot.c
@@ -8,23 +8,28 @@
static void set_boot_successful(void)
{
- /* Remember I successfully booted by setting
- * the initial boot direction
- * to the direction that I booted.
- */
- unsigned char index, byte;
+ uint8_t index, byte;
+
index = inb(RTC_PORT(0)) & 0x80;
index |= RTC_BOOT_BYTE;
outb(index, RTC_PORT(0));
byte = inb(RTC_PORT(1));
- byte &= 0xfe;
- byte |= (byte & (1 << 1)) >> 1;
- /* If we are in normal mode set the boot count to 0 */
- if (!IS_ENABLED(CONFIG_SKIP_MAX_REBOOT_CNT_CLEAR))
- if(byte & 1)
+ if (IS_ENABLED(CONFIG_SKIP_MAX_REBOOT_CNT_CLEAR)) {
+ /* Set the fallback boot bit to allow for recovery if
+ * the payload fails to boot.
+ * It is the responsibility of the payload to reset
+ * the normal boot bit to 1 if desired
+ */
+ byte &= ~RTC_BOOT_NORMAL;
+ } else {
+ /* If we are in normal mode set the boot count to 0 */
+ if (byte & RTC_BOOT_NORMAL)
byte &= 0x0f;
+
+ }
+
outb(byte, RTC_PORT(1));
}
#else