Vladimir Serbinenko (phcoder@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4831
-gerrit
commit 58b0a94d1d42b091f09eb8772fffb59bc0f2ec8b Author: Vladimir Serbinenko phcoder@gmail.com Date: Mon Jan 27 00:32:50 2014 +0100
mc146818: Determine checksum position at runtime.
Change-Id: I984427545754673c5f2191fb2a40c656ea1c379a Signed-off-by: Vladimir Serbinenko phcoder@gmail.com --- src/drivers/pc80/mc146818rtc.c | 77 ++++++++++++++++++++-------- src/drivers/pc80/mc146818rtc_early.c | 97 ++++++++++++++++++++++++------------ 2 files changed, 123 insertions(+), 51 deletions(-)
diff --git a/src/drivers/pc80/mc146818rtc.c b/src/drivers/pc80/mc146818rtc.c index 51cd6c3..0f44444 100644 --- a/src/drivers/pc80/mc146818rtc.c +++ b/src/drivers/pc80/mc146818rtc.c @@ -5,7 +5,6 @@ #include <boot/coreboot_tables.h> #include <string.h> #if CONFIG_USE_OPTION_TABLE -#include "option_table.h" #include <cbfs.h> #endif #if CONFIG_HAVE_ACPI_RESUME @@ -27,28 +26,69 @@ static void rtc_update_cmos_date(u8 has_century) }
#if CONFIG_USE_OPTION_TABLE -static int rtc_checksum_valid(int range_start, int range_end, int cks_loc) +static struct cmos_checksum *get_cmos_checksum_range(void) +{ + struct cmos_option_table *ct; + struct cmos_checksum *cc; + + ct = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, "cmos_layout.bin", + CBFS_COMPONENT_CMOS_LAYOUT, NULL); + if (!ct) + return 0; + cc=(struct cmos_checksum*)((unsigned char *)ct + ct->header_length); + for(;cc->tag==LB_TAG_OPTION || cc->tag==LB_TAG_OPTION_ENUM + || cc->tag == LB_TAG_OPTION_DEFAULTS; + cc=(struct cmos_checksum*)((unsigned char *)cc + cc->size)); + if (cc->tag != LB_TAG_OPTION_CHECKSUM) + return 0; + return cc; +} + +static int overlaps_checksum(u8 byte) +{ + struct cmos_checksum *cc; + + cc = get_cmos_checksum_range(); + if (!cc) + return 0; + + return (cc->range_start <= byte) && (byte <= cc->range_end); +} + +static int rtc_checksum_valid(void) { int i; u16 sum, old_sum; + struct cmos_checksum *cc; + + cc = get_cmos_checksum_range(); + if (!cc) + return 0; + sum = 0; - for(i = range_start; i <= range_end; i++) { + for(i = cc->range_start; i <= cc->range_end; i++) { sum += cmos_read(i); } - old_sum = ((cmos_read(cks_loc)<<8) | cmos_read(cks_loc+1))&0x0ffff; + old_sum = ((cmos_read(cc->location)<<8) | cmos_read(cc->location+1))&0x0ffff; return sum == old_sum; }
-static void rtc_set_checksum(int range_start, int range_end, int cks_loc) +static void rtc_set_checksum(void) { int i; u16 sum; + struct cmos_checksum *cc; + + cc = get_cmos_checksum_range(); + if (!cc) + return; + sum = 0; - for(i = range_start; i <= range_end; i++) { + for(i = cc->range_start; i <= cc->range_end; i++) { sum += cmos_read(i); } - cmos_write(((sum >> 8) & 0x0ff), cks_loc); - cmos_write(((sum >> 0) & 0x0ff), cks_loc+1); + cmos_write(((sum >> 8) & 0x0ff), cc->location); + cmos_write(((sum >> 0) & 0x0ff), cc->location+1); } #endif
@@ -90,8 +130,7 @@ void rtc_init(int invalid) cmos_invalid = !(x & RTC_VRT);
/* See if there is a CMOS checksum error */ - checksum_invalid = !rtc_checksum_valid(PC_CKS_RANGE_START, - PC_CKS_RANGE_END,PC_CKS_LOC); + checksum_invalid = !rtc_checksum_valid();
#define CLEAR_CMOS 0 #else @@ -129,14 +168,12 @@ void rtc_init(int invalid)
#if CONFIG_USE_OPTION_TABLE /* See if there is a LB CMOS checksum error */ - checksum_invalid = !rtc_checksum_valid(LB_CKS_RANGE_START, - LB_CKS_RANGE_END,LB_CKS_LOC); + checksum_invalid = !rtc_checksum_valid(); if(checksum_invalid) printk(BIOS_DEBUG, "RTC: coreboot checksum invalid\n");
/* Make certain we have a valid checksum */ - rtc_set_checksum(PC_CKS_RANGE_START, - PC_CKS_RANGE_END,PC_CKS_LOC); + rtc_set_checksum(); #endif
/* Clear any pending interrupts */ @@ -214,7 +251,7 @@ enum cb_err get_option(void *dest, const char *name)
if(get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS) return CB_CMOS_ACCESS_ERROR; - if(!rtc_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END,LB_CKS_LOC)) + if(!rtc_checksum_valid()) return CB_CMOS_CHECKSUM_INVALID; return CB_SUCCESS; } @@ -239,21 +276,21 @@ static enum cb_err set_cmos_value(unsigned long bit, unsigned long length, uchar &= ~mask; uchar |= (ret[0] << byte_bit); cmos_write(uchar, byte); - if (byte >= LB_CKS_RANGE_START && byte <= LB_CKS_RANGE_END) + if (overlaps_checksum (byte)) chksum_update_needed = 1; } else { /* more that one byte so transfer the whole bytes */ if (byte_bit || length % 8) return CB_ERR_ARG;
- for(i=0; length; i++, length-=8, byte++) + for(i=0; length; i++, length-=8, byte++) { cmos_write(ret[i], byte); - if (byte >= LB_CKS_RANGE_START && byte <= LB_CKS_RANGE_END) + if (overlaps_checksum (byte)) chksum_update_needed = 1; + } }
if (chksum_update_needed) { - rtc_set_checksum(LB_CKS_RANGE_START, - LB_CKS_RANGE_END,LB_CKS_LOC); + rtc_set_checksum(); } return CB_SUCCESS; } diff --git a/src/drivers/pc80/mc146818rtc_early.c b/src/drivers/pc80/mc146818rtc_early.c index bb6caf1..3bf7e82 100644 --- a/src/drivers/pc80/mc146818rtc_early.c +++ b/src/drivers/pc80/mc146818rtc_early.c @@ -8,10 +8,6 @@ #endif #include <boot/coreboot_tables.h>
-#if CONFIG_USE_OPTION_TABLE -#include "option_table.h" -#endif - #ifndef CONFIG_MAX_REBOOT_CNT #error "CONFIG_MAX_REBOOT_CNT not defined" #endif @@ -27,20 +23,75 @@ static int cmos_error(void) return (reg_d & RTC_VRT) == 0; }
+#ifdef __ROMCC__ +#define const_pointer uint32_t +#else +#define const_pointer const void * +#endif + +#if CONFIG_USE_OPTION_TABLE +static const_pointer find_first_entry(void) +{ + const struct cmos_option_table *ct; +#ifdef __ROMCC__ + ct = walkcbfs("cmos_layout.bin"); +#else + ct = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, "cmos_layout.bin", + CBFS_COMPONENT_CMOS_LAYOUT, NULL); +#endif + if (!ct) + return 0; + return (const_pointer) ((const unsigned char *) ct + ct->header_length); +} + +static const_pointer find_entry(const char *name) +{ + const struct cmos_entries *ce; + + ce = (struct cmos_entries *) find_first_entry(); + if (!ce) + return 0; + for(;ce->tag==LB_TAG_OPTION; + ce=(const struct cmos_entries*)((const unsigned char *)ce + ce->size)) { + unsigned i; + for (i = 0; ; i++) { + if (!(name[i] && i < CMOS_MAX_NAME_LENGTH)) + return (const_pointer) ce; + if (name[i] != ce->name[i]) + break; + } + } + return 0; +} +#endif + static int cmos_chksum_valid(void) { #if CONFIG_USE_OPTION_TABLE unsigned char addr; u16 sum, old_sum; + const struct cmos_checksum *cc; + + cc = (struct cmos_checksum *) find_first_entry(); + + if (!cc) + return 0; + + for(;cc->tag==LB_TAG_OPTION || cc->tag==LB_TAG_OPTION_ENUM + || cc->tag == LB_TAG_OPTION_DEFAULTS; + cc=(struct cmos_checksum*)((unsigned char *)cc + cc->size)); + if (cc->tag != LB_TAG_OPTION_CHECKSUM) + return 0; + sum = 0; /* Compute the cmos checksum */ - for(addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; addr++) { + for(addr = cc->range_start; addr <= cc->range_end; addr++) { sum += cmos_read(addr); }
/* Read the stored checksum */ - old_sum = cmos_read(LB_CKS_LOC) << 8; - old_sum |= cmos_read(LB_CKS_LOC+1); + old_sum = cmos_read(cc->location) << 8; + old_sum |= cmos_read(cc->location+1);
return sum == old_sum; #else @@ -102,34 +153,18 @@ static inline int do_normal_boot(void) unsigned read_option(const char *name, unsigned def) { #if CONFIG_USE_OPTION_TABLE - struct cmos_option_table *ct; - struct cmos_entries *ce; + const struct cmos_entries *ce; + unsigned byte;
-#ifdef __ROMCC__ - ct = (struct cmos_option_table *)walkcbfs("cmos_layout.bin"); -#else - ct = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, "cmos_layout.bin", - CBFS_COMPONENT_CMOS_LAYOUT, NULL); -#endif + ce = (struct cmos_entries *)find_entry(name);
- if (!ct) + if (!ce) return def; + + byte = cmos_read(ce->bit/8); + byte >>= (ce->bit & 7U);
- ce=(struct cmos_entries*)((unsigned char *)ct + ct->header_length); - for(;ce->tag==LB_TAG_OPTION; - ce=(struct cmos_entries*)((unsigned char *)ce + ce->size)) { - unsigned byte; - unsigned i; - for (i = 0; name[i] && i < CMOS_MAX_NAME_LENGTH; i++) - if (name[i] != ce->name[i]) - goto next_option; - byte = cmos_read(ce->bit/8); - byte >>= (ce->bit & 7U); - - return (byte) & ((1U << ce->length) - 1U); - next_option:; - } - return def; + return (byte) & ((1U << ce->length) - 1U); #else return def; #endif