Mattias Nissler has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/62639 )
Change subject: util/cbmem: add an option to append timestamp ......................................................................
util/cbmem: add an option to append timestamp
Add an option to the cbmem utility that can be used to append an entry to the cbmem timestamp table from userspace. This is useful for bookkeeping of post-coreboot timing information while still being able to use cbmem-based tooling for processing the generated data.
BUG=b:217638034 BRANCH=none TEST=Manual, invoke new cbmem option, then verify that cbmem -t shows the added timestamp.
Change-Id: Ic99e5a11d8cc3f9fffae8eaf2787652105cf4842 Signed-off-by: Mattias Nissler mnissler@chromium.org --- M util/cbmem/cbmem.c 1 file changed, 78 insertions(+), 7 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/39/62639/1
diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c index a39ef2a..72c7017 100644 --- a/util/cbmem/cbmem.c +++ b/util/cbmem/cbmem.c @@ -79,9 +79,9 @@ }
/* Return mapping of physical address requested. */ -static const void *mapping_virt(const struct mapping *mapping) +static void *mapping_virt(const struct mapping *mapping) { - const char *v = mapping->virt; + char *v = mapping->virt;
if (v == NULL) return NULL; @@ -90,8 +90,8 @@ }
/* Returns virtual address on success, NULL on error. mapping is filled in. */ -static const void *map_memory(struct mapping *mapping, unsigned long long phys, - size_t sz) +static void *map_memory_with_prot(struct mapping *mapping, + unsigned long long phys, size_t sz, int prot) { void *v; unsigned long long page_size; @@ -113,7 +113,7 @@ phys); }
- v = mmap(NULL, mapping->virt_size, PROT_READ, MAP_SHARED, mem_fd, + v = mmap(NULL, mapping->virt_size, prot, MAP_SHARED, mem_fd, phys - mapping->offset);
if (v == MAP_FAILED) { @@ -131,6 +131,14 @@ return mapping_virt(mapping); }
+/* Convenience helper for the common case of read-only mappings. */ +static const void *map_memory(struct mapping *mapping, unsigned long long phys, + size_t sz) +{ + return map_memory_with_prot(mapping, phys, sz, PROT_READ); +} + + /* Returns 0 on success, < 0 on error. mapping is cleared if successful. */ static int unmap_memory(struct mapping *mapping) { @@ -528,6 +536,16 @@ } }
+static uint64_t timestamp_get(void) +{ +#if defined(__x86_64__) + return __rdtsc(); +#else + fprintf(stderr, + "Don't know how to obtain timestamps on this platform.\n"); +#endif +} + static const char *timestamp_name(uint32_t id) { for (size_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++) { @@ -537,6 +555,15 @@ return "<unknown>"; }
+static uint32_t timestamp_name_to_id(const char *name) +{ + for (size_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++) { + if (!strcmp(timestamp_ids[i].name, name)) + return timestamp_ids[i].id; + } + return 0; +} + static uint64_t timestamp_print_parseable_entry(uint32_t id, uint64_t stamp, uint64_t prev_stamp) { @@ -673,6 +700,38 @@ free(sorted_tst_p); }
+/* add a timestamp entry */ +static void timestamp_add_now(uint32_t timestamp_id) +{ + struct timestamp_table *tst_p; + struct mapping timestamp_mapping; + + if (timestamps.tag != LB_TAG_TIMESTAMPS) { + fprintf(stderr, "No timestamps found in coreboot table.\n"); + return; + } + + 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. + */ + if (tst_p->num_entries >= tst_p->max_entries) { + fprintf(stderr, "Not enough space to add timestamp.\n"); + } else { + int64_t time = timestamp_get() - tst_p->base_time; + tst_p->entries[tst_p->num_entries].entry_id = timestamp_id; + tst_p->entries[tst_p->num_entries].entry_stamp = time; + tst_p->num_entries += 1; + } + + unmap_memory(×tamp_mapping); +} + /* dump the tcpa log table */ static void dump_tcpa_log(void) { @@ -1304,6 +1363,7 @@ unsigned int rawdump_id = 0; int max_loglevel = BIOS_NEVER; int print_unknown_logs = 1; + uint32_t timestamp_id = 0;
int opt, option_index = 0; static struct option long_options[] = { @@ -1316,6 +1376,7 @@ {"tcpa-log", 0, 0, 'L'}, {"timestamps", 0, 0, 't'}, {"parseable-timestamps", 0, 0, 'T'}, + {"add-timestamp", required_argument, 0, 'a'}, {"hexdump", 0, 0, 'x'}, {"rawdump", required_argument, 0, 'r'}, {"verbose", 0, 0, 'V'}, @@ -1323,7 +1384,7 @@ {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "c12B:CltTLxVvh?r:", + while ((opt = getopt_long(argc, argv, "c12B:CltTa:LxVvh?r:", long_options, &option_index)) != EOF) { switch (opt) { case 'c': @@ -1373,6 +1434,13 @@ machine_readable_timestamps = 1; print_defaults = 0; break; + case 'a': + print_defaults = 0; + timestamp_id = timestamp_name_to_id(optarg); + /* Parse numeric value if name is unknown */ + if (timestamp_id == 0) + timestamp_id = strtoul(optarg, NULL, 10); + break; case 'V': verbose = 1; break; @@ -1395,7 +1463,7 @@ print_usage(argv[0], 1); }
- mem_fd = open("/dev/mem", O_RDONLY, 0); + mem_fd = open("/dev/mem", O_RDWR, 0); if (mem_fd < 0) { fprintf(stderr, "Failed to gain memory access: %s\n", strerror(errno)); @@ -1482,6 +1550,9 @@ if (print_rawdump) dump_cbmem_raw(rawdump_id);
+ if (timestamp_id) + timestamp_add_now(timestamp_id); + if (print_defaults || print_timestamps) dump_timestamps(machine_readable_timestamps);