summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Reinauer <reinauer@chromium.org>2013-07-16 17:47:35 -0700
committerStefan Reinauer <stefan.reinauer@coreboot.org>2013-12-04 22:21:13 +0100
commita9c8361c02474f66c398fc292c6c5129b48578de (patch)
treede20e4cff45d7239c082fb858e7427992fc93b6c
parent7f68150f1e148528169680438ee5047bfb46cfe1 (diff)
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 <reinauer@google.com> Reviewed-on: https://gerrit.chromium.org/gerrit/62287 Reviewed-by: David Hendricks <dhendrix@chromium.org> Commit-Queue: Stefan Reinauer <reinauer@chromium.org> Tested-by: Stefan Reinauer <reinauer@chromium.org> Reviewed-on: http://review.coreboot.org/4312 Tested-by: build bot (Jenkins)
-rw-r--r--util/cbmem/cbmem.c245
1 files changed, 210 insertions, 35 deletions
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 <getopt.h>
#include <errno.h>
#include <fcntl.h>
+#include <ctype.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -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; i<MAX_CBMEM_ENTRIES; i++) {
if (entries[i].magic != CBMEM_MAGIC)
break;
+ cbmem_print_entry(i, entries[i].id,
+ entries[i].base, entries[i].size);
+ }
+}
- printf("%2d. ", i);
- switch (entries[i].id) {
- case CBMEM_ID_FREESPACE: printf("FREE SPACE "); break;
- case CBMEM_ID_GDT: printf("GDT "); break;
- case CBMEM_ID_ACPI: printf("ACPI "); break;
- case CBMEM_ID_ACPI_GNVS: printf("ACPI GNVS "); break;
- case CBMEM_ID_CBTABLE: printf("COREBOOT "); break;
- case CBMEM_ID_PIRQ: printf("IRQ TABLE "); break;
- case CBMEM_ID_MPTABLE: printf("SMP TABLE "); break;
- case CBMEM_ID_RESUME: printf("ACPI RESUME "); break;
- case CBMEM_ID_RESUME_SCRATCH: printf("ACPI SCRATCH"); break;
- case CBMEM_ID_SMBIOS: printf("SMBIOS "); break;
- case CBMEM_ID_TIMESTAMP: printf("TIME STAMP "); break;
- case CBMEM_ID_MRCDATA: printf("MRC DATA "); break;
- case CBMEM_ID_CONSOLE: printf("CONSOLE "); break;
- case CBMEM_ID_ELOG: printf("ELOG "); break;
- case CBMEM_ID_COVERAGE: printf("COVERAGE "); break;
- default: printf("%08x ",
- entries[i].id); break;
- }
- printf(" 0x%08jx 0x%08jx\n", (uintmax_t)entries[i].base,
- (uintmax_t)entries[i].size);
+static void dump_dynamic_cbmem_toc(struct cbmem_root *root)
+{
+ int i;
+ debug("CBMEM: max_entries=%d num_entries=%d locked=0x%x, size=%d\n\n",
+ root->max_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();