drivers/pc80: Rework normal / fallback selector code
Per IRC and Gerrit discussion, the normal / fallback selector code is a rather weak spot in coreboot, and did not function correctly for certain use cases. Rework the selector to more clearly indicate proper operation, and also remove dead code. Also tentatively abandon use of RTC bit 385; a follow-up patch will remove said bit from all affected mainboards. The correct operation of the fallback code selector approximates that of a power line recloser, with a user option to attempt normal boot that can be cleared by firmware, but never set by firmware. Additionally, if cleared by user, the fallback path should always be used on the next reboot. Change-Id: I753ae9f0710c524875a85354ac2547df0c305569 Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/12289 Reviewed-by: Nico Huber <nico.h@gmx.de> Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
parent
2a4f58ac12
commit
3bfd7cc61e
|
@ -268,9 +268,12 @@ config BOOTBLOCK_SOURCE
|
||||||
config SKIP_MAX_REBOOT_CNT_CLEAR
|
config SKIP_MAX_REBOOT_CNT_CLEAR
|
||||||
bool "Do not clear reboot count after successful boot"
|
bool "Do not clear reboot count after successful boot"
|
||||||
default n
|
default n
|
||||||
|
depends on BOOTBLOCK_NORMAL
|
||||||
help
|
help
|
||||||
Do not clear the reboot count immediately after successful boot.
|
Do not clear the reboot count immediately after successful boot.
|
||||||
Set to allow the payload to control normal/fallback image recovery.
|
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
|
config UPDATE_IMAGE
|
||||||
bool "Update existing coreboot.rom image"
|
bool "Update existing coreboot.rom image"
|
||||||
|
|
|
@ -41,12 +41,24 @@ static int cmos_chksum_valid(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((unused)) int boot_count(uint8_t rtc_byte)
|
||||||
static inline __attribute__((unused)) int last_boot_normal(void)
|
|
||||||
{
|
{
|
||||||
unsigned char byte;
|
return rtc_byte >> 4;
|
||||||
byte = cmos_read(RTC_BOOT_BYTE);
|
}
|
||||||
return (byte & (1 << 1));
|
|
||||||
|
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)
|
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;
|
unsigned char byte;
|
||||||
|
|
||||||
if (cmos_error() || !cmos_chksum_valid()) {
|
if (cmos_error() || !cmos_chksum_valid()) {
|
||||||
/* There are no impossible values, no checksums so just
|
/* Invalid CMOS checksum detected!
|
||||||
* trust whatever value we have in the the cmos,
|
* Force fallback boot...
|
||||||
* but clear the fallback bit.
|
|
||||||
*/
|
*/
|
||||||
byte = cmos_read(RTC_BOOT_BYTE);
|
byte = cmos_read(RTC_BOOT_BYTE);
|
||||||
byte &= 0x0c;
|
byte &= boot_set_fallback(byte) & 0x0f;
|
||||||
byte |= CONFIG_MAX_REBOOT_CNT << 4;
|
byte |= 0xf << 4;
|
||||||
cmos_write(byte, RTC_BOOT_BYTE);
|
cmos_write(byte, RTC_BOOT_BYTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The RTC_BOOT_BYTE is now o.k. see where to go. */
|
/* The RTC_BOOT_BYTE is now o.k. see where to go. */
|
||||||
byte = cmos_read(RTC_BOOT_BYTE);
|
byte = cmos_read(RTC_BOOT_BYTE);
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_SKIP_MAX_REBOOT_CNT_CLEAR))
|
/* Are we attempting to boot normally? */
|
||||||
/* Are we in normal mode? */
|
if (boot_use_normal(byte)) {
|
||||||
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? */
|
/* Are we already at the max count? */
|
||||||
if ((byte >> 4) < CONFIG_MAX_REBOOT_CNT) {
|
if (boot_count(byte) < CONFIG_MAX_REBOOT_CNT)
|
||||||
byte += 1 << 4; /* No, add 1 to the count */
|
byte = increment_boot_count(byte);
|
||||||
}
|
else
|
||||||
else {
|
byte = boot_set_fallback(byte);
|
||||||
byte &= 0xfc; /* Yes, put in fallback mode */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save the boot byte */
|
/* Save the boot byte */
|
||||||
cmos_write(byte, RTC_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)
|
unsigned read_option_lowlevel(unsigned start, unsigned size, unsigned def)
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#define RTC_FREQ_SELECT RTC_REG_A
|
#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,
|
/* 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,
|
* reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
|
||||||
* totaling to a max high interval of 2.228 ms.
|
* totaling to a max high interval of 2.228 ms.
|
||||||
|
|
|
@ -8,23 +8,28 @@
|
||||||
|
|
||||||
static void set_boot_successful(void)
|
static void set_boot_successful(void)
|
||||||
{
|
{
|
||||||
/* Remember I successfully booted by setting
|
uint8_t index, byte;
|
||||||
* the initial boot direction
|
|
||||||
* to the direction that I booted.
|
|
||||||
*/
|
|
||||||
unsigned char index, byte;
|
|
||||||
index = inb(RTC_PORT(0)) & 0x80;
|
index = inb(RTC_PORT(0)) & 0x80;
|
||||||
index |= RTC_BOOT_BYTE;
|
index |= RTC_BOOT_BYTE;
|
||||||
outb(index, RTC_PORT(0));
|
outb(index, RTC_PORT(0));
|
||||||
|
|
||||||
byte = inb(RTC_PORT(1));
|
byte = inb(RTC_PORT(1));
|
||||||
byte &= 0xfe;
|
|
||||||
byte |= (byte & (1 << 1)) >> 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 we are in normal mode set the boot count to 0 */
|
||||||
if (!IS_ENABLED(CONFIG_SKIP_MAX_REBOOT_CNT_CLEAR))
|
if (byte & RTC_BOOT_NORMAL)
|
||||||
if(byte & 1)
|
|
||||||
byte &= 0x0f;
|
byte &= 0x0f;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
outb(byte, RTC_PORT(1));
|
outb(byte, RTC_PORT(1));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
Loading…
Reference in New Issue