diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c index bdb6794dbf..9fc4060302 100644 --- a/util/cbmem/cbmem.c +++ b/util/cbmem/cbmem.c @@ -35,9 +35,6 @@ #include #endif -/* Return < 0 on error, 0 on success. */ -static int parse_cbtable(uint64_t address, size_t table_size); - struct mapping { void *virt; size_t offset; @@ -56,9 +53,6 @@ static int verbose = 0; static int mem_fd; static struct mapping lbtable_mapping; -/* TSC frequency from the LB_TAG_TSC_INFO record. 0 if not present. */ -static uint32_t tsc_freq_khz = 0; - static void die(const char *msg) { if (msg) @@ -195,57 +189,6 @@ static void *aligned_memcpy(void *dest, const void *src, size_t n) return dest; } -/* Find the first cbmem entry filling in the details. */ -static int find_cbmem_entry(uint32_t id, uint64_t *addr, size_t *size) -{ - const uint8_t *table; - size_t offset; - int ret = -1; - - table = mapping_virt(&lbtable_mapping); - - if (table == NULL) - return -1; - - offset = 0; - - while (offset < mapping_size(&lbtable_mapping)) { - const struct lb_record *lbr; - struct lb_cbmem_entry lbe; - - lbr = (const void *)(table + offset); - offset += lbr->size; - - if (lbr->tag != LB_TAG_CBMEM_ENTRY) - continue; - - aligned_memcpy(&lbe, lbr, sizeof(lbe)); - if (lbe.id != id) - continue; - - *addr = lbe.address; - *size = lbe.entry_size; - ret = 0; - break; - } - - return ret; -} - -/* - * Try finding the timestamp table and coreboot cbmem console starting from the - * passed in memory offset. Could be called recursively in case a forwarding - * entry is found. - * - * Returns pointer to a memory buffer containing the timestamp table or zero if - * none found. - */ - -static struct lb_cbmem_ref timestamps; -static struct lb_cbmem_ref console; -static struct lb_cbmem_ref tpm_cb_log; -static struct lb_memory_range cbmem; - /* This is a work-around for a nasty problem introduced by initially having * pointer sized entries in the lb_cbmem_ref structures. This caused problems * on 64bit x86 systems because coreboot is 32bit on those systems. @@ -267,90 +210,168 @@ static struct lb_cbmem_ref parse_cbmem_ref(const struct lb_cbmem_ref *cbmem_ref) return ret; } -static void parse_memory_tags(const struct lb_memory *mem) +static uint32_t cbmem_id_to_lb_tag(uint32_t tag) { - int num_entries; - int i; - - /* Peel off the header size and calculate the number of entries. */ - num_entries = (mem->size - sizeof(*mem)) / sizeof(mem->map[0]); - - for (i = 0; i < num_entries; i++) { - if (mem->map[i].type != LB_MEM_TABLE) - continue; - debug(" LB_MEM_TABLE found.\n"); - /* The last one found is CBMEM */ - aligned_memcpy(&cbmem, &mem->map[i], sizeof(cbmem)); + /* Minimal subset. Expand based on the CBMEM to coreboot table + records mapping in lib/coreboot_table.c */ + switch (tag) { + case CBMEM_ID_TIMESTAMP: + return LB_TAG_TIMESTAMPS; + case CBMEM_ID_CONSOLE: + return LB_TAG_CBMEM_CONSOLE; + case CBMEM_ID_TPM_CB_LOG: + return LB_TAG_TPM_CB_LOG; } + return LB_TAG_UNUSED; } -/* Return < 0 on error, 0 on success, 1 if forwarding table entry found. */ -static int parse_cbtable_entries(const struct mapping *table_mapping) +struct cbmem_console { + uint32_t size; + uint32_t cursor; + uint8_t body[]; +} __packed; + +#define CBMC_CURSOR_MASK ((1 << 28) - 1) +#define CBMC_OVERFLOW (1 << 31) + + +/* Find the first cbmem entry filling in the details. */ +static int find_cbmem_entry(uint32_t id, uint64_t *addr, size_t *size) { - size_t i; - const struct lb_record *lbr_p; - size_t table_size = mapping_size(table_mapping); - const void *lbtable = mapping_virt(table_mapping); - int forwarding_table_found = 0; + const uint8_t *table; + size_t offset = 0; + const uint32_t legacy_tag = cbmem_id_to_lb_tag(id); + struct lb_cbmem_ref *ref = NULL; - for (i = 0; i < table_size; i += lbr_p->size) { - lbr_p = lbtable + i; - debug(" coreboot table entry 0x%02x\n", lbr_p->tag); - switch (lbr_p->tag) { - case LB_TAG_MEMORY: - debug(" Found memory map.\n"); - parse_memory_tags(lbtable + i); - continue; - case LB_TAG_TIMESTAMPS: { - debug(" Found timestamp table.\n"); - timestamps = - parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p); - continue; - } - case LB_TAG_CBMEM_CONSOLE: { - debug(" Found cbmem console.\n"); - console = parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p); - continue; - } - case LB_TAG_TPM_CB_LOG: { - debug(" Found TPM CB log table.\n"); - tpm_cb_log = - parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p); - continue; - } - case LB_TAG_TSC_INFO: - debug(" Found TSC info.\n"); - tsc_freq_khz = ((struct lb_tsc_info *)lbr_p)->freq_khz; - continue; - case LB_TAG_FORWARD: { - int ret; - /* - * This is a forwarding entry - repeat the - * search at the new address. - */ - struct lb_forward lbf_p = - *(const struct lb_forward *)lbr_p; - debug(" Found forwarding entry.\n"); - ret = parse_cbtable(lbf_p.forward, 0); + table = mapping_virt(&lbtable_mapping); - /* Assume the forwarding entry is valid. If this fails - * then there's a total failure. */ - if (ret < 0) - return -1; - forwarding_table_found = 1; - } - default: - break; - } + if (table == NULL) + return -1; + + const struct lb_record *lbr = NULL; + while (offset < mapping_size(&lbtable_mapping)) { + lbr = (const void *)(table + offset); + offset += lbr->size; + + /* Store coreboot table entry for later if CBMEM entry does not exist. + CBMEM entry stores size including the reserved area, so prefer it, + so more potential data and/or space is available. */ + if (legacy_tag != LB_TAG_UNUSED && lbr->tag == legacy_tag) + ref = (struct lb_cbmem_ref *)lbr; + + if (lbr->tag != LB_TAG_CBMEM_ENTRY) + continue; + + struct lb_cbmem_entry lbe; + aligned_memcpy(&lbe, lbr, sizeof(lbe)); + if (lbe.id != id) + continue; + + *addr = lbe.address; + *size = lbe.entry_size; + return 0; } - return forwarding_table_found; + /* No mapping and/or no potential reference means that + the requested entry does not exit. */ + if (legacy_tag == LB_TAG_UNUSED || ref == NULL) + return -1; + + debug("Found coreboot table record equivalent of CBMEM entry id: %#x, tag: %#x\n", id, + legacy_tag); + + const struct lb_cbmem_ref lbc = parse_cbmem_ref(ref); + size_t header_map_size = 0; + + /* Process legacy coreboot table entries */ + switch (lbc.tag) { + case LB_TAG_TIMESTAMPS: + header_map_size = sizeof(struct timestamp_table); + break; + case LB_TAG_CBMEM_CONSOLE: + header_map_size = sizeof(struct cbmem_console); + break; + case LB_TAG_TPM_CB_LOG: + header_map_size = sizeof(struct tpm_cb_log_table); + break; + } + + struct mapping entry_mapping; + const void *entry_header = NULL; + + entry_header = map_memory(&entry_mapping, lbc.cbmem_addr, header_map_size); + if (!entry_header) { + fprintf(stderr, "Unable to map header for coreboot table entry id: %#x\n", + legacy_tag); + abort(); + } + + *addr = lbc.cbmem_addr; + + switch (legacy_tag) { + case LB_TAG_TIMESTAMPS: { + const struct timestamp_table *tst_p = entry_header; + *size = sizeof(*tst_p) + tst_p->num_entries * sizeof(tst_p->entries[0]); + break; + } + case LB_TAG_CBMEM_CONSOLE: { + const struct cbmem_console *console_p = entry_header; + *size = sizeof(*console_p) + console_p->size; + break; + } + case LB_TAG_TPM_CB_LOG: { + const struct tpm_cb_log_table *tclt_p = entry_header; + *size = sizeof(*tclt_p) + tclt_p->num_entries * sizeof(tclt_p->entries[0]); + break; + } + } + + unmap_memory(&entry_mapping); + + return 0; +} + +/** + * Returns pointer to allocated buffer and size of the buffer in parameters. + * Returns zero on success. + * free() buffer after use. + */ +static int get_cbmem_entry(uint32_t id, uint8_t **buf_out, size_t *size_out) +{ + uint64_t addr; + size_t size; + struct mapping cbmem_mapping; + + if (find_cbmem_entry(id, &addr, &size)) { + debug("CBMEM entry not found. CBMEM id: %#x\n", id); + return -1; + } + + const uint8_t *buf = map_memory(&cbmem_mapping, addr, size); + if (!buf) { + fprintf(stderr, "Unable to map CBMEM entry id: %#x, size: %zu\n", id, size); + abort(); + } + + *buf_out = malloc(size); + if (!*buf_out) { + unmap_memory(&cbmem_mapping); + fprintf(stderr, + "Unable to allocate memory for CBMEM entry id: %#x, size: %zu\n", id, + size); + abort(); + } + + aligned_memcpy(*buf_out, buf, size); + unmap_memory(&cbmem_mapping); + *size_out = size; + return 0; } /* Return < 0 on error, 0 on success. */ static int parse_cbtable(uint64_t address, size_t table_size) { - const void *buf; + const uint8_t *buf; struct mapping header_mapping; size_t req_size; size_t i; @@ -360,8 +381,7 @@ static int parse_cbtable(uint64_t address, size_t table_size) if (req_size == 0) req_size = 4 * 1024; - debug("Looking for coreboot table at %" PRIx64 " %zd bytes.\n", - address, req_size); + debug("Looking for coreboot table at %" PRIx64 " %zd bytes.\n", address, req_size); buf = map_memory(&header_mapping, address, req_size); @@ -370,11 +390,10 @@ static int parse_cbtable(uint64_t address, size_t table_size) /* look at every 16 bytes */ for (i = 0; i <= req_size - sizeof(struct lb_header); i += 16) { - int ret; const struct lb_header *lbh; struct mapping table_mapping; - lbh = buf + i; + lbh = (const struct lb_header *)&buf[i]; if (memcmp(lbh->signature, "LBIO", sizeof(lbh->signature)) || !lbh->header_bytes || ipchksum(lbh, sizeof(*lbh))) { @@ -395,27 +414,32 @@ static int parse_cbtable(uint64_t address, size_t table_size) continue; } - debug("Found!\n"); + debug("Found at %#lx\n", address + i); - ret = parse_cbtable_entries(&table_mapping); + const struct lb_record *lbr_p; + const uint8_t *lbtable = mapping_virt(&table_mapping); - /* Table parsing failed. */ - if (ret < 0) { + for (size_t offset = 0; offset < lbh->table_bytes; offset += lbr_p->size) { + lbr_p = (const struct lb_record *)&lbtable[offset]; + debug(" coreboot table entry 0x%02x\n", lbr_p->tag); + + if (lbr_p->tag != LB_TAG_FORWARD) + continue; + + /* This is a forwarding entry. Repeat the search at the new address. */ + struct lb_forward lbf_p = *(const struct lb_forward *)lbr_p; + debug(" Found forwarding entry.\n"); + + const uint64_t next_addr = lbf_p.forward; + unmap_memory(&header_mapping); unmap_memory(&table_mapping); - continue; + + return parse_cbtable(next_addr, 0); } - /* Succeeded in parsing the table. Header not needed anymore. */ + debug("correct coreboot table found.\n"); unmap_memory(&header_mapping); - - /* - * Table parsing succeeded. If forwarding table not found update - * coreboot table mapping for future use. - */ - if (ret == 0) - lbtable_mapping = table_mapping; - else - unmap_memory(&table_mapping); + lbtable_mapping = table_mapping; return 0; } @@ -425,6 +449,78 @@ static int parse_cbtable(uint64_t address, size_t table_size) return -1; } +static void lb_table_get_entry(uint32_t tag, uint8_t **buf_out, size_t *size_out) +{ + const struct lb_record *lbr_p; + const uint8_t *lbtable_raw; + size_t table_size; + bool tag_found = false; + + if (get_cbmem_entry(CBMEM_ID_CBTABLE, (uint8_t **)&lbtable_raw, &table_size)) { + fprintf(stderr, "coreboot table not found.\n"); + abort(); + } + + const struct lb_header *lbh = (const struct lb_header *)lbtable_raw; + + for (size_t i = 0; i < lbh->table_bytes; i += lbr_p->size) { + lbr_p = (const struct lb_record *)(&lbtable_raw[lbh->header_bytes + i]); + if (lbr_p->tag == tag) { + tag_found = true; + break; + } + } + + if (!tag_found) { + fprintf(stderr, "coreboot table entry %#x not found.\n", tag); + free((void *)lbtable_raw); + abort(); + } + + debug("coreboot table entry %#x found.\n", tag); + + *buf_out = malloc(lbr_p->size); + if (!*buf_out) { + fprintf(stderr, + "Unable to allocate memory for coreboot table entry %#x, size: %d\n", + tag, lbr_p->size); + free((void *)lbtable_raw); + abort(); + } + memcpy(*buf_out, lbr_p, lbr_p->size); + *size_out = lbr_p->size; + free((void *)lbtable_raw); +} + + +/** + * Returns mapping, mapped buffer pointer and its size by parameters. + * Returns zero on success. + * unmap_mempry() after use. + */ +static int map_cbmem_entry_rw(uint32_t id, struct mapping *mapping, uint8_t **buf_out, + size_t *size_out) +{ + uint64_t addr; + size_t size; + + if (find_cbmem_entry(id, &addr, &size)) { + debug("CBMEM entry not found. CBMEM id: %#x\n", id); + return -1; + } + + *buf_out = map_memory_with_prot(mapping, addr, size, PROT_READ | PROT_WRITE); + if (!*buf_out) { + fprintf(stderr, + "Unable to map CBMEM entry id: %#x, size: %zu for read-write access.\n", + id, size); + abort(); + } + + *size_out = size; + return 0; +} + #if defined(linux) && (defined(__i386__) || defined(__x86_64__)) /* * read CPU frequency from a sysfs file, return an frequency in Megahertz as @@ -528,11 +624,19 @@ static uint64_t timestamp_get(uint64_t table_tick_freq_mhz) { #if defined(__i386__) || defined(__x86_64__) uint64_t tsc = __rdtsc(); + struct lb_tsc_info *tsc_info; + size_t size; /* No tick frequency specified means raw TSC values. */ if (!table_tick_freq_mhz) return tsc; + lb_table_get_entry(LB_TAG_TSC_INFO, (uint8_t **)&tsc_info, &size); + + const uint32_t tsc_freq_khz = tsc_info->freq_khz; + + free(tsc_info); + if (tsc_freq_khz) return tsc * table_tick_freq_mhz * 1000 / tsc_freq_khz; #else @@ -679,34 +783,23 @@ static void dump_timestamps(enum timestamps_print_type output_type) size_t size; uint64_t prev_stamp = 0; uint64_t total_time = 0; - struct mapping timestamp_mapping; - if (timestamps.tag != LB_TAG_TIMESTAMPS) { - fprintf(stderr, "No timestamps found in coreboot table.\n"); - return; + if (get_cbmem_entry(CBMEM_ID_TIMESTAMP, (uint8_t **)&tst_p, &size)) { + fprintf(stderr, "Timestamps not found.\n"); + abort(); } - size = sizeof(*tst_p); - tst_p = map_memory(×tamp_mapping, timestamps.cbmem_addr, size); - if (!tst_p) - die("Unable to map timestamp header\n"); - timestamp_set_tick_freq(tst_p->tick_freq_mhz); if (output_type == TIMESTAMPS_PRINT_NORMAL) printf("%d entries total:\n\n", tst_p->num_entries); - size += tst_p->num_entries * sizeof(tst_p->entries[0]); - - unmap_memory(×tamp_mapping); - - tst_p = map_memory(×tamp_mapping, timestamps.cbmem_addr, size); - if (!tst_p) - die("Unable to map full timestamp table\n"); sorted_tst_p = malloc(size + sizeof(struct timestamp_entry)); - if (!sorted_tst_p) + if (!sorted_tst_p) { + free((void *)tst_p); die("Failed to allocate memory"); - aligned_memcpy(sorted_tst_p, tst_p, size); + } + memcpy(sorted_tst_p, tst_p, size); /* * Insert a timestamp to represent the base time (start of coreboot), @@ -783,8 +876,8 @@ static void dump_timestamps(enum timestamps_print_type output_type) printf("\n"); } - unmap_memory(×tamp_mapping); free(sorted_tst_p); + free((void *)tst_p); } /* add a timestamp entry */ @@ -792,16 +885,14 @@ static void timestamp_add_now(uint32_t timestamp_id) { struct timestamp_table *tst_p; struct mapping timestamp_mapping; + size_t tst_size; - if (timestamps.tag != LB_TAG_TIMESTAMPS) { - die("No timestamps found in coreboot table.\n"); + if (map_cbmem_entry_rw(CBMEM_ID_TIMESTAMP, ×tamp_mapping, (uint8_t **)&tst_p, + &tst_size)) { + fprintf(stderr, "Unable to find timestamps.\n"); + abort(); } - tst_p = map_memory_with_prot(×tamp_mapping, timestamps.cbmem_addr, - timestamps.size, PROT_READ | PROT_WRITE); - if (!tst_p) - die("Unable to map timestamp table\n"); - /* * Note that coreboot sizes the cbmem entry in the table according to * max_entries, so it's OK to just add more entries if there's room. @@ -995,32 +1086,24 @@ static void parse_tpm2_log(const struct tcg_efi_spec_id_event *tpm2_log) } /* Dump the TPM log table in format defined by specifications */ -static void dump_tpm_std_log(uint64_t addr, size_t size) +static void dump_tpm_std_log(void *buf) { - const void *event_log; const struct tcpa_spec_entry *tspec_entry; const struct tcg_efi_spec_id_event *tcg_spec_entry; - struct mapping log_mapping; - event_log = map_memory(&log_mapping, addr, size); - if (!event_log) - die("Unable to map TPM eventlog\n"); - - tspec_entry = event_log; + tspec_entry = buf; if (!strcmp((const char *)tspec_entry->signature, TCPA_SPEC_ID_EVENT_SIGNATURE)) { if (tspec_entry->spec_version_major == 1 && - tspec_entry->spec_version_minor == 2 && - tspec_entry->spec_errata >= 1 && + tspec_entry->spec_version_minor == 2 && tspec_entry->spec_errata >= 1 && le32toh(tspec_entry->entry.event_type) == EV_NO_ACTION) { parse_tpm12_log(tspec_entry); } else { fprintf(stderr, "Unknown TPM1.2 log specification\n"); } - unmap_memory(&log_mapping); return; } - tcg_spec_entry = event_log; + tcg_spec_entry = buf; if (!strcmp((const char *)tcg_spec_entry->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE)) { if (tcg_spec_entry->spec_version_major == 2 && tcg_spec_entry->spec_version_minor == 0 && @@ -1029,42 +1112,25 @@ static void dump_tpm_std_log(uint64_t addr, size_t size) } else { fprintf(stderr, "Unknown TPM2 log specification.\n"); } - unmap_memory(&log_mapping); return; } fprintf(stderr, "Unknown TPM log specification: %.*s\n", (int)sizeof(tcg_spec_entry->signature), (const char *)tcg_spec_entry->signature); - - unmap_memory(&log_mapping); } /* dump the TPM CB log table */ static void dump_tpm_cb_log(void) { const struct tpm_cb_log_table *tclt_p; - size_t size; - struct mapping log_mapping; + size_t tclt_size; - if (tpm_cb_log.tag != LB_TAG_TPM_CB_LOG) { - fprintf(stderr, "No TPM log found in coreboot table.\n"); - return; + if (get_cbmem_entry(CBMEM_ID_TPM_CB_LOG, (uint8_t **)&tclt_p, &tclt_size)) { + fprintf(stderr, "coreboot TPM log not found.\n"); + abort(); } - size = sizeof(*tclt_p); - tclt_p = map_memory(&log_mapping, tpm_cb_log.cbmem_addr, size); - if (!tclt_p) - die("Unable to map TPM log header\n"); - - size += tclt_p->num_entries * sizeof(tclt_p->entries[0]); - - unmap_memory(&log_mapping); - - tclt_p = map_memory(&log_mapping, tpm_cb_log.cbmem_addr, size); - if (!tclt_p) - die("Unable to map full TPM log table\n"); - printf("coreboot TPM log:\n\n"); for (uint16_t i = 0; i < tclt_p->num_entries; i++) { @@ -1075,30 +1141,22 @@ static void dump_tpm_cb_log(void) printf(" %s [%s]\n", tce->digest_type, tce->name); } - unmap_memory(&log_mapping); + free((void *)tclt_p); } static void dump_tpm_log(void) { - uint64_t start; + uint8_t *buf; size_t size; - if (!find_cbmem_entry(CBMEM_ID_TCPA_TCG_LOG, &start, &size) || - !find_cbmem_entry(CBMEM_ID_TPM2_TCG_LOG, &start, &size)) - dump_tpm_std_log(start, size); - else + if (!get_cbmem_entry(CBMEM_ID_TCPA_TCG_LOG, &buf, &size) || + !get_cbmem_entry(CBMEM_ID_TPM2_TCG_LOG, &buf, &size)) { + dump_tpm_std_log(buf); + free(buf); + } else dump_tpm_cb_log(); } -struct cbmem_console { - uint32_t size; - uint32_t cursor; - uint8_t body[]; -} __attribute__ ((__packed__)); - -#define CBMC_CURSOR_MASK ((1 << 28) - 1) -#define CBMC_OVERFLOW (1 << 31) - enum console_print_type { CONSOLE_PRINT_FULL = 0, CONSOLE_PRINT_LAST, @@ -1134,50 +1192,37 @@ static void dump_console(enum console_print_type type, int max_loglevel, int pri const struct cbmem_console *console_p; char *console_c; size_t size, cursor, previous; - struct mapping console_mapping; + size_t console_buf_size; - if (console.tag != LB_TAG_CBMEM_CONSOLE) { - fprintf(stderr, "No console found in coreboot table.\n"); - return; + if (get_cbmem_entry(CBMEM_ID_CONSOLE, (uint8_t **)&console_p, &console_buf_size)) { + fprintf(stderr, "CBMEM console not found.\n"); + abort(); } - size = sizeof(*console_p); - console_p = map_memory(&console_mapping, console.cbmem_addr, size); - if (!console_p) - die("Unable to map console object.\n"); - cursor = console_p->cursor & CBMC_CURSOR_MASK; if (!(console_p->cursor & CBMC_OVERFLOW) && cursor < console_p->size) size = cursor; else size = console_p->size; - unmap_memory(&console_mapping); console_c = malloc(size + 1); if (!console_c) { fprintf(stderr, "Not enough memory for console.\n"); - exit(1); + free((void *)console_p); + abort(); } console_c[size] = '\0'; - console_p = map_memory(&console_mapping, console.cbmem_addr, - size + sizeof(*console_p)); - - if (!console_p) - die("Unable to map full console object.\n"); - if (console_p->cursor & CBMC_OVERFLOW) { if (cursor >= size) { printf("cbmem: ERROR: CBMEM console struct is illegal, " "output may be corrupt or out of order!\n\n"); cursor = 0; } - aligned_memcpy(console_c, console_p->body + cursor, - size - cursor); - aligned_memcpy(console_c + size - cursor, - console_p->body, cursor); + memcpy(console_c, console_p->body + cursor, size - cursor); + memcpy(console_c + size - cursor, console_p->body, cursor); } else { - aligned_memcpy(console_c, console_p->body, size); + memcpy(console_c, console_p->body, size); } /* Slight memory corruption may occur between reboots and give us a few @@ -1252,109 +1297,88 @@ static void dump_console(enum console_print_type type, int max_loglevel, int pri printf(BIOS_LOG_ESCAPE_RESET); free(console_c); - unmap_memory(&console_mapping); + free((void *)console_p); } -static void hexdump(unsigned long memory, int length) +/* Hexdump provided buffer using start_address as an offset in the output. */ +static void hexdump(const uintptr_t start_address, const uint8_t *buf, const int length) { int i; - const uint8_t *m; int all_zero = 0; - struct mapping hexdump_mapping; - - m = map_memory(&hexdump_mapping, memory, length); - if (!m) - die("Unable to map hexdump memory.\n"); for (i = 0; i < length; i += 16) { int j; all_zero++; for (j = 0; j < 16; j++) { - if(m[i+j] != 0) { + if (buf[i + j] != 0) { all_zero = 0; break; } } if (all_zero < 2) { - printf("%08lx:", memory + i); + printf("%08lx:", start_address + i); for (j = 0; j < 16; j++) - printf(" %02x", m[i+j]); + printf(" %02x", buf[i + j]); printf(" "); for (j = 0; j < 16; j++) - printf("%c", isprint(m[i+j]) ? m[i+j] : '.'); + printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.'); printf("\n"); } else if (all_zero == 2) { printf("...\n"); } } - - unmap_memory(&hexdump_mapping); } static void dump_cbmem_hex(void) { - if (cbmem.type != LB_MEM_TABLE) { - fprintf(stderr, "No coreboot CBMEM area found!\n"); - return; + struct mapping cbmem_mapping; + struct lb_memory *memory; + const uint8_t *buf = NULL; + size_t size = 0; + + lb_table_get_entry(LB_TAG_MEMORY, (uint8_t **)&memory, &size); + + if (!memory) + die("No memory entries available.\n"); + + const int entries = (memory->size - sizeof(*memory)) / sizeof(memory->map[0]); + /* First from the end is CBMEM */ + for (int i = entries - 1; i >= 0; --i) { + if (memory->map[i].type != LB_MEM_TABLE) + continue; + + buf = map_memory(&cbmem_mapping, memory->map[i].start, memory->map[i].size); + if (!buf) + die("Unable to map CBMEM area memory.\n"); + + size = memory->map[i].size; + break; } - hexdump(cbmem.start, cbmem.size); -} + if (!buf) + die("Unable to find CBMEM area memory entry.\n"); -static void rawdump(uint64_t base, uint64_t size) -{ - const uint8_t *m; - struct mapping dump_mapping; + hexdump(cbmem_mapping.phys, buf, size); - m = map_memory(&dump_mapping, base, size); - if (!m) - die("Unable to map rawdump memory\n"); - - for (uint64_t i = 0 ; i < size; i++) - printf("%c", m[i]); - - unmap_memory(&dump_mapping); + unmap_memory(&cbmem_mapping); + free(memory); } static void dump_cbmem_raw(unsigned int id) { - const uint8_t *table; - size_t offset; - uint64_t base = 0; - uint64_t size = 0; + uint8_t *buf; + size_t size; - table = mapping_virt(&lbtable_mapping); - - if (table == NULL) - return; - - offset = 0; - - while (offset < mapping_size(&lbtable_mapping)) { - const struct lb_record *lbr; - struct lb_cbmem_entry lbe; - - lbr = (const void *)(table + offset); - offset += lbr->size; - - if (lbr->tag != LB_TAG_CBMEM_ENTRY) - continue; - - aligned_memcpy(&lbe, lbr, sizeof(lbe)); - if (lbe.id == id) { - debug("found id for raw dump %0x", lbe.id); - base = lbe.address; - size = lbe.entry_size; - break; - } + if (get_cbmem_entry(id, &buf, &size)) { + fprintf(stderr, "cbmem entry id: %#x not found.\n", id); + abort(); } - if (!base) - fprintf(stderr, "id %0x not found in cbtable\n", id); - else - rawdump(base, size); + fwrite(buf, 1, size, stdout); + + free(buf); } struct cbmem_id_to_name { @@ -1399,34 +1423,31 @@ static void cbmem_print_entry(int n, uint32_t id, uint64_t base, uint64_t size) static void dump_cbmem_toc(void) { - int i; - const uint8_t *table; - size_t offset; + int i = 0; + const uint8_t *table = NULL; + size_t table_size = 0; - table = mapping_virt(&lbtable_mapping); + if (get_cbmem_entry(CBMEM_ID_CBTABLE, (uint8_t **)&table, &table_size)) { + fprintf(stderr, "coreboot table not found.\n"); + abort(); + } - if (table == NULL) - return; + const struct lb_header *lbh = (const struct lb_header *)table; printf("CBMEM table of contents:\n"); - printf(" %-20s %-8s %-8s %-8s\n", "NAME", "ID", "START", - "LENGTH"); + printf(" %-20s %-8s %-8s %-8s\n", "NAME", "ID", "START", "LENGTH"); - i = 0; - offset = 0; - - while (offset < mapping_size(&lbtable_mapping)) { - const struct lb_record *lbr; - struct lb_cbmem_entry lbe; - - lbr = (const void *)(table + offset); - offset += lbr->size; + const struct lb_record *lbr = NULL; + for (size_t offset = lbh->header_bytes; + offset < lbh->table_bytes + lbh->header_bytes - sizeof(struct lb_cbmem_entry); + offset += lbr->size) { + lbr = (const struct lb_record *)&table[offset]; if (lbr->tag != LB_TAG_CBMEM_ENTRY) continue; - aligned_memcpy(&lbe, lbr, sizeof(lbe)); - cbmem_print_entry(i, lbe.id, lbe.address, lbe.entry_size); + const struct lb_cbmem_entry *lbe = (const struct lb_cbmem_entry *)lbr; + cbmem_print_entry(i, lbe->id, lbe->address, lbe->entry_size); i++; } } @@ -1461,21 +1482,23 @@ static int mkpath(char *path, mode_t mode) static void dump_coverage(void) { uint64_t start; + uint8_t *coverage; size_t size; - const void *coverage; - struct mapping coverage_mapping; unsigned long phys_offset; #define phys_to_virt(x) ((void *)(unsigned long)(x) + phys_offset) + if (get_cbmem_entry(CBMEM_ID_COVERAGE, &coverage, &size)) { + fprintf(stderr, "No coverage information found\n"); + return; + } + + // Physical address is needed for pointer translation if (find_cbmem_entry(CBMEM_ID_COVERAGE, &start, &size)) { fprintf(stderr, "No coverage information found\n"); return; } /* Map coverage area */ - coverage = map_memory(&coverage_mapping, start, size); - if (!coverage) - die("Unable to map coverage area.\n"); phys_offset = (unsigned long)coverage - (unsigned long)start; printf("Dumping coverage data...\n"); @@ -1512,7 +1535,7 @@ static void dump_coverage(void) else file = NULL; } - unmap_memory(&coverage_mapping); + free(coverage); } static void print_version(void)