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)
This commit is contained in:
committed by
Stefan Reinauer
parent
7f68150f1e
commit
a9c8361c02
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the coreboot project.
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -45,7 +46,7 @@ typedef uint64_t u64;
|
|||||||
#include "cbmem.h"
|
#include "cbmem.h"
|
||||||
#include "timestamp.h"
|
#include "timestamp.h"
|
||||||
|
|
||||||
#define CBMEM_VERSION "1.0"
|
#define CBMEM_VERSION "1.1"
|
||||||
|
|
||||||
/* verbose output? */
|
/* verbose output? */
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
@@ -83,6 +84,7 @@ static void *map_memory(u64 physical)
|
|||||||
void *v;
|
void *v;
|
||||||
off_t p;
|
off_t p;
|
||||||
u64 page = getpagesize();
|
u64 page = getpagesize();
|
||||||
|
int padding;
|
||||||
|
|
||||||
/* Mapped memory must be aligned to page size */
|
/* Mapped memory must be aligned to page size */
|
||||||
p = physical & ~(page - 1);
|
p = physical & ~(page - 1);
|
||||||
@@ -101,7 +103,11 @@ static void *map_memory(u64 physical)
|
|||||||
mapped_virtual = v;
|
mapped_virtual = v;
|
||||||
|
|
||||||
/* ... but return address to the physical memory that was requested */
|
/* ... 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;
|
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))
|
if (cbmem_ref->size < sizeof(*cbmem_ref))
|
||||||
ret.cbmem_addr = (uint32_t)ret.cbmem_addr;
|
ret.cbmem_addr = (uint32_t)ret.cbmem_addr;
|
||||||
|
|
||||||
|
debug(" cbmem_addr = %" PRIx64 "\n", ret.cbmem_addr);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,6 +384,83 @@ static void dump_console(void)
|
|||||||
unmap_memory();
|
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 CBMEM_MAGIC 0x434f5245
|
||||||
#define MAX_CBMEM_ENTRIES 16
|
#define MAX_CBMEM_ENTRIES 16
|
||||||
|
|
||||||
@@ -384,52 +469,132 @@ struct cbmem_entry {
|
|||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint64_t base;
|
uint64_t base;
|
||||||
uint64_t size;
|
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" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void cbmem_print_entry(int n, uint32_t id, uint64_t base, uint64_t size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
name = NULL;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cbmem_ids); i++) {
|
||||||
|
if (cbmem_ids[i].id == id) {
|
||||||
|
name = cbmem_ids[i].name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%2d. ", n);
|
||||||
|
if (name == NULL)
|
||||||
|
printf("%08x ", id);
|
||||||
|
else
|
||||||
|
printf("%s", name);
|
||||||
|
printf(" %08" PRIx64 " ", base);
|
||||||
|
printf(" %08" PRIx64 "\n", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
static void dump_cbmem_toc(void)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
uint64_t start;
|
uint64_t start;
|
||||||
|
void *cbmem_area;
|
||||||
struct cbmem_entry *entries;
|
struct cbmem_entry *entries;
|
||||||
|
|
||||||
if (cbmem.type != LB_MEM_TABLE) {
|
if (cbmem.type != LB_MEM_TABLE) {
|
||||||
fprintf(stderr, "No coreboot table area found!\n");
|
fprintf(stderr, "No coreboot CBMEM area found!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
start = unpack_lb64(cbmem.start);
|
start = unpack_lb64(cbmem.start);
|
||||||
|
|
||||||
entries = (struct cbmem_entry *)map_memory(start);
|
cbmem_area = map_memory(start);
|
||||||
|
entries = (struct cbmem_entry *)cbmem_area;
|
||||||
|
|
||||||
printf("CBMEM table of contents:\n");
|
if (entries[0].magic == CBMEM_MAGIC) {
|
||||||
printf(" ID START LENGTH\n");
|
dump_static_cbmem_toc(entries);
|
||||||
for (i=0; i<MAX_CBMEM_ENTRIES; i++) {
|
} else {
|
||||||
if (entries[i].magic != CBMEM_MAGIC)
|
uint64_t rootptr;
|
||||||
break;
|
|
||||||
|
|
||||||
printf("%2d. ", i);
|
rootptr = unpack_lb64(cbmem.start) + unpack_lb64(cbmem.size);
|
||||||
switch (entries[i].id) {
|
rootptr &= ~(DYN_CBMEM_ALIGN_SIZE - 1);
|
||||||
case CBMEM_ID_FREESPACE: printf("FREE SPACE "); break;
|
rootptr -= sizeof(struct cbmem_root_pointer);
|
||||||
case CBMEM_ID_GDT: printf("GDT "); break;
|
unmap_memory();
|
||||||
case CBMEM_ID_ACPI: printf("ACPI "); break;
|
struct cbmem_root_pointer *r =
|
||||||
case CBMEM_ID_ACPI_GNVS: printf("ACPI GNVS "); break;
|
(struct cbmem_root_pointer *)map_memory(rootptr);
|
||||||
case CBMEM_ID_CBTABLE: printf("COREBOOT "); break;
|
if (r->magic == CBMEM_POINTER_MAGIC) {
|
||||||
case CBMEM_ID_PIRQ: printf("IRQ TABLE "); break;
|
struct cbmem_root *root;
|
||||||
case CBMEM_ID_MPTABLE: printf("SMP TABLE "); break;
|
uint64_t rootaddr = r->root;
|
||||||
case CBMEM_ID_RESUME: printf("ACPI RESUME "); break;
|
unmap_memory();
|
||||||
case CBMEM_ID_RESUME_SCRATCH: printf("ACPI SCRATCH"); break;
|
/* Note that this only works because our default mmap
|
||||||
case CBMEM_ID_SMBIOS: printf("SMBIOS "); break;
|
* size is 1MiB which happens to be larger than the
|
||||||
case CBMEM_ID_TIMESTAMP: printf("TIME STAMP "); break;
|
* root entry size which is default to be 4KiB.
|
||||||
case CBMEM_ID_MRCDATA: printf("MRC DATA "); break;
|
*/
|
||||||
case CBMEM_ID_CONSOLE: printf("CONSOLE "); break;
|
root = (struct cbmem_root *)map_memory(rootaddr);
|
||||||
case CBMEM_ID_ELOG: printf("ELOG "); break;
|
dump_dynamic_cbmem_toc(root);
|
||||||
case CBMEM_ID_COVERAGE: printf("COVERAGE "); break;
|
} else
|
||||||
default: printf("%08x ",
|
fprintf(stderr, "No valid coreboot CBMEM root pointer found.\n");
|
||||||
entries[i].id); break;
|
|
||||||
}
|
|
||||||
printf(" 0x%08jx 0x%08jx\n", (uintmax_t)entries[i].base,
|
|
||||||
(uintmax_t)entries[i].size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unmap_memory();
|
unmap_memory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,11 +720,12 @@ static void print_version(void)
|
|||||||
|
|
||||||
static void print_usage(const char *name)
|
static void print_usage(const char *name)
|
||||||
{
|
{
|
||||||
printf("usage: %s [-cCltVvh?]\n", name);
|
printf("usage: %s [-cCltxVvh?]\n", name);
|
||||||
printf("\n"
|
printf("\n"
|
||||||
" -c | --console: print cbmem console\n"
|
" -c | --console: print cbmem console\n"
|
||||||
" -C | --coverage: dump coverage information\n"
|
" -C | --coverage: dump coverage information\n"
|
||||||
" -l | --list: print cbmem table of contents\n"
|
" -l | --list: print cbmem table of contents\n"
|
||||||
|
" -x | --hexdump: print hexdump of cbmem area\n"
|
||||||
" -t | --timestamps: print timestamp information\n"
|
" -t | --timestamps: print timestamp information\n"
|
||||||
" -V | --verbose: verbose (debugging) output\n"
|
" -V | --verbose: verbose (debugging) output\n"
|
||||||
" -v | --version: print the version\n"
|
" -v | --version: print the version\n"
|
||||||
@@ -574,6 +740,7 @@ int main(int argc, char** argv)
|
|||||||
int print_console = 0;
|
int print_console = 0;
|
||||||
int print_coverage = 0;
|
int print_coverage = 0;
|
||||||
int print_list = 0;
|
int print_list = 0;
|
||||||
|
int print_hexdump = 0;
|
||||||
int print_timestamps = 0;
|
int print_timestamps = 0;
|
||||||
|
|
||||||
int opt, option_index = 0;
|
int opt, option_index = 0;
|
||||||
@@ -582,12 +749,13 @@ int main(int argc, char** argv)
|
|||||||
{"coverage", 0, 0, 'C'},
|
{"coverage", 0, 0, 'C'},
|
||||||
{"list", 0, 0, 'l'},
|
{"list", 0, 0, 'l'},
|
||||||
{"timestamps", 0, 0, 't'},
|
{"timestamps", 0, 0, 't'},
|
||||||
|
{"hexdump", 0, 0, 'x'},
|
||||||
{"verbose", 0, 0, 'V'},
|
{"verbose", 0, 0, 'V'},
|
||||||
{"version", 0, 0, 'v'},
|
{"version", 0, 0, 'v'},
|
||||||
{"help", 0, 0, 'h'},
|
{"help", 0, 0, 'h'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
while ((opt = getopt_long(argc, argv, "cCltVvh?",
|
while ((opt = getopt_long(argc, argv, "cCltxVvh?",
|
||||||
long_options, &option_index)) != EOF) {
|
long_options, &option_index)) != EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'c':
|
case 'c':
|
||||||
@@ -602,6 +770,10 @@ int main(int argc, char** argv)
|
|||||||
print_list = 1;
|
print_list = 1;
|
||||||
print_defaults = 0;
|
print_defaults = 0;
|
||||||
break;
|
break;
|
||||||
|
case 'x':
|
||||||
|
print_hexdump = 1;
|
||||||
|
print_defaults = 0;
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
print_timestamps = 1;
|
print_timestamps = 1;
|
||||||
print_defaults = 0;
|
print_defaults = 0;
|
||||||
@@ -669,6 +841,9 @@ int main(int argc, char** argv)
|
|||||||
if (print_list)
|
if (print_list)
|
||||||
dump_cbmem_toc();
|
dump_cbmem_toc();
|
||||||
|
|
||||||
|
if (print_hexdump)
|
||||||
|
dump_cbmem_hex();
|
||||||
|
|
||||||
if (print_defaults || print_timestamps)
|
if (print_defaults || print_timestamps)
|
||||||
dump_timestamps();
|
dump_timestamps();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user