-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;
- }
-
-/****************************************************************************
- * process_cmos_table
- *
- * Extract layout information from the CMOS option table and store it in our
- * internal repository.
- ****************************************************************************/
-static void process_cmos_table (void)
- { const struct cmos_enums *p;
- const struct cmos_entries *q;
- cmos_enum_t cmos_enum;
- cmos_entry_t cmos_entry;
-
- /* First add the enums. */
- for (p = first_cmos_table_enum(); p != NULL; p = next_cmos_table_enum(p))
- { cmos_enum.config_id = p->config_id;
- cmos_enum.value = p->value;
- strncpy(cmos_enum.text, (char *)p->text, CMOS_MAX_TEXT_LENGTH);
- cmos_enum.text[CMOS_MAX_TEXT_LENGTH] = '\0';
- try_add_cmos_table_enum(&cmos_enum);
- }
-
- /* Now add the entries. We must add the entries after the enums because
- * the entries are sanity checked against the enums as they are added.
- */
- for (q = first_cmos_table_entry(); q != NULL; q = next_cmos_table_entry(q))
- { cmos_entry.bit = q->bit;
- cmos_entry.length = q->length;
-
- switch (q->config)
- { case 'e':
- cmos_entry.config = CMOS_ENTRY_ENUM;
- break;
-
- case 'h':
- cmos_entry.config = CMOS_ENTRY_HEX;
- break;
-
- case 'r':
- cmos_entry.config = CMOS_ENTRY_RESERVED;
- break;
-
- case 's':
- cmos_entry.config = CMOS_ENTRY_STRING;
- break;
-
- default:
- fprintf(stderr,
- "%s: Entry in CMOS option table has unknown config "
- "value.\n", prog_name);
- exit(1);
- }
-
- cmos_entry.config_id = q->config_id;
- strncpy(cmos_entry.name, (char *)q->name, CMOS_MAX_NAME_LENGTH);
- cmos_entry.name[CMOS_MAX_NAME_LENGTH] = '\0';
- try_add_cmos_table_entry(&cmos_entry);
- }
- }
-
-/****************************************************************************
- * 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;
- }
-
-/****************************************************************************
- * try_convert_checksum_layout
- *
- * Perform sanity checking on CMOS checksum layout information and attempt to
- * convert information from bit positions to byte positions. Return OK on
- * success or an error code on failure.
- ****************************************************************************/
-static void try_convert_checksum_layout (cmos_checksum_layout_t *layout)
- { switch (checksum_layout_to_bytes(layout))
- { case OK:
- return;
-
- case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
- fprintf(stderr,
- "%s: CMOS checksummed area start is not byte-aligned.\n",
- prog_name);
- break;
-
- case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
- fprintf(stderr,
- "%s: CMOS checksummed area end is not byte-aligned.\n",
- prog_name);
- break;
-
- case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
- fprintf(stderr,
- "%s: CMOS checksum location is not byte-aligned.\n",
- prog_name);
- break;
-
- case LAYOUT_INVALID_SUMMED_AREA:
- fprintf(stderr,
- "%s: CMOS checksummed area end must be greater than "
- "CMOS checksummed area start.\n",
- prog_name);
- break;
-
- case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
- fprintf(stderr,
- "%s: CMOS checksum overlaps checksummed area.\n",
- prog_name);
- break;
-
- case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
- fprintf(stderr,
- "%s: CMOS checksummed area out of range.\n",
- prog_name);
- break;
-
- case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
- fprintf(stderr,
- "%s: CMOS checksum location out of range.\n",
- prog_name);
- break;
-
- default:
- BUG();
- }
-
- exit(1);
- }
-
-/****************************************************************************
- * try_add_cmos_table_enum
- *
- * Attempt to add a CMOS enum to our internal repository. Exit with an error
- * message on failure.
- ****************************************************************************/
-static void try_add_cmos_table_enum (cmos_enum_t *cmos_enum)
- { switch (add_cmos_enum(cmos_enum))
- { case OK:
- return;
-
- case LAYOUT_DUPLICATE_ENUM:
- fprintf(stderr, "%s: Duplicate enum %s found in CMOS option "
- "table.\n", prog_name, cmos_enum->text);
- break;
-
- default:
- BUG();
- }
-
- exit(1);
- }
-
-/****************************************************************************
- * try_add_cmos_table_entry
- *
- * Attempt to add a CMOS entry to our internal repository. Exit with an
- * error message on failure.
- ****************************************************************************/
-static void try_add_cmos_table_entry (cmos_entry_t *cmos_entry)
- { const cmos_entry_t *conflict;
-
- switch (add_cmos_entry(cmos_entry, &conflict))
- { case OK:
- return;
-
- case CMOS_AREA_OUT_OF_RANGE:
- fprintf(stderr,
- "%s: Bad CMOS option layout in CMOS option table entry "
- "%s.\n", prog_name, cmos_entry->name);
- break;
-
- case CMOS_AREA_TOO_WIDE:
- fprintf(stderr,
- "%s: Area too wide for CMOS option table entry %s.\n",
- prog_name, cmos_entry->name);
- break;
-
- case LAYOUT_ENTRY_OVERLAP:
- fprintf(stderr,
- "%s: CMOS option table entries %s and %s have overlapping "
- "layouts.\n", prog_name, cmos_entry->name, conflict->name);
- break;
-
- case LAYOUT_ENTRY_BAD_LENGTH:
- /* Silently ignore entries with zero length. Although this should
- * never happen in practice, we should handle the case in a
- * reasonable manner just to be safe.
- */
- return;
-
- default:
- BUG();
- }
-
- exit(1);
- }
+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;
+ const uint32_t *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.
+ */
+ 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;
+}