#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sbuf.h>
#include <sys/sysctl.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <dev/coreboot/coreboot.h>
static const struct cb_id_name ts_names[] = {
{ 1, "start of romstage" },
{ 2, "before RAM initialization" },
{ 3, "after RAM initialization" },
{ 4, "end of romstage" },
{ 5, "start of verified boot" },
{ 6, "end of verified boot" },
{ 8, "starting to load ramstage" },
{ 9, "finished loading ramstage" },
{ 10, "start of ramstage" },
{ 11, "start of bootblock" },
{ 12, "end of bootblock" },
{ 13, "starting to load romstage" },
{ 14, "finished loading romstage" },
{ 15, "starting LZMA decompress" },
{ 16, "finished LZMA decompress" },
{ 17, "starting LZ4 decompress" },
{ 18, "finished LZ4 decompress" },
{ 19, "starting ZSTD decompress" },
{ 20, "finished ZSTD decompress" },
{ 30, "early chipset initialization" },
{ 31, "device enumeration" },
{ 40, "device configure" },
{ 50, "device enable" },
{ 60, "device initialization" },
{ 65, "option ROM initialization" },
{ 66, "option ROM copy done" },
{ 67, "option ROM run done" },
{ 70, "device setup done" },
{ 75, "cbmem post" },
{ 80, "write tables" },
{ 85, "finalize chips" },
{ 90, "starting to load payload" },
{ 98, "acpi wake jump" },
{ 99, "selfboot jump" },
{ 100, "start of postcar" },
{ 101, "end of postcar" },
{ 110, "forced delay start" },
{ 111, "forced delay end" },
{ 112, "read microcode start" },
{ 113, "read microcode end" },
{ 114, "elog init start" },
{ 115, "elog init end" },
{ 950, "fsp memory init start" },
{ 951, "fsp memory init end" },
{ 952, "fsp temp RAM exit start" },
{ 953, "fsp temp RAM exit end" },
{ 954, "fsp silicon init start" },
{ 955, "fsp silicon init end" },
{ 956, "fsp enumerate start" },
{ 957, "fsp enumerate end" },
{ 958, "fsp finalize start" },
{ 959, "fsp finalize end" },
{ 960, "fsp end-of-firmware start" },
{ 961, "fsp end-of-firmware end" },
{ 962, "fsp multi-phase silicon init start" },
{ 963, "fsp multi-phase silicon init end" },
{ 964, "fsp multi-phase memory init start" },
{ 965, "fsp multi-phase memory init end" },
{ 970, "fsp memory init load" },
{ 971, "fsp silicon init load" },
{ 1000, "depthcharge start" },
{ 1100, "vboot done" },
{ 1101, "kernel start" },
{ 1102, "kernel decompression" },
{ 0, NULL }
};
static const char *
ts_id_to_name(uint32_t id)
{
return (cb_id_lookup(ts_names, id, NULL));
}
static int
coreboot_timestamps_sysctl(SYSCTL_HANDLER_ARGS)
{
struct coreboot_softc *sc = arg1;
struct cb_timestamp_table *tst;
struct sbuf *sb;
void *va;
vm_size_t map_size;
uint32_t i, max, num;
uint64_t base;
uint64_t total;
uint32_t freq;
int error;
if (sc->timestamps_paddr == 0)
return (ENXIO);
va = pmap_mapbios(sc->timestamps_paddr,
sizeof(struct cb_timestamp_table));
if (va == NULL)
return (ENOMEM);
tst = (struct cb_timestamp_table *)va;
max = tst->max_entries;
num = tst->num_entries;
freq = tst->tick_freq_mhz;
base = tst->base_time;
if (max > 1024)
max = 1024;
if (num > max)
num = max;
pmap_unmapbios(va, sizeof(struct cb_timestamp_table));
total = (uint64_t)sizeof(struct cb_timestamp_table) +
(uint64_t)num * sizeof(struct cb_timestamp_entry);
if (total > SIZE_MAX)
return (EINVAL);
map_size = (vm_size_t)total;
va = pmap_mapbios(sc->timestamps_paddr, map_size);
if (va == NULL)
return (ENOMEM);
tst = (struct cb_timestamp_table *)va;
sb = sbuf_new_for_sysctl(NULL, NULL, 0, req);
if (sb == NULL) {
pmap_unmapbios(va, map_size);
return (ENOMEM);
}
sbuf_printf(sb, "\n%-4s %-40s %12s %12s\n",
"ID", "Stage", "Stamp (us)", "Delta (us)");
sbuf_printf(sb, "---- ----------------------------------------"
" ------------ ------------\n");
for (i = 0; i < num; i++) {
uint32_t eid = tst->entries[i].entry_id;
int64_t stamp = tst->entries[i].entry_stamp;
int64_t us, delta_us;
const char *name;
if (freq > 0)
us = (stamp - (int64_t)base) / (int64_t)freq;
else
us = stamp;
if (i > 0 && freq > 0) {
int64_t prev = tst->entries[i - 1].entry_stamp;
delta_us = (stamp - prev) / (int64_t)freq;
} else {
delta_us = 0;
}
name = ts_id_to_name(eid);
if (name != NULL)
sbuf_printf(sb, "%4u %-40s %12jd %12jd\n",
eid, name,
(intmax_t)us, (intmax_t)delta_us);
else
sbuf_printf(sb, "%4u %-40s %12jd %12jd\n",
eid, "(unknown)",
(intmax_t)us, (intmax_t)delta_us);
}
error = sbuf_finish(sb);
sbuf_delete(sb);
pmap_unmapbios(va, map_size);
return (error);
}
int
coreboot_timestamps_register(struct coreboot_softc *sc,
struct sysctl_oid *parent)
{
SYSCTL_ADD_PROC(&sc->sysctl_ctx,
SYSCTL_CHILDREN(parent), OID_AUTO, "timestamps",
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
sc, 0, coreboot_timestamps_sysctl, "A",
"Boot stage timing from coreboot timestamps");
return (0);
}