From c24a12db860f33cee2a8ff4c7fd66af3775fba5d Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Wed, 12 Feb 2025 16:46:08 +0000 Subject: [PATCH] util/cbmem: Consolidate CBMEM and coreboot table access Provide common functions for accessing CBMEM and coreboot table entries instead of mapping them manually in each function. New functions return a copy of requested region as a heap-allocated buffer thus avoiding a need for aligned memory access. Remove global variables wherever possible to make code easier to read and to isolate responsibilities of functions. Use CBMEM entries instead of coreboot table records directly, but provide fallback for old systems in case the correcponding CBMEM entry does not exist. BUG=b:391874512 TEST=cbmem -l; cbmem -x; cbmem -r 434f4e53; cbmem -t; cbmem -a 1200 Change-Id: I89b371e27ab3840cfbbd44880c32383b77f65e5c Signed-off-by: Jakub Czapiga Reviewed-on: https://review.coreboot.org/c/coreboot/+/87417 Tested-by: build bot (Jenkins) Reviewed-by: Julius Werner --- util/cbmem/cbmem.c | 683 +++++++++++++++++++++++---------------------- 1 file changed, 353 insertions(+), 330 deletions(-) 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)