/**************************************************************************** * get_lbtable * * Find the coreboot table and set global variable lbtable to point to it. ****************************************************************************/ void get_lbtable(void) { int i, bad_header_count, bad_table_count, bad_headers, bad_tables; if (lbtable != NULL) return; /* The coreboot table is located in low physical memory, which may be * conveniently accessed by calling mmap() on /dev/mem. */ if ((fd = open("/dev/mem", O_RDONLY, 0)) < 0) { fprintf(stderr, "%s: Can not open /dev/mem for reading: %s\n", prog_name, strerror(errno)); exit(1); } if ((low_phys_mem = mmap(NULL, BYTES_TO_MAP, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { fprintf(stderr, "%s: Failed to mmap /dev/mem: %s\n", prog_name, strerror(errno)); exit(1); } bad_header_count = 0; bad_table_count = 0; for (i = 0; i < NUM_MEM_RANGES; i++) { lbtable = lbtable_scan(phystov(mem_ranges[i].start), phystov(mem_ranges[i].end), &bad_headers, &bad_tables); if (lbtable != NULL) return; /* success: we found it! */ bad_header_count += bad_headers; bad_table_count += bad_tables; } fprintf(stderr, "%s: coreboot table not found. coreboot does not appear to\n" " be installed on this system. Scanning for the table " "produced the\n" " following results:\n\n" " %d valid signatures were found with bad header " "checksums.\n" " %d valid headers were found with bad table " "checksums.\n", prog_name, bad_header_count, bad_table_count); exit(1); }
/**************************************************************************** * 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; }