diff options
Diffstat (limited to 'cbtable.c')
-rw-r--r-- | cbtable.c | 77 |
1 files changed, 62 insertions, 15 deletions
@@ -26,6 +26,7 @@ #include "flash.h" #include "programmer.h" #include "coreboot_tables.h" +#include "hwaccess_physmap.h" static char *cb_vendor = NULL, *cb_model = NULL; @@ -158,7 +159,7 @@ static int lb_header_valid(struct lb_header *head, unsigned long addr) msg_pdbg("Found candidate at: %08lx-%08lx\n", addr, addr + sizeof(*head) + head->table_bytes); if (head->header_bytes != sizeof(*head)) { - msg_perr("Header bytes of %d are incorrect.\n", + msg_perr("Header bytes of %"PRId32" are incorrect.\n", head->header_bytes); return 0; } @@ -174,12 +175,12 @@ static int lb_table_valid(struct lb_header *head, struct lb_record *recs) { if (compute_checksum(recs, head->table_bytes) != head->table_checksum) { - msg_perr("Bad table checksum: %04x.\n", + msg_perr("Bad table checksum: %04"PRIx32".\n", head->table_checksum); return 0; } if (count_lb_records(head) != head->table_entries) { - msg_perr("Bad record count: %d.\n", + msg_perr("Bad record count: %"PRId32".\n", head->table_entries); return 0; } @@ -210,6 +211,62 @@ static struct lb_header *find_lb_table(void *base, unsigned long start, return NULL; } +static struct lb_header *find_lb_table_remap(unsigned long start_addr, + uint8_t **table_area) +{ + size_t offset; + unsigned long end; + size_t mapping_size; + void *base; + + mapping_size = getpagesize(); + offset = start_addr % getpagesize(); + start_addr -= offset; + + base = physmap_ro("high tables", start_addr, mapping_size); + if (ERROR_PTR == base) { + msg_perr("Failed getting access to coreboot high tables.\n"); + return NULL; + } + + for (end = getpagesize(); offset < end; offset += 16) { + struct lb_record *recs; + struct lb_header *head; + + /* No more headers to check. */ + if (end - offset < sizeof(*head)) + return NULL; + + head = (struct lb_header *)(((char *)base) + offset); + + if (!lb_header_valid(head, offset)) + continue; + + if (mapping_size - offset < head->table_bytes + sizeof(*head)) { + size_t prev_mapping_size = mapping_size; + mapping_size = head->table_bytes + sizeof(*head); + mapping_size += offset; + mapping_size += getpagesize() - (mapping_size % getpagesize()); + physunmap(base, prev_mapping_size); + base = physmap_ro("high tables", start_addr, mapping_size); + if (ERROR_PTR == base) + msg_perr("Failed getting access to coreboot high tables.\n"); + else + head = (struct lb_header *)(((char *)base) + offset); + } + + recs = (struct lb_record *)(((char *)base) + offset + sizeof(*head)); + if (!lb_table_valid(head, recs)) + continue; + msg_pdbg("Found coreboot table at 0x%08zx.\n", offset); + *table_area = base; + return head; + } + + physunmap(base, mapping_size); + return NULL; +} + static void find_mainboard(struct lb_record *ptr, unsigned long addr) { struct lb_mainboard *rec; @@ -238,13 +295,10 @@ static struct lb_record *next_record(struct lb_record *rec) static void search_lb_records(struct lb_record *rec, struct lb_record *last, unsigned long addr) { struct lb_record *next; - int count; - count = 0; for (next = next_record(rec); (rec < last) && (next <= last); rec = next, addr += rec->size) { next = next_record(rec); - count++; if (rec->tag == LB_TAG_MAINBOARD) { find_mainboard(rec, addr); break; @@ -283,15 +337,8 @@ int cb_parse_table(const char **vendor, const char **model) (((char *)lb_table) + lb_table->header_bytes); if (forward->tag == LB_TAG_FORWARD) { start = forward->forward; - start &= ~(getpagesize() - 1); physunmap_unaligned(table_area, BYTES_TO_MAP); - // FIXME: table_area is never unmapped below, nor is it unmapped above in the no-forward case - table_area = physmap_ro_unaligned("high tables", start, BYTES_TO_MAP); - if (ERROR_PTR == table_area) { - msg_perr("Failed getting access to coreboot high tables.\n"); - return -1; - } - lb_table = find_lb_table(table_area, 0x00000, 0x1000); + lb_table = find_lb_table_remap(start, &table_area); } } @@ -305,7 +352,7 @@ int cb_parse_table(const char **vendor, const char **model) (unsigned long)lb_table - (unsigned long)table_area + start); rec = (struct lb_record *)(((char *)lb_table) + lb_table->header_bytes); last = (struct lb_record *)(((char *)rec) + lb_table->table_bytes); - msg_pdbg("coreboot header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n", + msg_pdbg("coreboot header(%"PRId32") checksum: %04"PRIx32" table(%"PRId32") checksum: %04"PRIx32" entries: %"PRId32"\n", lb_table->header_bytes, lb_table->header_checksum, lb_table->table_bytes, lb_table->table_checksum, lb_table->table_entries); |