aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/coreboot/coreboot_timestamps.c
blob: ab0e5b2cd114a47d0a6e35d3459ab01d0c9eb807 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
 * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

/*
 * coreboot(4) timestamp CBMEM reader
 *
 * Maps the timestamp CBMEM region on demand and formats boot stage
 * timing as a human-readable sysctl.  The mapping is transient —
 * created when the sysctl is read and released immediately after.
 */

#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>

/*
 * Timestamp ID to name mapping.
 * IDs from coreboot's src/commonlib/include/commonlib/timestamp_serialized.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));
}

/*
 * Sysctl handler for hw.coreboot.timestamps.
 * Maps the CBMEM timestamp region, formats entries, and unmaps.
 */
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);
}