summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/cbmem/cbmem.c103
1 files changed, 96 insertions, 7 deletions
diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c
index 3af8a25020..748bc36453 100644
--- a/util/cbmem/cbmem.c
+++ b/util/cbmem/cbmem.c
@@ -29,6 +29,10 @@
#include <sys/sysctl.h>
#endif
+#if defined(__i386__) || defined(__x86_64__)
+#include <x86intrin.h>
+#endif
+
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
typedef uint8_t u8;
@@ -57,6 +61,9 @@ 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)
@@ -80,9 +87,9 @@ static inline size_t size_to_mib(size_t sz)
}
/* 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;
@@ -91,8 +98,8 @@ static const void *mapping_virt(const struct mapping *mapping)
}
/* 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;
@@ -114,7 +121,7 @@ static const void *map_memory(struct mapping *mapping, unsigned long long phys,
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) {
@@ -132,6 +139,14 @@ static const void *map_memory(struct mapping *mapping, unsigned long long phys,
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)
{
@@ -327,6 +342,10 @@ static int parse_cbtable_entries(const struct mapping *table_mapping)
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;
/*
@@ -529,6 +548,22 @@ static void print_norm(u64 v)
}
}
+static uint64_t timestamp_get(uint64_t table_tick_freq_mhz)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ uint64_t tsc = __rdtsc();
+
+ /* No tick frequency specified means raw TSC values. */
+ if (!table_tick_freq_mhz)
+ return tsc;
+
+ if (tsc_freq_khz)
+ return tsc * table_tick_freq_mhz * 1000 / tsc_freq_khz;
+#endif
+ die("Don't know how to obtain timestamps on this platform.\n");
+ return 0;
+}
+
static const char *timestamp_name(uint32_t id)
{
for (size_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
@@ -538,6 +573,15 @@ static const char *timestamp_name(uint32_t id)
return "<unknown>";
}
+static uint32_t timestamp_enum_name_to_id(const char *name)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
+ if (!strcmp(timestamp_ids[i].enum_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)
{
@@ -765,6 +809,38 @@ static void dump_timestamps(enum timestamps_print_type output_type)
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) {
+ die("No timestamps found in coreboot table.\n");
+ }
+
+ tst_p = map_memory_with_prot(&timestamp_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) {
+ die("Not enough space to add timestamp.\n");
+ } else {
+ int64_t time =
+ timestamp_get(tst_p->tick_freq_mhz) - 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(&timestamp_mapping);
+}
+
/* dump the tcpa log table */
static void dump_tcpa_log(void)
{
@@ -1260,6 +1336,7 @@ static void print_usage(const char *name, int exit_code)
" -t | --timestamps: print timestamp information\n"
" -T | --parseable-timestamps: print parseable timestamps\n"
" -S | --stacked-timestamps: print stacked timestamps (e.g. for flame graph tools)\n"
+ " -a | --add-timestamp ID: append timestamp with ID\n"
" -L | --tcpa-log print TCPA log\n"
" -V | --verbose: verbose (debugging) output\n"
" -v | --version: print the version\n"
@@ -1397,6 +1474,7 @@ int main(int argc, char** argv)
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[] = {
@@ -1410,6 +1488,7 @@ int main(int argc, char** argv)
{"timestamps", 0, 0, 't'},
{"parseable-timestamps", 0, 0, 'T'},
{"stacked-timestamps", 0, 0, 'S'},
+ {"add-timestamp", required_argument, 0, 'a'},
{"hexdump", 0, 0, 'x'},
{"rawdump", required_argument, 0, 'r'},
{"verbose", 0, 0, 'V'},
@@ -1417,7 +1496,7 @@ int main(int argc, char** argv)
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
- while ((opt = getopt_long(argc, argv, "c12B:CltTSLxVvh?r:",
+ while ((opt = getopt_long(argc, argv, "c12B:CltTSa:LxVvh?r:",
long_options, &option_index)) != EOF) {
switch (opt) {
case 'c':
@@ -1470,6 +1549,13 @@ int main(int argc, char** argv)
timestamp_type = TIMESTAMPS_PRINT_STACKED;
print_defaults = 0;
break;
+ case 'a':
+ print_defaults = 0;
+ timestamp_id = timestamp_enum_name_to_id(optarg);
+ /* Parse numeric value if name is unknown */
+ if (timestamp_id == 0)
+ timestamp_id = strtoul(optarg, NULL, 0);
+ break;
case 'V':
verbose = 1;
break;
@@ -1492,7 +1578,7 @@ int main(int argc, char** argv)
print_usage(argv[0], 1);
}
- mem_fd = open("/dev/mem", O_RDONLY, 0);
+ mem_fd = open("/dev/mem", timestamp_id ? O_RDWR : O_RDONLY, 0);
if (mem_fd < 0) {
fprintf(stderr, "Failed to gain memory access: %s\n",
strerror(errno));
@@ -1579,6 +1665,9 @@ int main(int argc, char** argv)
if (print_rawdump)
dump_cbmem_raw(rawdump_id);
+ if (timestamp_id)
+ timestamp_add_now(timestamp_id);
+
if (print_defaults)
timestamp_type = TIMESTAMPS_PRINT_NORMAL;