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 last_boot_normal(void) +static inline __attribute__((unused)) int boot_count(uint8_t rtc_byte) { - unsigned char byte; - byte = cmos_read(RTC_BOOT_BYTE); - return (byte & (1 << 1)); + return rtc_byte >> 4; +} + +static inline __attribute__((unused)) uint8_t increment_boot_count(uint8_t rtc_byte) +{ + 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