/**************************************************************************** * get_layout_from_cmos_table * * Find the CMOS table which is stored within the coreboot table and set the * global variable cmos_table to point to it. ****************************************************************************/ void get_layout_from_cmos_table(void) { get_lbtable(); cmos_table = (const struct cmos_option_table *) find_lbrec(LB_TAG_CMOS_OPTION_TABLE); process_layout(); }
/**************************************************************************** * get_cmos_checksum_info * * Get layout information for CMOS checksum. ****************************************************************************/ static void get_cmos_checksum_info(void) { const cmos_entry_t *e; struct cmos_checksum *checksum; cmos_checksum_layout_t layout; unsigned index, index2; checksum = (struct cmos_checksum *)find_lbrec(LB_TAG_OPTION_CHECKSUM); if (checksum != NULL) { /* We are lucky. The coreboot table hints us to the checksum. * We might have to check the type field here though. */ layout.summed_area_start = checksum->range_start; layout.summed_area_end = checksum->range_end; layout.checksum_at = checksum->location; try_convert_checksum_layout(&layout); cmos_checksum_start = layout.summed_area_start; cmos_checksum_end = layout.summed_area_end; cmos_checksum_index = layout.checksum_at; return; } if ((e = find_cmos_entry(checksum_param_name)) == NULL) return; /* If we get here, we are unlucky. The CMOS option table contains the * location of the CMOS checksum. However, there is no information * regarding which bytes of the CMOS area the checksum is computed over. * Thus we have to hope our presets will be fine. */ if (e->bit % 8) { fprintf(stderr, "%s: Error: CMOS checksum is not byte-aligned.\n", prog_name); exit(1); } index = e->bit / 8; index2 = index + 1; /* The CMOS checksum occupies 16 bits. */ if (verify_cmos_byte_index(index) || verify_cmos_byte_index(index2)) { fprintf(stderr, "%s: Error: CMOS checksum location out of range.\n", prog_name); exit(1); } if (((index >= cmos_checksum_start) && (index <= cmos_checksum_end)) || (((index2) >= cmos_checksum_start) && ((index2) <= cmos_checksum_end))) { fprintf(stderr, "%s: Error: CMOS checksum overlaps checksummed area.\n", prog_name); exit(1); } cmos_checksum_index = index; }
/**************************************************************************** * get_layout_from_cmos_table * * Find the CMOS table which is stored within the coreboot table and set the * global variable cmos_table to point to it. ****************************************************************************/ void get_layout_from_cmos_table(void) { get_lbtable(); cmos_table = (const struct cmos_option_table *) find_lbrec(LB_TAG_CMOS_OPTION_TABLE); if ((cmos_table) == NULL) { fprintf(stderr, "%s: CMOS option table not found in coreboot table. " "Apparently, the coreboot installed on this system was " "built without specifying CONFIG_HAVE_OPTION_TABLE.\n", prog_name); exit(1); } process_cmos_table(); get_cmos_checksum_info(); }
/**************************************************************************** * list_lbtable_item * * Show the coreboot table item specified by 'item'. ****************************************************************************/ void list_lbtable_item(const char item[]) { int i; const struct lb_record *rec; for (i = 0; i < NUM_LBTABLE_CHOICES; i++) { if (strcmp(item, lbtable_choices[i].name) == 0) break; } if (i == NUM_LBTABLE_CHOICES) { fprintf(stderr, "%s: Invalid coreboot table item %s.\n", prog_name, item); exit(1); } if ((rec = find_lbrec(lbtable_choices[i].tag)) == NULL) { fprintf(stderr, lbtable_choices[i].nofound_msg, prog_name, lbtable_choices[i].name); exit(1); } lbtable_choices[i].print_fn(rec); }
/**************************************************************************** * lbtable_scan * * Scan the chunk of memory specified by 'start' and 'end' for a coreboot * table. The first 4 bytes of the table are marked by the signature * { 'L', 'B', 'I', 'O' }. 'start' and 'end' indicate the addresses of the * first and last bytes of the chunk of memory to be scanned. For instance, * values of 0x10000000 and 0x1000ffff for 'start' and 'end' specify a 64k * chunk of memory starting at address 0x10000000. 'start' and 'end' are * physical addresses. * * If a coreboot table is found, return a pointer to it. Otherwise return * NULL. On return, *bad_header_count and *bad_table_count are set as * follows: * * *bad_header_count: * Indicates the number of times in which a valid signature was found * but the header checksum was invalid. * * *bad_table_count: * Indicates the number of times in which a header with a valid * checksum was found but the table checksum was invalid. ****************************************************************************/ static const struct lb_header *lbtable_scan(unsigned long start, unsigned long end, int *bad_header_count, int *bad_table_count) { static const char signature[4] = { 'L', 'B', 'I', 'O' }; const struct lb_header *table; const struct lb_forward *forward; unsigned long p; uint32_t sig; assert(end >= start); memcpy(&sig, signature, sizeof(sig)); table = NULL; *bad_header_count = 0; *bad_table_count = 0; /* Look for signature. Table is aligned on 16-byte boundary. Therefore * only check every fourth 32-bit memory word. As the loop is coded below, * this function will behave in a reasonable manner for ALL possible values * for 'start' and 'end': even weird boundary cases like 0x00000000 and * 0xffffffff on a 32-bit architecture. */ map_pages(start, end - start); for (p = start; (p <= end) && (end - p >= (sizeof(uint32_t) - 1)); p += 4) { if (*(uint32_t*)phystov(p) != sig) continue; /* We found a valid signature. */ table = (const struct lb_header *)phystov(p); /* validate header checksum */ if (compute_ip_checksum((void *)table, sizeof(*table))) { (*bad_header_count)++; continue; } map_pages(p, table->table_bytes + sizeof(*table)); /* validate table checksum */ if (table->table_checksum != compute_ip_checksum(((char *)table) + sizeof(*table), table->table_bytes)) { (*bad_table_count)++; continue; } /* checksums are ok: we found it! */ /* But it may just be a forwarding table, so look if there's a forwarder */ lbtable = table; forward = (struct lb_forward *)find_lbrec(LB_TAG_FORWARD); lbtable = NULL; if (forward) { uint64_t new_phys = forward->forward; table = lbtable_scan(new_phys, new_phys + getpagesize(), bad_header_count, bad_table_count); } return table; } return NULL; }
/**************************************************************************** * lbtable_scan * * Scan the chunk of memory specified by 'start' and 'end' for a coreboot * table. The first 4 bytes of the table are marked by the signature * { 'L', 'B', 'I', 'O' }. 'start' and 'end' indicate the addresses of the * first and last bytes of the chunk of memory to be scanned. For instance, * values of 0x10000000 and 0x1000ffff for 'start' and 'end' specify a 64k * chunk of memory starting at address 0x10000000. 'start' and 'end' are * virtual addresses in the address space of the current process. They * represent a chunk of memory obtained by calling mmap() on /dev/mem. * * If a coreboot table is found, return a pointer to it. Otherwise return * NULL. On return, *bad_header_count and *bad_table_count are set as * follows: * * *bad_header_count: * Indicates the number of times in which a valid signature was found * but the header checksum was invalid. * * *bad_table_count: * Indicates the number of times in which a header with a valid * checksum was found but the table checksum was invalid. ****************************************************************************/ static const struct lb_header *lbtable_scan(unsigned long start, unsigned long end, int *bad_header_count, int *bad_table_count) { static const char signature[] = { 'L', 'B', 'I', 'O' }; const struct lb_header *table; const struct lb_forward *forward; const uint32_t *p; uint32_t sig; assert(end >= start); sig = (*((const uint32_t *)signature)); table = NULL; *bad_header_count = 0; *bad_table_count = 0; /* Look for signature. Table is aligned on 16-byte boundary. Therefore * only check every fourth 32-bit memory word. As the loop is coded below, * this function will behave in a reasonable manner for ALL possible values * for 'start' and 'end': even weird boundary cases like 0x00000000 and * 0xffffffff on a 32-bit architecture. */ for (p = (const uint32_t *)start; (((unsigned long)p) <= end) && ((end - (unsigned long)p) >= (sizeof(uint32_t) - 1)); p += 4) { if (*p != sig) continue; /* We found a valid signature. */ table = (const struct lb_header *)p; /* validate header checksum */ if (compute_ip_checksum((void *)table, sizeof(*table))) { (*bad_header_count)++; continue; } /* validate table checksum */ if (table->table_checksum != compute_ip_checksum(((char *)table) + sizeof(*table), table->table_bytes)) { (*bad_table_count)++; continue; } /* checksums are ok: we found it! */ /* But it may just be a forwarding table, so look if there's a forwarder */ lbtable = table; forward = (struct lb_forward *)find_lbrec(LB_TAG_FORWARD); lbtable = NULL; if (forward) { uint64_t new_phys = forward->forward; new_phys &= ~(getpagesize() - 1); munmap((void *)low_phys_mem, BYTES_TO_MAP); if ((low_phys_mem = mmap(NULL, BYTES_TO_MAP, PROT_READ, MAP_SHARED, fd, (off_t) new_phys)) == MAP_FAILED) { fprintf(stderr, "%s: Failed to mmap /dev/mem: %s\n", prog_name, strerror(errno)); exit(1); } low_phys_base = new_phys; table = lbtable_scan(phystov(low_phys_base), phystov(low_phys_base + BYTES_TO_MAP), bad_header_count, bad_table_count); } return table; } return NULL; }