From a9c8361c02474f66c398fc292c6c5129b48578de Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Tue, 16 Jul 2013 17:47:35 -0700 Subject: cbmem: fix userspace utility to work with dynamic CBMEM This also adds an option -x/--hexdump to dump the whole CBMEM area for debugging. Change-Id: I244955394c6a2199acf7af78ae4b8b0a6f3bfe33 Signed-off-by: Stefan Reinauer Reviewed-on: https://gerrit.chromium.org/gerrit/62287 Reviewed-by: David Hendricks Commit-Queue: Stefan Reinauer Tested-by: Stefan Reinauer Reviewed-on: http://review.coreboot.org/4312 Tested-by: build bot (Jenkins) --- util/cbmem/cbmem.c | 245 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 210 insertions(+), 35 deletions(-) (limited to 'util/cbmem/cbmem.c') diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c index cb9555630a..48918b3877 100644 --- a/util/cbmem/cbmem.c +++ b/util/cbmem/cbmem.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2012 The ChromiumOS Authors. All rights reserved. + * Copyright 2012 Google Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,7 @@ typedef uint64_t u64; #include "cbmem.h" #include "timestamp.h" -#define CBMEM_VERSION "1.0" +#define CBMEM_VERSION "1.1" /* verbose output? */ static int verbose = 0; @@ -83,6 +84,7 @@ static void *map_memory(u64 physical) void *v; off_t p; u64 page = getpagesize(); + int padding; /* Mapped memory must be aligned to page size */ p = physical & ~(page - 1); @@ -101,7 +103,11 @@ static void *map_memory(u64 physical) mapped_virtual = v; /* ... but return address to the physical memory that was requested */ - v += physical & (page-1); + padding = physical & (page-1); + if (padding) + debug(" ... padding virtual address with 0x%x bytes.\n", + padding); + v += padding; return v; } @@ -146,6 +152,8 @@ static struct lb_cbmem_ref parse_cbmem_ref(struct lb_cbmem_ref *cbmem_ref) if (cbmem_ref->size < sizeof(*cbmem_ref)) ret.cbmem_addr = (uint32_t)ret.cbmem_addr; + debug(" cbmem_addr = %" PRIx64 "\n", ret.cbmem_addr); + return ret; } @@ -376,6 +384,83 @@ static void dump_console(void) unmap_memory(); } +static void hexdump(unsigned long memory, int length) +{ + int i; + uint8_t *m; + int all_zero = 0; + + m = map_memory((intptr_t)memory); + + if (length > MAP_BYTES) { + printf("Truncating hex dump from %d to %d bytes\n\n", + length, MAP_BYTES); + length = MAP_BYTES; + } + + for (i = 0; i < length; i += 16) { + int j; + + all_zero++; + for (j = 0; j < 16; j++) { + if(m[i+j] != 0) { + all_zero = 0; + break; + } + } + + if (all_zero < 2) { + printf("%08lx:", memory + i); + for (j = 0; j < 16; j++) + printf(" %02x", m[i+j]); + printf(" "); + for (j = 0; j < 16; j++) + printf("%c", isprint(m[i+j]) ? m[i+j] : '.'); + printf("\n"); + } else if (all_zero == 2) { + printf("...\n"); + } + } + + unmap_memory(); +} + +static void dump_cbmem_hex(void) +{ + if (cbmem.type != LB_MEM_TABLE) { + fprintf(stderr, "No coreboot CBMEM area found!\n"); + return; + } + + hexdump(unpack_lb64(cbmem.start), unpack_lb64(cbmem.size)); +} + +/* The root region is at least DYN_CBMEM_ALIGN_SIZE . */ +#define DYN_CBMEM_ALIGN_SIZE (4096) +#define ROOT_MIN_SIZE DYN_CBMEM_ALIGN_SIZE +#define CBMEM_POINTER_MAGIC 0xc0389479 +#define CBMEM_ENTRY_MAGIC ~(CBMEM_POINTER_MAGIC) + +struct cbmem_root_pointer { + uint32_t magic; + uint32_t root; +} __attribute__((packed)); + +struct dynamic_cbmem_entry { + uint32_t magic; + uint32_t start; + uint32_t size; + uint32_t id; +} __attribute__((packed)); + +struct cbmem_root { + uint32_t max_entries; + uint32_t num_entries; + uint32_t locked; + uint32_t size; + struct dynamic_cbmem_entry entries[0]; +} __attribute__((packed)); + #define CBMEM_MAGIC 0x434f5245 #define MAX_CBMEM_ENTRIES 16 @@ -384,52 +469,132 @@ struct cbmem_entry { uint32_t id; uint64_t base; uint64_t size; +} __attribute__((packed)); + +static const struct cbmem_id_to_name { + u32 id; + const char *name; +} cbmem_ids[] = { + { CBMEM_ID_FREESPACE, "FREE SPACE " }, + { CBMEM_ID_GDT, "GDT " }, + { CBMEM_ID_ACPI, "ACPI " }, + { CBMEM_ID_CBTABLE, "COREBOOT " }, + { CBMEM_ID_PIRQ, "IRQ TABLE " }, + { CBMEM_ID_MPTABLE, "SMP TABLE " }, + { CBMEM_ID_RESUME, "ACPI RESUME" }, + { CBMEM_ID_RESUME_SCRATCH, "ACPISCRATCH" }, + { CBMEM_ID_ACPI_GNVS, "ACPI GNVS " }, + { CBMEM_ID_ACPI_GNVS_PTR, "GNVS PTR " }, + { CBMEM_ID_SMBIOS, "SMBIOS " }, + { CBMEM_ID_TIMESTAMP, "TIME STAMP " }, + { CBMEM_ID_MRCDATA, "MRC DATA " }, + { CBMEM_ID_CONSOLE, "CONSOLE " }, + { CBMEM_ID_ELOG, "ELOG " }, + { CBMEM_ID_COVERAGE, "COVERAGE " }, + { CBMEM_ID_ROMSTAGE_INFO, "ROMSTAGE " }, + { CBMEM_ID_ROMSTAGE_RAM_STACK, "ROMSTG STCK" }, + { CBMEM_ID_RAMSTAGE, "RAMSTAGE " }, + { CBMEM_ID_RAMSTAGE_CACHE, "RAMSTAGE $ " }, + { CBMEM_ID_ROOT, "CBMEM ROOT " }, + { CBMEM_ID_VBOOT_HANDOFF, "VBOOT " }, + { CBMEM_ID_CAR_GLOBALS, "CAR GLOBALS" }, }; -static void dump_cbmem_toc(void) +void cbmem_print_entry(int n, uint32_t id, uint64_t base, uint64_t size) { int i; - uint64_t start; - struct cbmem_entry *entries; + const char *name; - if (cbmem.type != LB_MEM_TABLE) { - fprintf(stderr, "No coreboot table area found!\n"); - return; + name = NULL; + for (i = 0; i < ARRAY_SIZE(cbmem_ids); i++) { + if (cbmem_ids[i].id == id) { + name = cbmem_ids[i].name; + break; + } } - start = unpack_lb64(cbmem.start); + printf("%2d. ", n); + if (name == NULL) + printf("%08x ", id); + else + printf("%s", name); + printf(" %08" PRIx64 " ", base); + printf(" %08" PRIx64 "\n", size); +} - entries = (struct cbmem_entry *)map_memory(start); +static void dump_static_cbmem_toc(struct cbmem_entry *entries) +{ + int i; printf("CBMEM table of contents:\n"); printf(" ID START LENGTH\n"); + for (i=0; imax_entries, root->num_entries, root->locked, root->size); + + printf("CBMEM table of contents:\n"); + printf(" ID START LENGTH\n"); + + for (i = 0; i < root->num_entries; i++) { + if(root->entries[i].magic != CBMEM_ENTRY_MAGIC) + break; + cbmem_print_entry(i, root->entries[i].id, + root->entries[i].start, root->entries[i].size); + } +} + +static void dump_cbmem_toc(void) +{ + uint64_t start; + void *cbmem_area; + struct cbmem_entry *entries; + + if (cbmem.type != LB_MEM_TABLE) { + fprintf(stderr, "No coreboot CBMEM area found!\n"); + return; + } + + start = unpack_lb64(cbmem.start); + + cbmem_area = map_memory(start); + entries = (struct cbmem_entry *)cbmem_area; + + if (entries[0].magic == CBMEM_MAGIC) { + dump_static_cbmem_toc(entries); + } else { + uint64_t rootptr; + + rootptr = unpack_lb64(cbmem.start) + unpack_lb64(cbmem.size); + rootptr &= ~(DYN_CBMEM_ALIGN_SIZE - 1); + rootptr -= sizeof(struct cbmem_root_pointer); + unmap_memory(); + struct cbmem_root_pointer *r = + (struct cbmem_root_pointer *)map_memory(rootptr); + if (r->magic == CBMEM_POINTER_MAGIC) { + struct cbmem_root *root; + uint64_t rootaddr = r->root; + unmap_memory(); + /* Note that this only works because our default mmap + * size is 1MiB which happens to be larger than the + * root entry size which is default to be 4KiB. + */ + root = (struct cbmem_root *)map_memory(rootaddr); + dump_dynamic_cbmem_toc(root); + } else + fprintf(stderr, "No valid coreboot CBMEM root pointer found.\n"); } + unmap_memory(); } @@ -555,11 +720,12 @@ static void print_version(void) static void print_usage(const char *name) { - printf("usage: %s [-cCltVvh?]\n", name); + printf("usage: %s [-cCltxVvh?]\n", name); printf("\n" " -c | --console: print cbmem console\n" " -C | --coverage: dump coverage information\n" " -l | --list: print cbmem table of contents\n" + " -x | --hexdump: print hexdump of cbmem area\n" " -t | --timestamps: print timestamp information\n" " -V | --verbose: verbose (debugging) output\n" " -v | --version: print the version\n" @@ -574,6 +740,7 @@ int main(int argc, char** argv) int print_console = 0; int print_coverage = 0; int print_list = 0; + int print_hexdump = 0; int print_timestamps = 0; int opt, option_index = 0; @@ -582,12 +749,13 @@ int main(int argc, char** argv) {"coverage", 0, 0, 'C'}, {"list", 0, 0, 'l'}, {"timestamps", 0, 0, 't'}, + {"hexdump", 0, 0, 'x'}, {"verbose", 0, 0, 'V'}, {"version", 0, 0, 'v'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "cCltVvh?", + while ((opt = getopt_long(argc, argv, "cCltxVvh?", long_options, &option_index)) != EOF) { switch (opt) { case 'c': @@ -602,6 +770,10 @@ int main(int argc, char** argv) print_list = 1; print_defaults = 0; break; + case 'x': + print_hexdump = 1; + print_defaults = 0; + break; case 't': print_timestamps = 1; print_defaults = 0; @@ -669,6 +841,9 @@ int main(int argc, char** argv) if (print_list) dump_cbmem_toc(); + if (print_hexdump) + dump_cbmem_hex(); + if (print_defaults || print_timestamps) dump_timestamps(); -- cgit v1.2.3