blob: d33b714d224b52b05d7f919c26ceb44da35381d7 [file] [log] [blame]
Patrick Georgi7333a112020-05-08 20:48:04 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07002
Nico Huber8e4bb9282013-05-26 18:17:54 +02003#include <inttypes.h>
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01004#include <stdbool.h>
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07005#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08008#include <unistd.h>
9#include <getopt.h>
Julius Werner337de4c2014-06-16 23:02:03 -070010#include <dirent.h>
Stefan Reinauer05cbce62013-01-03 14:30:33 -080011#include <errno.h>
12#include <fcntl.h>
Stefan Reinauera9c83612013-07-16 17:47:35 -070013#include <ctype.h>
Stefan Reinauer7f681502013-06-19 15:39:09 -070014#include <arpa/inet.h>
Stefan Reinauer05cbce62013-01-03 14:30:33 -080015#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/mman.h>
Stefan Reinauerd37ab452012-12-18 16:23:28 -080018#include <libgen.h>
19#include <assert.h>
Julius Wernerb7b64a92017-04-28 16:31:46 -070020#include <regex.h>
Jakub Czapigaea619422021-11-23 08:43:25 +000021#include <commonlib/bsd/cbmem_id.h>
Sergii Dmytruk6da62682022-10-23 00:55:03 +030022#include <commonlib/bsd/tpm_log_defs.h>
Julius Werner984d03c2022-01-21 15:33:47 -080023#include <commonlib/loglevel.h>
Aaron Durbindc9f5cd2015-09-08 13:34:43 -050024#include <commonlib/timestamp_serialized.h>
Sergii Dmytruk2710df72022-11-10 00:40:51 +020025#include <commonlib/tpm_log_serialized.h>
Aaron Durbindc9f5cd2015-09-08 13:34:43 -050026#include <commonlib/coreboot_tables.h>
Vadim Bendebury6d18fd02012-09-27 19:24:07 -070027
Patrick Georgid00f1802015-07-13 16:53:50 +020028#ifdef __OpenBSD__
29#include <sys/param.h>
30#include <sys/sysctl.h>
31#endif
32
Mattias Nisslerecc165b2022-02-08 23:01:50 +000033#if defined(__i386__) || defined(__x86_64__)
34#include <x86intrin.h>
35#endif
36
Julius Werner337de4c2014-06-16 23:02:03 -070037typedef uint8_t u8;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -070038typedef uint16_t u16;
39typedef uint32_t u32;
40typedef uint64_t u64;
41
Aaron Durbin46300aa2017-09-26 16:22:38 -060042/* Return < 0 on error, 0 on success. */
43static int parse_cbtable(u64 address, size_t table_size);
44
45struct mapping {
46 void *virt;
47 size_t offset;
48 size_t virt_size;
49 unsigned long long phys;
50 size_t size;
51};
52
Stefan Reinauera9c83612013-07-16 17:47:35 -070053#define CBMEM_VERSION "1.1"
Stefan Reinauer1e0e5562013-01-02 15:43:56 -080054
Stefan Reinauer05cbce62013-01-03 14:30:33 -080055/* verbose output? */
56static int verbose = 0;
57#define debug(x...) if(verbose) printf(x)
58
59/* File handle used to access /dev/mem */
Julius Werner337de4c2014-06-16 23:02:03 -070060static int mem_fd;
Aaron Durbin46300aa2017-09-26 16:22:38 -060061static struct mapping lbtable_mapping;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -070062
Mattias Nisslerecc165b2022-02-08 23:01:50 +000063/* TSC frequency from the LB_TAG_TSC_INFO record. 0 if not present. */
64static uint32_t tsc_freq_khz = 0;
65
Aaron Durbin46300aa2017-09-26 16:22:38 -060066static void die(const char *msg)
67{
68 if (msg)
69 fputs(msg, stderr);
70 exit(1);
71}
72
73static unsigned long long system_page_size(void)
74{
75 static unsigned long long page_size;
76
77 if (!page_size)
78 page_size = getpagesize();
79
80 return page_size;
81}
82
83static inline size_t size_to_mib(size_t sz)
84{
85 return sz >> 20;
86}
87
88/* Return mapping of physical address requested. */
Mattias Nisslerecc165b2022-02-08 23:01:50 +000089static void *mapping_virt(const struct mapping *mapping)
Aaron Durbin46300aa2017-09-26 16:22:38 -060090{
Mattias Nisslerecc165b2022-02-08 23:01:50 +000091 char *v = mapping->virt;
Aaron Durbin46300aa2017-09-26 16:22:38 -060092
93 if (v == NULL)
94 return NULL;
95
96 return v + mapping->offset;
97}
98
Aaron Durbincf20c902017-09-28 17:52:59 -060099/* Returns virtual address on success, NULL on error. mapping is filled in. */
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000100static void *map_memory_with_prot(struct mapping *mapping,
101 unsigned long long phys, size_t sz, int prot)
Aaron Durbin46300aa2017-09-26 16:22:38 -0600102{
103 void *v;
104 unsigned long long page_size;
105
106 page_size = system_page_size();
107
108 mapping->virt = NULL;
109 mapping->offset = phys % page_size;
110 mapping->virt_size = sz + mapping->offset;
111 mapping->size = sz;
112 mapping->phys = phys;
113
114 if (size_to_mib(mapping->virt_size) == 0) {
115 debug("Mapping %zuB of physical memory at 0x%llx (requested 0x%llx).\n",
116 mapping->virt_size, phys - mapping->offset, phys);
117 } else {
118 debug("Mapping %zuMB of physical memory at 0x%llx (requested 0x%llx).\n",
119 size_to_mib(mapping->virt_size), phys - mapping->offset,
120 phys);
121 }
122
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000123 v = mmap(NULL, mapping->virt_size, prot, MAP_SHARED, mem_fd,
Aaron Durbin46300aa2017-09-26 16:22:38 -0600124 phys - mapping->offset);
125
126 if (v == MAP_FAILED) {
127 debug("Mapping failed %zuB of physical memory at 0x%llx.\n",
128 mapping->virt_size, phys - mapping->offset);
129 return NULL;
130 }
131
132 mapping->virt = v;
133
134 if (mapping->offset != 0)
135 debug(" ... padding virtual address with 0x%zx bytes.\n",
136 mapping->offset);
137
138 return mapping_virt(mapping);
139}
140
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000141/* Convenience helper for the common case of read-only mappings. */
142static const void *map_memory(struct mapping *mapping, unsigned long long phys,
143 size_t sz)
144{
145 return map_memory_with_prot(mapping, phys, sz, PROT_READ);
146}
147
148
Aaron Durbin46300aa2017-09-26 16:22:38 -0600149/* Returns 0 on success, < 0 on error. mapping is cleared if successful. */
150static int unmap_memory(struct mapping *mapping)
151{
152 if (mapping->virt == NULL)
153 return -1;
154
155 munmap(mapping->virt, mapping->virt_size);
156 mapping->virt = NULL;
157 mapping->offset = 0;
158 mapping->virt_size = 0;
159
160 return 0;
161}
162
163/* Return size of physical address mapping requested. */
164static size_t mapping_size(const struct mapping *mapping)
165{
166 if (mapping->virt == NULL)
167 return 0;
168
169 return mapping->size;
170}
Timothy Pearsondf699d52015-05-16 14:55:54 -0500171
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700172/*
Julius Werner127a79e2017-02-03 12:50:03 -0800173 * Some architectures map /dev/mem memory in a way that doesn't support
174 * unaligned accesses. Most normal libc memcpy()s aren't safe to use in this
175 * case, so build our own which makes sure to never do unaligned accesses on
176 * *src (*dest is fine since we never map /dev/mem for writing).
177 */
178static void *aligned_memcpy(void *dest, const void *src, size_t n)
179{
180 u8 *d = dest;
181 const volatile u8 *s = src; /* volatile to prevent optimization */
182
183 while ((uintptr_t)s & (sizeof(size_t) - 1)) {
184 if (n-- == 0)
185 return dest;
186 *d++ = *s++;
187 }
188
189 while (n >= sizeof(size_t)) {
190 *(size_t *)d = *(const volatile size_t *)s;
191 d += sizeof(size_t);
192 s += sizeof(size_t);
193 n -= sizeof(size_t);
194 }
195
196 while (n-- > 0)
197 *d++ = *s++;
198
199 return dest;
200}
201
202/*
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700203 * calculate ip checksum (16 bit quantities) on a passed in buffer. In case
204 * the buffer length is odd last byte is excluded from the calculation
205 */
206static u16 ipchcksum(const void *addr, unsigned size)
207{
208 const u16 *p = addr;
209 unsigned i, n = size / 2; /* don't expect odd sized blocks */
210 u32 sum = 0;
211
212 for (i = 0; i < n; i++)
213 sum += p[i];
214
215 sum = (sum >> 16) + (sum & 0xffff);
216 sum += (sum >> 16);
217 sum = ~sum & 0xffff;
218 return (u16) sum;
219}
220
Aaron Durbin09c0c112015-09-30 12:33:01 -0500221/* Find the first cbmem entry filling in the details. */
222static int find_cbmem_entry(uint32_t id, uint64_t *addr, size_t *size)
223{
Aaron Durbinf2a38222017-09-26 17:44:28 -0600224 const uint8_t *table;
Aaron Durbin09c0c112015-09-30 12:33:01 -0500225 size_t offset;
226 int ret = -1;
227
Aaron Durbin46300aa2017-09-26 16:22:38 -0600228 table = mapping_virt(&lbtable_mapping);
Aaron Durbin09c0c112015-09-30 12:33:01 -0500229
230 if (table == NULL)
231 return -1;
232
233 offset = 0;
234
Aaron Durbin46300aa2017-09-26 16:22:38 -0600235 while (offset < mapping_size(&lbtable_mapping)) {
Aaron Durbinf2a38222017-09-26 17:44:28 -0600236 const struct lb_record *lbr;
Yidi Lin0811a642022-09-15 15:47:59 +0800237 struct lb_cbmem_entry lbe;
Aaron Durbin09c0c112015-09-30 12:33:01 -0500238
Aaron Durbinf2a38222017-09-26 17:44:28 -0600239 lbr = (const void *)(table + offset);
Aaron Durbin09c0c112015-09-30 12:33:01 -0500240 offset += lbr->size;
241
242 if (lbr->tag != LB_TAG_CBMEM_ENTRY)
243 continue;
244
Yidi Lin0811a642022-09-15 15:47:59 +0800245 aligned_memcpy(&lbe, lbr, sizeof(lbe));
246 if (lbe.id != id)
Aaron Durbin09c0c112015-09-30 12:33:01 -0500247 continue;
248
Yidi Lin0811a642022-09-15 15:47:59 +0800249 *addr = lbe.address;
250 *size = lbe.entry_size;
Aaron Durbin09c0c112015-09-30 12:33:01 -0500251 ret = 0;
252 break;
253 }
254
Aaron Durbin09c0c112015-09-30 12:33:01 -0500255 return ret;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700256}
257
258/*
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800259 * Try finding the timestamp table and coreboot cbmem console starting from the
260 * passed in memory offset. Could be called recursively in case a forwarding
261 * entry is found.
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700262 *
Patrick Georgi220c2092020-01-30 12:58:08 +0100263 * Returns pointer to a memory buffer containing the timestamp table or zero if
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700264 * none found.
265 */
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800266
267static struct lb_cbmem_ref timestamps;
268static struct lb_cbmem_ref console;
Sergii Dmytruk2710df72022-11-10 00:40:51 +0200269static struct lb_cbmem_ref tpm_cb_log;
Stefan Reinauerc0199072013-01-07 16:26:10 -0800270static struct lb_memory_range cbmem;
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800271
Stefan Reinauer8c594772013-04-19 14:22:29 -0700272/* This is a work-around for a nasty problem introduced by initially having
273 * pointer sized entries in the lb_cbmem_ref structures. This caused problems
274 * on 64bit x86 systems because coreboot is 32bit on those systems.
275 * When the problem was found, it was corrected, but there are a lot of
276 * systems out there with a firmware that does not produce the right
277 * lb_cbmem_ref structure. Hence we try to autocorrect this issue here.
278 */
Aaron Durbinf2a38222017-09-26 17:44:28 -0600279static struct lb_cbmem_ref parse_cbmem_ref(const struct lb_cbmem_ref *cbmem_ref)
Stefan Reinauer8c594772013-04-19 14:22:29 -0700280{
281 struct lb_cbmem_ref ret;
282
Julius Wernere3c23912018-11-26 15:57:59 -0800283 aligned_memcpy(&ret, cbmem_ref, sizeof(ret));
Stefan Reinauer8c594772013-04-19 14:22:29 -0700284
285 if (cbmem_ref->size < sizeof(*cbmem_ref))
286 ret.cbmem_addr = (uint32_t)ret.cbmem_addr;
287
Stefan Reinauera9c83612013-07-16 17:47:35 -0700288 debug(" cbmem_addr = %" PRIx64 "\n", ret.cbmem_addr);
289
Stefan Reinauer8c594772013-04-19 14:22:29 -0700290 return ret;
291}
292
Aaron Durbin46300aa2017-09-26 16:22:38 -0600293static void parse_memory_tags(const struct lb_memory *mem)
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700294{
Aaron Durbin46300aa2017-09-26 16:22:38 -0600295 int num_entries;
296 int i;
297
298 /* Peel off the header size and calculate the number of entries. */
299 num_entries = (mem->size - sizeof(*mem)) / sizeof(mem->map[0]);
300
301 for (i = 0; i < num_entries; i++) {
302 if (mem->map[i].type != LB_MEM_TABLE)
303 continue;
304 debug(" LB_MEM_TABLE found.\n");
305 /* The last one found is CBMEM */
Aaron Durbineb722282019-01-31 09:40:26 -0700306 aligned_memcpy(&cbmem, &mem->map[i], sizeof(cbmem));
Aaron Durbin46300aa2017-09-26 16:22:38 -0600307 }
308}
309
310/* Return < 0 on error, 0 on success, 1 if forwarding table entry found. */
311static int parse_cbtable_entries(const struct mapping *table_mapping)
312{
313 size_t i;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200314 const struct lb_record *lbr_p;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600315 size_t table_size = mapping_size(table_mapping);
316 const void *lbtable = mapping_virt(table_mapping);
317 int forwarding_table_found = 0;
318
319 for (i = 0; i < table_size; i += lbr_p->size) {
320 lbr_p = lbtable + i;
321 debug(" coreboot table entry 0x%02x\n", lbr_p->tag);
322 switch (lbr_p->tag) {
323 case LB_TAG_MEMORY:
324 debug(" Found memory map.\n");
325 parse_memory_tags(lbtable + i);
326 continue;
327 case LB_TAG_TIMESTAMPS: {
328 debug(" Found timestamp table.\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200329 timestamps =
330 parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p);
Aaron Durbin46300aa2017-09-26 16:22:38 -0600331 continue;
332 }
333 case LB_TAG_CBMEM_CONSOLE: {
334 debug(" Found cbmem console.\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200335 console = parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p);
336 continue;
337 }
Sergii Dmytruk2710df72022-11-10 00:40:51 +0200338 case LB_TAG_TPM_CB_LOG: {
339 debug(" Found TPM CB log table.\n");
340 tpm_cb_log =
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200341 parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p);
Aaron Durbin46300aa2017-09-26 16:22:38 -0600342 continue;
343 }
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000344 case LB_TAG_TSC_INFO:
345 debug(" Found TSC info.\n");
346 tsc_freq_khz = ((struct lb_tsc_info *)lbr_p)->freq_khz;
347 continue;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600348 case LB_TAG_FORWARD: {
349 int ret;
350 /*
351 * This is a forwarding entry - repeat the
352 * search at the new address.
353 */
354 struct lb_forward lbf_p =
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200355 *(const struct lb_forward *)lbr_p;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600356 debug(" Found forwarding entry.\n");
357 ret = parse_cbtable(lbf_p.forward, 0);
358
359 /* Assume the forwarding entry is valid. If this fails
360 * then there's a total failure. */
361 if (ret < 0)
362 return -1;
363 forwarding_table_found = 1;
364 }
365 default:
366 break;
367 }
368 }
369
370 return forwarding_table_found;
371}
372
373/* Return < 0 on error, 0 on success. */
374static int parse_cbtable(u64 address, size_t table_size)
375{
Aaron Durbinf2a38222017-09-26 17:44:28 -0600376 const void *buf;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600377 struct mapping header_mapping;
378 size_t req_size;
379 size_t i;
380
381 req_size = table_size;
382 /* Default to 4 KiB search space. */
383 if (req_size == 0)
384 req_size = 4 * 1024;
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800385
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500386 debug("Looking for coreboot table at %" PRIx64 " %zd bytes.\n",
Aaron Durbin46300aa2017-09-26 16:22:38 -0600387 address, req_size);
388
389 buf = map_memory(&header_mapping, address, req_size);
390
Timothy Pearsonbea71402015-09-05 18:07:17 -0500391 if (!buf)
Aaron Durbin46300aa2017-09-26 16:22:38 -0600392 return -1;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700393
Aaron Durbin46300aa2017-09-26 16:22:38 -0600394 /* look at every 16 bytes */
Aaron Durbincf20c902017-09-28 17:52:59 -0600395 for (i = 0; i <= req_size - sizeof(struct lb_header); i += 16) {
Aaron Durbin46300aa2017-09-26 16:22:38 -0600396 int ret;
Aaron Durbinf2a38222017-09-26 17:44:28 -0600397 const struct lb_header *lbh;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600398 struct mapping table_mapping;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700399
Aaron Durbin46300aa2017-09-26 16:22:38 -0600400 lbh = buf + i;
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800401 if (memcmp(lbh->signature, "LBIO", sizeof(lbh->signature)) ||
402 !lbh->header_bytes ||
403 ipchcksum(lbh, sizeof(*lbh))) {
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700404 continue;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700405 }
406
Aaron Durbin46300aa2017-09-26 16:22:38 -0600407 /* Map in the whole table to parse. */
408 if (!map_memory(&table_mapping, address + i + lbh->header_bytes,
409 lbh->table_bytes)) {
410 debug("Couldn't map in table\n");
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700411 continue;
412 }
413
Aaron Durbin46300aa2017-09-26 16:22:38 -0600414 if (ipchcksum(mapping_virt(&table_mapping), lbh->table_bytes) !=
415 lbh->table_checksum) {
416 debug("Signature found, but wrong checksum.\n");
417 unmap_memory(&table_mapping);
418 continue;
419 }
420
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800421 debug("Found!\n");
422
Aaron Durbin46300aa2017-09-26 16:22:38 -0600423 ret = parse_cbtable_entries(&table_mapping);
Aaron Durbin09c0c112015-09-30 12:33:01 -0500424
Aaron Durbin46300aa2017-09-26 16:22:38 -0600425 /* Table parsing failed. */
426 if (ret < 0) {
427 unmap_memory(&table_mapping);
428 continue;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700429 }
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800430
Aaron Durbin46300aa2017-09-26 16:22:38 -0600431 /* Succeeded in parsing the table. Header not needed anymore. */
432 unmap_memory(&header_mapping);
433
434 /*
435 * Table parsing succeeded. If forwarding table not found update
436 * coreboot table mapping for future use.
437 */
438 if (ret == 0)
439 lbtable_mapping = table_mapping;
440 else
441 unmap_memory(&table_mapping);
442
443 return 0;
444 }
445
446 unmap_memory(&header_mapping);
447
448 return -1;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700449}
450
Patrick Georgid00f1802015-07-13 16:53:50 +0200451#if defined(linux) && (defined(__i386__) || defined(__x86_64__))
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700452/*
Aaron Durbin08e920e2016-03-12 08:41:34 +0100453 * read CPU frequency from a sysfs file, return an frequency in Megahertz as
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700454 * an int or exit on any error.
455 */
Aaron Durbinc49014e2015-08-30 21:19:55 -0500456static unsigned long arch_tick_frequency(void)
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700457{
458 FILE *cpuf;
459 char freqs[100];
460 int size;
461 char *endp;
462 u64 rv;
463
464 const char* freq_file =
465 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
466
467 cpuf = fopen(freq_file, "r");
468 if (!cpuf) {
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800469 fprintf(stderr, "Could not open %s: %s\n",
470 freq_file, strerror(errno));
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700471 exit(1);
472 }
473
474 memset(freqs, 0, sizeof(freqs));
475 size = fread(freqs, 1, sizeof(freqs), cpuf);
476 if (!size || (size == sizeof(freqs))) {
477 fprintf(stderr, "Wrong number of bytes(%d) read from %s\n",
478 size, freq_file);
479 exit(1);
480 }
481 fclose(cpuf);
482 rv = strtoull(freqs, &endp, 10);
483
484 if (*endp == '\0' || *endp == '\n')
Aaron Durbin08e920e2016-03-12 08:41:34 +0100485 /* cpuinfo_max_freq is in kHz. Convert it to MHz. */
486 return rv / 1000;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700487 fprintf(stderr, "Wrong formatted value ^%s^ read from %s\n",
488 freqs, freq_file);
489 exit(1);
490}
Patrick Georgid00f1802015-07-13 16:53:50 +0200491#elif defined(__OpenBSD__) && (defined(__i386__) || defined(__x86_64__))
Aaron Durbinc49014e2015-08-30 21:19:55 -0500492static unsigned long arch_tick_frequency(void)
Patrick Georgid00f1802015-07-13 16:53:50 +0200493{
494 int mib[2] = { CTL_HW, HW_CPUSPEED };
495 static int value = 0;
496 size_t value_len = sizeof(value);
497
Aaron Durbinc49014e2015-08-30 21:19:55 -0500498 /* Return 1 MHz when sysctl fails. */
Patrick Georgid00f1802015-07-13 16:53:50 +0200499 if ((value == 0) && (sysctl(mib, 2, &value, &value_len, NULL, 0) == -1))
Aaron Durbinc49014e2015-08-30 21:19:55 -0500500 return 1;
Patrick Georgid00f1802015-07-13 16:53:50 +0200501
Aaron Durbinc49014e2015-08-30 21:19:55 -0500502 return value;
Patrick Georgid00f1802015-07-13 16:53:50 +0200503}
Stefan Reinauerd8ef9e92013-07-31 15:44:37 -0700504#else
Aaron Durbinc49014e2015-08-30 21:19:55 -0500505static unsigned long arch_tick_frequency(void)
Stefan Reinauerd8ef9e92013-07-31 15:44:37 -0700506{
Aaron Durbinc49014e2015-08-30 21:19:55 -0500507 /* 1 MHz = 1us. */
508 return 1;
Stefan Reinauerd8ef9e92013-07-31 15:44:37 -0700509}
510#endif
511
Aaron Durbinc49014e2015-08-30 21:19:55 -0500512static unsigned long tick_freq_mhz;
513
514static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz)
515{
516 tick_freq_mhz = table_tick_freq_mhz;
517
Martin Rothac9d6b82017-12-11 13:27:56 -0700518 /* Honor table frequency if present. */
519 if (!tick_freq_mhz)
520 tick_freq_mhz = arch_tick_frequency();
Aaron Durbinc49014e2015-08-30 21:19:55 -0500521
522 if (!tick_freq_mhz) {
523 fprintf(stderr, "Cannot determine timestamp tick frequency.\n");
524 exit(1);
525 }
Martin Rothac9d6b82017-12-11 13:27:56 -0700526
527 debug("Timestamp tick frequency: %ld MHz\n", tick_freq_mhz);
Aaron Durbinc49014e2015-08-30 21:19:55 -0500528}
529
Jacob Garber79a2f472019-06-27 17:23:25 -0600530static u64 arch_convert_raw_ts_entry(u64 ts)
Aaron Durbinc49014e2015-08-30 21:19:55 -0500531{
532 return ts / tick_freq_mhz;
533}
534
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700535/*
536 * Print an integer in 'normalized' form - with commas separating every three
Julius Wernera7d92442014-12-02 20:51:19 -0800537 * decimal orders.
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700538 */
Julius Wernera7d92442014-12-02 20:51:19 -0800539static void print_norm(u64 v)
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700540{
Julius Wernera7d92442014-12-02 20:51:19 -0800541 if (v >= 1000) {
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700542 /* print the higher order sections first */
Julius Wernera7d92442014-12-02 20:51:19 -0800543 print_norm(v / 1000);
544 printf(",%3.3u", (u32)(v % 1000));
545 } else {
546 printf("%u", (u32)(v % 1000));
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700547 }
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700548}
549
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000550static uint64_t timestamp_get(uint64_t table_tick_freq_mhz)
551{
552#if defined(__i386__) || defined(__x86_64__)
553 uint64_t tsc = __rdtsc();
554
555 /* No tick frequency specified means raw TSC values. */
556 if (!table_tick_freq_mhz)
557 return tsc;
558
559 if (tsc_freq_khz)
560 return tsc * table_tick_freq_mhz * 1000 / tsc_freq_khz;
Nick Vaccaro946e2922022-04-26 17:14:03 -0700561#else
562 (void)table_tick_freq_mhz;
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000563#endif
564 die("Don't know how to obtain timestamps on this platform.\n");
565 return 0;
566}
567
Aaron Durbinfbff3012015-08-30 22:00:12 -0500568static const char *timestamp_name(uint32_t id)
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700569{
Jacob Garber414d5d82019-06-27 16:02:32 -0600570 for (size_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
Aaron Durbinfbff3012015-08-30 22:00:12 -0500571 if (timestamp_ids[i].id == id)
572 return timestamp_ids[i].name;
573 }
574 return "<unknown>";
575}
576
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000577static uint32_t timestamp_enum_name_to_id(const char *name)
578{
579 for (size_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
580 if (!strcmp(timestamp_ids[i].enum_name, name))
581 return timestamp_ids[i].id;
582 }
583 return 0;
584}
585
Aaron Durbinfbff3012015-08-30 22:00:12 -0500586static uint64_t timestamp_print_parseable_entry(uint32_t id, uint64_t stamp,
587 uint64_t prev_stamp)
588{
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700589 const char *name;
Aaron Durbin799bf782015-08-06 13:52:08 -0500590 uint64_t step_time;
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700591
Aaron Durbinfbff3012015-08-30 22:00:12 -0500592 name = timestamp_name(id);
593
594 step_time = arch_convert_raw_ts_entry(stamp - prev_stamp);
595
596 /* ID<tab>absolute time<tab>relative time<tab>description */
597 printf("%d\t", id);
598 printf("%llu\t", (long long)arch_convert_raw_ts_entry(stamp));
599 printf("%llu\t", (long long)step_time);
600 printf("%s\n", name);
601
602 return step_time;
603}
604
Jacob Garber79a2f472019-06-27 17:23:25 -0600605static uint64_t timestamp_print_entry(uint32_t id, uint64_t stamp, uint64_t prev_stamp)
Aaron Durbinfbff3012015-08-30 22:00:12 -0500606{
607 const char *name;
608 uint64_t step_time;
609
610 name = timestamp_name(id);
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700611
612 printf("%4d:", id);
Julius Wernera7d92442014-12-02 20:51:19 -0800613 printf("%-50s", name);
614 print_norm(arch_convert_raw_ts_entry(stamp));
Aaron Durbin799bf782015-08-06 13:52:08 -0500615 step_time = arch_convert_raw_ts_entry(stamp - prev_stamp);
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700616 if (prev_stamp) {
617 printf(" (");
Aaron Durbin799bf782015-08-06 13:52:08 -0500618 print_norm(step_time);
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700619 printf(")");
620 }
621 printf("\n");
Aaron Durbin799bf782015-08-06 13:52:08 -0500622
623 return step_time;
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700624}
625
Raul E Rangeld4fec682018-05-11 11:08:07 -0600626static int compare_timestamp_entries(const void *a, const void *b)
627{
628 const struct timestamp_entry *tse_a = (struct timestamp_entry *)a;
629 const struct timestamp_entry *tse_b = (struct timestamp_entry *)b;
630
Furquan Shaikh8f567322018-05-17 15:08:03 -0700631 if (tse_a->entry_stamp > tse_b->entry_stamp)
632 return 1;
633 else if (tse_a->entry_stamp < tse_b->entry_stamp)
634 return -1;
635
636 return 0;
Raul E Rangeld4fec682018-05-11 11:08:07 -0600637}
638
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100639static int find_matching_end(struct timestamp_table *sorted_tst_p, uint32_t start, uint32_t end)
640{
641 uint32_t id = sorted_tst_p->entries[start].entry_id;
642 uint32_t possible_match = 0;
643
644 for (uint32_t i = 0; i < ARRAY_SIZE(timestamp_ids); ++i) {
645 if (timestamp_ids[i].id == id) {
646 possible_match = timestamp_ids[i].id_end;
647 break;
648 }
649 }
650
651 /* No match found or timestamp not defined in IDs table */
652 if (!possible_match)
653 return -1;
654
655 for (uint32_t i = start + 1; i < end; i++)
656 if (sorted_tst_p->entries[i].entry_id == possible_match)
657 return i;
658
659 return -1;
660}
661
662static const char *get_timestamp_name(const uint32_t id)
663{
664 for (uint32_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++)
665 if (timestamp_ids[i].id == id)
666 return timestamp_ids[i].enum_name;
667
668 return "UNKNOWN";
669}
670
671struct ts_range_stack {
672 const char *name;
673 const char *end_name;
674 uint32_t end;
675};
676
677static void print_with_path(struct ts_range_stack *range_stack, const int stacklvl,
678 const uint64_t stamp, const char *last_part)
679{
680 for (int i = 1; i <= stacklvl; ++i) {
681 printf("%s -> %s", range_stack[i].name, range_stack[i].end_name);
682 if (i < stacklvl || last_part)
683 putchar(';');
684 }
685 if (last_part)
686 printf("%s", last_part);
Paul Fagerburgac683842022-04-02 08:28:40 -0600687 printf(" %llu\n", (long long)arch_convert_raw_ts_entry(stamp));
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100688}
689
690enum timestamps_print_type {
691 TIMESTAMPS_PRINT_NONE,
692 TIMESTAMPS_PRINT_NORMAL,
693 TIMESTAMPS_PRINT_MACHINE_READABLE,
694 TIMESTAMPS_PRINT_STACKED,
695};
696
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700697/* dump the timestamp table */
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100698static void dump_timestamps(enum timestamps_print_type output_type)
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700699{
Aaron Durbinf2a38222017-09-26 17:44:28 -0600700 const struct timestamp_table *tst_p;
Raul E Rangeld4fec682018-05-11 11:08:07 -0600701 struct timestamp_table *sorted_tst_p;
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500702 size_t size;
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100703 uint64_t prev_stamp = 0;
704 uint64_t total_time = 0;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600705 struct mapping timestamp_mapping;
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800706
707 if (timestamps.tag != LB_TAG_TIMESTAMPS) {
708 fprintf(stderr, "No timestamps found in coreboot table.\n");
709 return;
710 }
711
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500712 size = sizeof(*tst_p);
Aaron Durbin46300aa2017-09-26 16:22:38 -0600713 tst_p = map_memory(&timestamp_mapping, timestamps.cbmem_addr, size);
714 if (!tst_p)
715 die("Unable to map timestamp header\n");
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700716
Aaron Durbinc49014e2015-08-30 21:19:55 -0500717 timestamp_set_tick_freq(tst_p->tick_freq_mhz);
718
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100719 if (output_type == TIMESTAMPS_PRINT_NORMAL)
Aaron Durbinfbff3012015-08-30 22:00:12 -0500720 printf("%d entries total:\n\n", tst_p->num_entries);
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500721 size += tst_p->num_entries * sizeof(tst_p->entries[0]);
722
Aaron Durbin46300aa2017-09-26 16:22:38 -0600723 unmap_memory(&timestamp_mapping);
724
725 tst_p = map_memory(&timestamp_mapping, timestamps.cbmem_addr, size);
726 if (!tst_p)
727 die("Unable to map full timestamp table\n");
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500728
Bora Guvendike383b3d2021-11-22 16:12:48 -0800729 sorted_tst_p = malloc(size + sizeof(struct timestamp_entry));
Raul E Rangeld4fec682018-05-11 11:08:07 -0600730 if (!sorted_tst_p)
731 die("Failed to allocate memory");
Julius Wernere3c23912018-11-26 15:57:59 -0800732 aligned_memcpy(sorted_tst_p, tst_p, size);
Raul E Rangeld4fec682018-05-11 11:08:07 -0600733
Bora Guvendike383b3d2021-11-22 16:12:48 -0800734 /*
735 * Insert a timestamp to represent the base time (start of coreboot),
736 * in case we have to rebase for negative timestamps below.
737 */
738 sorted_tst_p->entries[tst_p->num_entries].entry_id = 0;
739 sorted_tst_p->entries[tst_p->num_entries].entry_stamp = 0;
740 sorted_tst_p->num_entries += 1;
741
Raul E Rangeld4fec682018-05-11 11:08:07 -0600742 qsort(&sorted_tst_p->entries[0], sorted_tst_p->num_entries,
743 sizeof(struct timestamp_entry), compare_timestamp_entries);
744
Bora Guvendike383b3d2021-11-22 16:12:48 -0800745 /*
746 * If there are negative timestamp entries, rebase all of the
747 * timestamps to the lowest one in the list.
748 */
Bora Guvendikc79da5f2022-02-10 20:13:50 -0800749 if (sorted_tst_p->entries[0].entry_stamp < 0) {
Bora Guvendike383b3d2021-11-22 16:12:48 -0800750 sorted_tst_p->base_time = -sorted_tst_p->entries[0].entry_stamp;
Bora Guvendikc79da5f2022-02-10 20:13:50 -0800751 prev_stamp = 0;
752 } else {
753 prev_stamp = tst_p->base_time;
754 }
Bora Guvendike383b3d2021-11-22 16:12:48 -0800755
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100756 struct ts_range_stack range_stack[20];
757 range_stack[0].end = sorted_tst_p->num_entries;
758 int stacklvl = 0;
759
Jacob Garber414d5d82019-06-27 16:02:32 -0600760 for (uint32_t i = 0; i < sorted_tst_p->num_entries; i++) {
Aaron Durbin31540fb2015-07-11 12:44:10 -0500761 uint64_t stamp;
Raul E Rangeld4fec682018-05-11 11:08:07 -0600762 const struct timestamp_entry *tse = &sorted_tst_p->entries[i];
Aaron Durbin31540fb2015-07-11 12:44:10 -0500763
764 /* Make all timestamps absolute. */
Raul E Rangeld4fec682018-05-11 11:08:07 -0600765 stamp = tse->entry_stamp + sorted_tst_p->base_time;
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100766 if (output_type == TIMESTAMPS_PRINT_MACHINE_READABLE) {
767 timestamp_print_parseable_entry(tse->entry_id, stamp, prev_stamp);
768 } else if (output_type == TIMESTAMPS_PRINT_NORMAL) {
769 total_time += timestamp_print_entry(tse->entry_id, stamp, prev_stamp);
770 } else if (output_type == TIMESTAMPS_PRINT_STACKED) {
771 bool end_of_range = false;
772 /* Iterate over stacked entries to pop all ranges, which are closed by
773 current element. For example, assuming two ranges: (TS_A, TS_C),
774 (TS_B, TS_C) it will pop all of them instead of just last one. */
775 while (stacklvl > 0 && range_stack[stacklvl].end == i) {
776 end_of_range = true;
777 stacklvl--;
778 }
779
780 int match =
781 find_matching_end(sorted_tst_p, i, range_stack[stacklvl].end);
782 if (match != -1) {
783 const uint64_t match_stamp =
784 sorted_tst_p->entries[match].entry_stamp
785 + sorted_tst_p->base_time;
786 stacklvl++;
787 assert(stacklvl < (int)ARRAY_SIZE(range_stack));
788 range_stack[stacklvl].name = get_timestamp_name(tse->entry_id);
789 range_stack[stacklvl].end_name = get_timestamp_name(
790 sorted_tst_p->entries[match].entry_id);
791 range_stack[stacklvl].end = match;
792 print_with_path(range_stack, stacklvl, match_stamp - stamp,
793 NULL);
794 } else if (!end_of_range) {
795 print_with_path(range_stack, stacklvl, stamp - prev_stamp,
796 get_timestamp_name(tse->entry_id));
797 }
798 /* else: No match && end_of_range == true */
799 }
Aaron Durbin31540fb2015-07-11 12:44:10 -0500800 prev_stamp = stamp;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700801 }
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800802
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100803 if (output_type == TIMESTAMPS_PRINT_NORMAL) {
Aaron Durbinfbff3012015-08-30 22:00:12 -0500804 printf("\nTotal Time: ");
805 print_norm(total_time);
806 printf("\n");
807 }
Aaron Durbin799bf782015-08-06 13:52:08 -0500808
Aaron Durbin46300aa2017-09-26 16:22:38 -0600809 unmap_memory(&timestamp_mapping);
Raul E Rangeld4fec682018-05-11 11:08:07 -0600810 free(sorted_tst_p);
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700811}
812
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000813/* add a timestamp entry */
814static void timestamp_add_now(uint32_t timestamp_id)
815{
816 struct timestamp_table *tst_p;
817 struct mapping timestamp_mapping;
818
819 if (timestamps.tag != LB_TAG_TIMESTAMPS) {
820 die("No timestamps found in coreboot table.\n");
821 }
822
823 tst_p = map_memory_with_prot(&timestamp_mapping, timestamps.cbmem_addr,
824 timestamps.size, PROT_READ | PROT_WRITE);
825 if (!tst_p)
826 die("Unable to map timestamp table\n");
827
828 /*
829 * Note that coreboot sizes the cbmem entry in the table according to
830 * max_entries, so it's OK to just add more entries if there's room.
831 */
832 if (tst_p->num_entries >= tst_p->max_entries) {
833 die("Not enough space to add timestamp.\n");
834 } else {
835 int64_t time =
836 timestamp_get(tst_p->tick_freq_mhz) - tst_p->base_time;
837 tst_p->entries[tst_p->num_entries].entry_id = timestamp_id;
838 tst_p->entries[tst_p->num_entries].entry_stamp = time;
839 tst_p->num_entries += 1;
840 }
841
842 unmap_memory(&timestamp_mapping);
843}
844
Sergii Dmytruk6da62682022-10-23 00:55:03 +0300845static bool can_print(const uint8_t *data, size_t len)
846{
847 unsigned int i;
848 for (i = 0; i < len; i++) {
849 if (!isprint(data[i]) && !isspace(data[i])) {
850 /* If printable prefix is followed by zeroes, this is a valid string */
851 for (; i < len; i++) {
852 if (data[i] != 0)
853 return false;
854 }
855 return true;
856 }
857 }
858 return true;
859}
860
861static void print_hex_string(const uint8_t *hex, size_t len)
862{
863 unsigned int i;
864 for (i = 0; i < len; i++)
865 printf("%02x", hex[i]);
866}
867
868static void print_hex_line(const uint8_t *hex, size_t len)
869{
870 print_hex_string(hex, len);
871 printf("\n");
872}
873
874static void print_event_type(uint32_t event_type)
875{
876 unsigned int known_event_count = ARRAY_SIZE(tpm_event_types);
877 if (event_type >= known_event_count)
878 printf("Unknown (0x%x >= %u)", event_type, known_event_count);
879 else
880 printf("%s", tpm_event_types[event_type]);
881}
882
883static void parse_tpm12_log(const struct tcpa_spec_entry *spec_log)
884{
885 const uint8_t zero_block[sizeof(struct tcpa_spec_entry)] = {0};
886
887 uintptr_t current;
888 uint32_t counter = 0;
889
890 printf("TCPA log:\n");
891 printf("\tSpecification: %d.%d%d\n",
892 spec_log->spec_version_major,
893 spec_log->spec_version_minor,
894 spec_log->spec_errata);
895 printf("\tPlatform class: %s\n",
896 le32toh(spec_log->platform_class) == 0 ? "PC Client" :
897 le32toh(spec_log->platform_class) == 1 ? "Server" : "Unknown");
898
899 current = (uintptr_t)&spec_log->vendor_info[spec_log->vendor_info_size];
900 while (memcmp((const void *)current, (const void *)zero_block, sizeof(zero_block))) {
901 uint32_t len;
902 struct tcpa_log_entry *log_entry = (void *)current;
903 uint32_t event_type = le32toh(log_entry->event_type);
904
905 printf("TCPA log entry %u:\n", ++counter);
906 printf("\tPCR: %d\n", le32toh(log_entry->pcr));
907 printf("\tEvent type: ");
908 print_event_type(event_type);
909 printf("\n");
910 printf("\tDigest: ");
911 print_hex_line(log_entry->digest, SHA1_DIGEST_SIZE);
912 current += sizeof(struct tcpa_log_entry);
913 len = le32toh(log_entry->event_data_size);
914 if (len != 0) {
915 current += len;
916 printf("\tEvent data: ");
917 if (can_print(log_entry->event, len))
918 printf("%.*s\n", len, log_entry->event);
919 else
920 print_hex_line(log_entry->event, len);
921 } else {
922 printf("\tEvent data not provided\n");
923 }
924 }
925}
926
927static uint32_t print_tpm2_digests(struct tcg_pcr_event2_header *log_entry)
928{
929 unsigned int i;
930 uintptr_t current = (uintptr_t)log_entry->digests;
931
932 for (i = 0; i < le32toh(log_entry->digest_count); i++) {
933 struct tpm_hash_algorithm *hash = (struct tpm_hash_algorithm *)current;
934 switch (le16toh(hash->hashAlg)) {
935 case TPM2_ALG_SHA1:
936 printf("\t\t SHA1: ");
937 print_hex_line(hash->digest.sha1, SHA1_DIGEST_SIZE);
938 current += sizeof(hash->hashAlg) + SHA1_DIGEST_SIZE;
939 break;
940 case TPM2_ALG_SHA256:
941 printf("\t\t SHA256: ");
942 print_hex_line(hash->digest.sha256, SHA256_DIGEST_SIZE);
943 current += sizeof(hash->hashAlg) + SHA256_DIGEST_SIZE;
944 break;
945 case TPM2_ALG_SHA384:
946 printf("\t\t SHA384: ");
947 print_hex_line(hash->digest.sha384, SHA384_DIGEST_SIZE);
948 current += sizeof(hash->hashAlg) + SHA384_DIGEST_SIZE;
949 break;
950 case TPM2_ALG_SHA512:
951 printf("\t\t SHA512: ");
952 print_hex_line(hash->digest.sha512, SHA512_DIGEST_SIZE);
953 current += sizeof(hash->hashAlg) + SHA512_DIGEST_SIZE;
954 break;
955 case TPM2_ALG_SM3_256:
956 printf("\t\t SM3: ");
957 print_hex_line(hash->digest.sm3_256, SM3_256_DIGEST_SIZE);
958 current += sizeof(hash->hashAlg) + SM3_256_DIGEST_SIZE;
959 break;
960 default:
961 die("Unknown hash algorithm\n");
962 }
963 }
964
965 return current - (uintptr_t)&log_entry->digest_count;
966}
967
968static void parse_tpm2_log(const struct tcg_efi_spec_id_event *tpm2_log)
969{
970 const uint8_t zero_block[12] = {0}; /* Only PCR index, event type and digest count */
971
972 uintptr_t current;
973 uint32_t counter = 0;
974
975 printf("TPM2 log:\n");
976 printf("\tSpecification: %d.%d%d\n",
977 tpm2_log->spec_version_major,
978 tpm2_log->spec_version_minor,
979 tpm2_log->spec_errata);
980 printf("\tPlatform class: %s\n",
981 le32toh(tpm2_log->platform_class) == 0 ? "PC Client" :
982 le32toh(tpm2_log->platform_class) == 1 ? "Server" : "Unknown");
983
984 /* Start after the first variable-sized part of the header */
985 current = (uintptr_t)&tpm2_log->digest_sizes[le32toh(tpm2_log->num_of_algorithms)];
986 /* current is at `uint8_t vendor_info_size` here */
987 current += 1 + *(uint8_t *)current;
988
989 while (memcmp((const void *)current, (const void *)zero_block, sizeof(zero_block))) {
990 uint32_t len;
991 struct tcg_pcr_event2_header *log_entry = (void *)current;
992 uint32_t event_type = le32toh(log_entry->event_type);
993
994 printf("TPM2 log entry %u:\n", ++counter);
995 printf("\tPCR: %d\n", le32toh(log_entry->pcr_index));
996 printf("\tEvent type: ");
997 print_event_type(event_type);
998 printf("\n");
999
1000 current = (uintptr_t)&log_entry->digest_count;
1001 if (le32toh(log_entry->digest_count) > 0) {
1002 printf("\tDigests:\n");
1003 current += print_tpm2_digests(log_entry);
1004 } else {
1005 printf("\tNo digests in this log entry\n");
1006 current += sizeof(log_entry->digest_count);
1007 }
1008 /* Now event size and event are left to be parsed */
1009 len = le32toh(*(uint32_t *)current);
1010 current += sizeof(uint32_t);
1011 if (len != 0) {
1012 printf("\tEvent data: %.*s\n", len, (const char *)current);
1013 current += len;
1014 } else {
1015 printf("\tEvent data not provided\n");
1016 }
1017 }
1018}
1019
1020/* Dump the TPM log table in format defined by specifications */
1021static void dump_tpm_std_log(uint64_t addr, size_t size)
1022{
1023 const void *event_log;
1024 const struct tcpa_spec_entry *tspec_entry;
1025 const struct tcg_efi_spec_id_event *tcg_spec_entry;
1026 struct mapping log_mapping;
1027
1028 event_log = map_memory(&log_mapping, addr, size);
1029 if (!event_log)
1030 die("Unable to map TPM eventlog\n");
1031
1032 tspec_entry = event_log;
1033 if (!strcmp((const char *)tspec_entry->signature, TCPA_SPEC_ID_EVENT_SIGNATURE)) {
1034 if (tspec_entry->spec_version_major == 1 &&
1035 tspec_entry->spec_version_minor == 2 &&
1036 tspec_entry->spec_errata >= 1 &&
1037 le32toh(tspec_entry->entry.event_type) == EV_NO_ACTION) {
1038 parse_tpm12_log(tspec_entry);
1039 } else {
1040 fprintf(stderr, "Unknown TPM1.2 log specification\n");
1041 }
1042 unmap_memory(&log_mapping);
1043 return;
1044 }
1045
1046 tcg_spec_entry = event_log;
1047 if (!strcmp((const char *)tcg_spec_entry->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE)) {
1048 if (tcg_spec_entry->spec_version_major == 2 &&
1049 tcg_spec_entry->spec_version_minor == 0 &&
1050 le32toh(tcg_spec_entry->event_type) == EV_NO_ACTION) {
1051 parse_tpm2_log(tcg_spec_entry);
1052 } else {
1053 fprintf(stderr, "Unknown TPM2 log specification.\n");
1054 }
1055 unmap_memory(&log_mapping);
1056 return;
1057 }
1058
1059 fprintf(stderr, "Unknown TPM log specification: %.*s\n",
1060 (int)sizeof(tcg_spec_entry->signature),
1061 (const char *)tcg_spec_entry->signature);
1062
1063 unmap_memory(&log_mapping);
1064}
1065
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001066/* dump the TPM CB log table */
1067static void dump_tpm_cb_log(void)
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001068{
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001069 const struct tpm_cb_log_table *tclt_p;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001070 size_t size;
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001071 struct mapping log_mapping;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001072
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001073 if (tpm_cb_log.tag != LB_TAG_TPM_CB_LOG) {
1074 fprintf(stderr, "No TPM log found in coreboot table.\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001075 return;
1076 }
1077
1078 size = sizeof(*tclt_p);
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001079 tclt_p = map_memory(&log_mapping, tpm_cb_log.cbmem_addr, size);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001080 if (!tclt_p)
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001081 die("Unable to map TPM log header\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001082
1083 size += tclt_p->num_entries * sizeof(tclt_p->entries[0]);
1084
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001085 unmap_memory(&log_mapping);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001086
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001087 tclt_p = map_memory(&log_mapping, tpm_cb_log.cbmem_addr, size);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001088 if (!tclt_p)
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001089 die("Unable to map full TPM log table\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001090
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001091 printf("coreboot TPM log:\n\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001092
Jacob Garber414d5d82019-06-27 16:02:32 -06001093 for (uint16_t i = 0; i < tclt_p->num_entries; i++) {
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001094 const struct tpm_cb_log_entry *tce = &tclt_p->entries[i];
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001095
Philipp Deppenwiesec9b7d1f2018-11-10 00:35:02 +01001096 printf(" PCR-%u ", tce->pcr);
Sergii Dmytruk6da62682022-10-23 00:55:03 +03001097 print_hex_string(tce->digest, tce->digest_length);
Philipp Deppenwiesec9b7d1f2018-11-10 00:35:02 +01001098 printf(" %s [%s]\n", tce->digest_type, tce->name);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001099 }
1100
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001101 unmap_memory(&log_mapping);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001102}
1103
Sergii Dmytruk6da62682022-10-23 00:55:03 +03001104static void dump_tpm_log(void)
1105{
1106 uint64_t start;
1107 size_t size;
1108
1109 if (!find_cbmem_entry(CBMEM_ID_TCPA_TCG_LOG, &start, &size) ||
1110 !find_cbmem_entry(CBMEM_ID_TPM2_TCG_LOG, &start, &size))
1111 dump_tpm_std_log(start, size);
1112 else
1113 dump_tpm_cb_log();
1114}
1115
Julius Wernerd67c6872017-02-02 17:32:00 -08001116struct cbmem_console {
1117 u32 size;
1118 u32 cursor;
Elyes Haouasfc2f3042023-07-30 13:06:10 +02001119 u8 body[];
Julius Wernerd67c6872017-02-02 17:32:00 -08001120} __attribute__ ((__packed__));
1121
1122#define CBMC_CURSOR_MASK ((1 << 28) - 1)
1123#define CBMC_OVERFLOW (1 << 31)
1124
Julius Werner8202fc42021-09-08 16:10:15 -07001125enum console_print_type {
1126 CONSOLE_PRINT_FULL = 0,
1127 CONSOLE_PRINT_LAST,
1128 CONSOLE_PRINT_PREVIOUS,
1129};
1130
Julius Wernerb8258bd2022-02-09 17:26:39 -08001131static int parse_loglevel(char *arg, int *print_unknown_logs)
1132{
1133 if (arg[0] == '+') {
1134 *print_unknown_logs = 1;
1135 arg++;
1136 } else {
1137 *print_unknown_logs = 0;
1138 }
1139
1140 char *endptr;
1141 int loglevel = strtol(arg, &endptr, 0);
1142 if (*endptr == '\0' && loglevel >= BIOS_EMERG && loglevel <= BIOS_LOG_PREFIX_MAX_LEVEL)
1143 return loglevel;
1144
1145 /* Only match first 3 characters so `NOTE` and `NOTICE` both match. */
1146 for (int i = BIOS_EMERG; i <= BIOS_LOG_PREFIX_MAX_LEVEL; i++)
1147 if (!strncasecmp(arg, bios_log_prefix[i], 3))
1148 return i;
1149
1150 *print_unknown_logs = 1;
1151 return BIOS_NEVER;
1152}
1153
Stefan Reinauer19f87562013-01-07 13:37:12 -08001154/* dump the cbmem console */
Julius Wernerb8258bd2022-02-09 17:26:39 -08001155static void dump_console(enum console_print_type type, int max_loglevel, int print_unknown_logs)
Stefan Reinauer19f87562013-01-07 13:37:12 -08001156{
Aaron Durbinf2a38222017-09-26 17:44:28 -06001157 const struct cbmem_console *console_p;
Stefan Reinauer19f87562013-01-07 13:37:12 -08001158 char *console_c;
Julius Werner8202fc42021-09-08 16:10:15 -07001159 size_t size, cursor, previous;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001160 struct mapping console_mapping;
Stefan Reinauer19f87562013-01-07 13:37:12 -08001161
1162 if (console.tag != LB_TAG_CBMEM_CONSOLE) {
1163 fprintf(stderr, "No console found in coreboot table.\n");
1164 return;
1165 }
1166
Julius Wernerd67c6872017-02-02 17:32:00 -08001167 size = sizeof(*console_p);
Aaron Durbin46300aa2017-09-26 16:22:38 -06001168 console_p = map_memory(&console_mapping, console.cbmem_addr, size);
1169 if (!console_p)
1170 die("Unable to map console object.\n");
1171
Julius Wernerd67c6872017-02-02 17:32:00 -08001172 cursor = console_p->cursor & CBMC_CURSOR_MASK;
1173 if (!(console_p->cursor & CBMC_OVERFLOW) && cursor < console_p->size)
Vladimir Serbinenkof4a0d012013-03-30 12:15:12 +01001174 size = cursor;
Julius Wernerd67c6872017-02-02 17:32:00 -08001175 else
1176 size = console_p->size;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001177 unmap_memory(&console_mapping);
Julius Wernerd67c6872017-02-02 17:32:00 -08001178
1179 console_c = malloc(size + 1);
Stefan Reinauer19f87562013-01-07 13:37:12 -08001180 if (!console_c) {
1181 fprintf(stderr, "Not enough memory for console.\n");
1182 exit(1);
1183 }
Julius Wernerd67c6872017-02-02 17:32:00 -08001184 console_c[size] = '\0';
Stefan Reinauer19f87562013-01-07 13:37:12 -08001185
Aaron Durbin46300aa2017-09-26 16:22:38 -06001186 console_p = map_memory(&console_mapping, console.cbmem_addr,
1187 size + sizeof(*console_p));
1188
1189 if (!console_p)
1190 die("Unable to map full console object.\n");
1191
Julius Wernerd67c6872017-02-02 17:32:00 -08001192 if (console_p->cursor & CBMC_OVERFLOW) {
1193 if (cursor >= size) {
1194 printf("cbmem: ERROR: CBMEM console struct is illegal, "
1195 "output may be corrupt or out of order!\n\n");
1196 cursor = 0;
1197 }
1198 aligned_memcpy(console_c, console_p->body + cursor,
1199 size - cursor);
1200 aligned_memcpy(console_c + size - cursor,
1201 console_p->body, cursor);
1202 } else {
1203 aligned_memcpy(console_c, console_p->body, size);
1204 }
Stefan Reinauer19f87562013-01-07 13:37:12 -08001205
Julius Wernerd67c6872017-02-02 17:32:00 -08001206 /* Slight memory corruption may occur between reboots and give us a few
1207 unprintable characters like '\0'. Replace them with '?' on output. */
1208 for (cursor = 0; cursor < size; cursor++)
Julius Werner984d03c2022-01-21 15:33:47 -08001209 if (!isprint(console_c[cursor]) && !isspace(console_c[cursor])
1210 && !BIOS_LOG_IS_MARKER(console_c[cursor]))
Julius Wernerd67c6872017-02-02 17:32:00 -08001211 console_c[cursor] = '?';
Stefan Reinauer19f87562013-01-07 13:37:12 -08001212
Julius Werner8202fc42021-09-08 16:10:15 -07001213 /* We detect the reboot cutoff by looking for a bootblock, romstage or
Julius Wernerb7b64a92017-04-28 16:31:46 -07001214 ramstage banner, in that order (to account for platforms without
1215 CONFIG_BOOTBLOCK_CONSOLE and/or CONFIG_EARLY_CONSOLE). Once we find
Julius Werner8202fc42021-09-08 16:10:15 -07001216 a banner, store the last two matches for that stage and stop. */
1217 cursor = previous = 0;
1218 if (type != CONSOLE_PRINT_FULL) {
You-Cheng Syu1430b392019-07-01 16:40:25 +08001219#define BANNER_REGEX(stage) \
Julius Wernerce878322022-03-09 16:51:43 -08001220 "\n\n.?coreboot-[^\n]* " stage " starting.*\\.\\.\\.\n"
1221#define OVERFLOW_REGEX(stage) "\n.?\\*\\*\\* Pre-CBMEM " stage " console overflow"
Kangheui Won4b5c8b52020-10-07 14:29:38 +11001222 const char *regex[] = { BANNER_REGEX("verstage-before-bootblock"),
1223 BANNER_REGEX("bootblock"),
You-Cheng Syu1430b392019-07-01 16:40:25 +08001224 BANNER_REGEX("verstage"),
Julius Wernerd906bb62017-05-16 13:54:18 -07001225 OVERFLOW_REGEX("romstage"),
Furquan Shaikh35972de2018-02-16 16:12:02 -08001226 BANNER_REGEX("romstage"),
1227 OVERFLOW_REGEX("ramstage"),
1228 BANNER_REGEX("ramstage") };
Julius Wernerb7b64a92017-04-28 16:31:46 -07001229
Jacob Garber414d5d82019-06-27 16:02:32 -06001230 for (size_t i = 0; !cursor && i < ARRAY_SIZE(regex); i++) {
Julius Wernerb7b64a92017-04-28 16:31:46 -07001231 regex_t re;
1232 regmatch_t match;
Konrad Adamczyk8120cb42023-04-24 10:06:30 +00001233 int res = regcomp(&re, regex[i], REG_EXTENDED | REG_NEWLINE);
Julius Wernerce878322022-03-09 16:51:43 -08001234 assert(res == 0);
Julius Wernerb7b64a92017-04-28 16:31:46 -07001235
1236 /* Keep looking for matches so we find the last one. */
Julius Werner8202fc42021-09-08 16:10:15 -07001237 while (!regexec(&re, console_c + cursor, 1, &match, 0)) {
1238 previous = cursor;
Julius Wernerb7b64a92017-04-28 16:31:46 -07001239 cursor += match.rm_so + 1;
Julius Werner8202fc42021-09-08 16:10:15 -07001240 }
Julius Wernerb7b64a92017-04-28 16:31:46 -07001241 regfree(&re);
1242 }
1243 }
1244
Julius Werner8202fc42021-09-08 16:10:15 -07001245 if (type == CONSOLE_PRINT_PREVIOUS) {
1246 console_c[cursor] = '\0';
1247 cursor = previous;
1248 }
1249
Julius Werner984d03c2022-01-21 15:33:47 -08001250 char c;
Julius Wernerb8258bd2022-02-09 17:26:39 -08001251 int suppressed = 0;
Julius Werner984d03c2022-01-21 15:33:47 -08001252 int tty = isatty(fileno(stdout));
1253 while ((c = console_c[cursor++])) {
1254 if (BIOS_LOG_IS_MARKER(c)) {
1255 int lvl = BIOS_LOG_MARKER_TO_LEVEL(c);
Julius Wernerb8258bd2022-02-09 17:26:39 -08001256 if (lvl > max_loglevel) {
1257 suppressed = 1;
1258 continue;
1259 }
1260 suppressed = 0;
Julius Werner984d03c2022-01-21 15:33:47 -08001261 if (tty)
1262 printf(BIOS_LOG_ESCAPE_PATTERN, bios_log_escape[lvl]);
1263 printf(BIOS_LOG_PREFIX_PATTERN, bios_log_prefix[lvl]);
1264 } else {
Julius Wernerb8258bd2022-02-09 17:26:39 -08001265 if (!suppressed)
1266 putchar(c);
1267 if (c == '\n') {
1268 if (tty && !suppressed)
1269 printf(BIOS_LOG_ESCAPE_RESET);
1270 suppressed = !print_unknown_logs;
1271 }
Julius Werner984d03c2022-01-21 15:33:47 -08001272 }
1273 }
1274 if (tty)
1275 printf(BIOS_LOG_ESCAPE_RESET);
1276
Stefan Reinauer19f87562013-01-07 13:37:12 -08001277 free(console_c);
Aaron Durbin46300aa2017-09-26 16:22:38 -06001278 unmap_memory(&console_mapping);
Stefan Reinauer19f87562013-01-07 13:37:12 -08001279}
1280
Stefan Reinauera9c83612013-07-16 17:47:35 -07001281static void hexdump(unsigned long memory, int length)
1282{
1283 int i;
Aaron Durbinf2a38222017-09-26 17:44:28 -06001284 const uint8_t *m;
Stefan Reinauera9c83612013-07-16 17:47:35 -07001285 int all_zero = 0;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001286 struct mapping hexdump_mapping;
Stefan Reinauera9c83612013-07-16 17:47:35 -07001287
Aaron Durbin46300aa2017-09-26 16:22:38 -06001288 m = map_memory(&hexdump_mapping, memory, length);
1289 if (!m)
1290 die("Unable to map hexdump memory.\n");
Stefan Reinauera9c83612013-07-16 17:47:35 -07001291
1292 for (i = 0; i < length; i += 16) {
1293 int j;
1294
1295 all_zero++;
1296 for (j = 0; j < 16; j++) {
1297 if(m[i+j] != 0) {
1298 all_zero = 0;
1299 break;
1300 }
1301 }
1302
1303 if (all_zero < 2) {
1304 printf("%08lx:", memory + i);
1305 for (j = 0; j < 16; j++)
1306 printf(" %02x", m[i+j]);
1307 printf(" ");
1308 for (j = 0; j < 16; j++)
1309 printf("%c", isprint(m[i+j]) ? m[i+j] : '.');
1310 printf("\n");
1311 } else if (all_zero == 2) {
1312 printf("...\n");
1313 }
1314 }
1315
Aaron Durbin46300aa2017-09-26 16:22:38 -06001316 unmap_memory(&hexdump_mapping);
Stefan Reinauera9c83612013-07-16 17:47:35 -07001317}
1318
1319static void dump_cbmem_hex(void)
1320{
1321 if (cbmem.type != LB_MEM_TABLE) {
1322 fprintf(stderr, "No coreboot CBMEM area found!\n");
1323 return;
1324 }
1325
Jianjun Wangb2537bd2022-04-08 16:57:28 +08001326 hexdump(cbmem.start, cbmem.size);
Stefan Reinauera9c83612013-07-16 17:47:35 -07001327}
1328
Jacob Garber79a2f472019-06-27 17:23:25 -06001329static void rawdump(uint64_t base, uint64_t size)
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001330{
Aaron Durbinf2a38222017-09-26 17:44:28 -06001331 const uint8_t *m;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001332 struct mapping dump_mapping;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001333
Aaron Durbin46300aa2017-09-26 16:22:38 -06001334 m = map_memory(&dump_mapping, base, size);
1335 if (!m)
1336 die("Unable to map rawdump memory\n");
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001337
Jacob Garber414d5d82019-06-27 16:02:32 -06001338 for (uint64_t i = 0 ; i < size; i++)
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001339 printf("%c", m[i]);
Aaron Durbin46300aa2017-09-26 16:22:38 -06001340
1341 unmap_memory(&dump_mapping);
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001342}
1343
1344static void dump_cbmem_raw(unsigned int id)
1345{
Aaron Durbinf2a38222017-09-26 17:44:28 -06001346 const uint8_t *table;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001347 size_t offset;
1348 uint64_t base = 0;
1349 uint64_t size = 0;
1350
Aaron Durbin46300aa2017-09-26 16:22:38 -06001351 table = mapping_virt(&lbtable_mapping);
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001352
1353 if (table == NULL)
1354 return;
1355
1356 offset = 0;
1357
Aaron Durbin46300aa2017-09-26 16:22:38 -06001358 while (offset < mapping_size(&lbtable_mapping)) {
Aaron Durbinf2a38222017-09-26 17:44:28 -06001359 const struct lb_record *lbr;
Yidi Lin0811a642022-09-15 15:47:59 +08001360 struct lb_cbmem_entry lbe;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001361
Aaron Durbinf2a38222017-09-26 17:44:28 -06001362 lbr = (const void *)(table + offset);
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001363 offset += lbr->size;
1364
1365 if (lbr->tag != LB_TAG_CBMEM_ENTRY)
1366 continue;
1367
Yidi Lin0811a642022-09-15 15:47:59 +08001368 aligned_memcpy(&lbe, lbr, sizeof(lbe));
1369 if (lbe.id == id) {
1370 debug("found id for raw dump %0x", lbe.id);
1371 base = lbe.address;
1372 size = lbe.entry_size;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001373 break;
1374 }
1375 }
1376
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001377 if (!base)
1378 fprintf(stderr, "id %0x not found in cbtable\n", id);
1379 else
1380 rawdump(base, size);
1381}
1382
Aaron Durbin0dff57d2015-03-05 21:18:33 -06001383struct cbmem_id_to_name {
1384 uint32_t id;
1385 const char *name;
1386};
Vadim Bendebury8b143c52014-05-14 10:12:55 -07001387static const struct cbmem_id_to_name cbmem_ids[] = { CBMEM_ID_TO_NAME_TABLE };
Stefan Reinauerc0199072013-01-07 16:26:10 -08001388
Kyösti Mälkkieab5c122017-09-04 11:10:17 +03001389#define MAX_STAGEx 10
Jacob Garber79a2f472019-06-27 17:23:25 -06001390static void cbmem_print_entry(int n, uint32_t id, uint64_t base, uint64_t size)
Stefan Reinauera9c83612013-07-16 17:47:35 -07001391{
Stefan Reinauera9c83612013-07-16 17:47:35 -07001392 const char *name;
Kyösti Mälkkieab5c122017-09-04 11:10:17 +03001393 char stage_x[20];
Stefan Reinauera9c83612013-07-16 17:47:35 -07001394
1395 name = NULL;
Jacob Garber414d5d82019-06-27 16:02:32 -06001396 for (size_t i = 0; i < ARRAY_SIZE(cbmem_ids); i++) {
Stefan Reinauera9c83612013-07-16 17:47:35 -07001397 if (cbmem_ids[i].id == id) {
1398 name = cbmem_ids[i].name;
1399 break;
1400 }
Kyösti Mälkkieab5c122017-09-04 11:10:17 +03001401 if (id >= CBMEM_ID_STAGEx_META &&
1402 id < CBMEM_ID_STAGEx_META + MAX_STAGEx) {
1403 snprintf(stage_x, sizeof(stage_x), "STAGE%d META",
1404 (id - CBMEM_ID_STAGEx_META));
1405 name = stage_x;
1406 }
1407 if (id >= CBMEM_ID_STAGEx_CACHE &&
1408 id < CBMEM_ID_STAGEx_CACHE + MAX_STAGEx) {
1409 snprintf(stage_x, sizeof(stage_x), "STAGE%d $ ",
1410 (id - CBMEM_ID_STAGEx_CACHE));
1411 name = stage_x;
1412 }
Stefan Reinauera9c83612013-07-16 17:47:35 -07001413 }
1414
1415 printf("%2d. ", n);
1416 if (name == NULL)
Martin Roth90e4f3d2022-10-20 21:11:30 -06001417 name = "(unknown)";
1418 printf("%-20s %08x", name, id);
Stefan Reinauera9c83612013-07-16 17:47:35 -07001419 printf(" %08" PRIx64 " ", base);
Martin Roth90e4f3d2022-10-20 21:11:30 -06001420 printf(" %08" PRIx64 "\n", size);
Stefan Reinauera9c83612013-07-16 17:47:35 -07001421}
1422
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001423static void dump_cbmem_toc(void)
Stefan Reinauerc0199072013-01-07 16:26:10 -08001424{
Aaron Durbin09c0c112015-09-30 12:33:01 -05001425 int i;
Aaron Durbinf2a38222017-09-26 17:44:28 -06001426 const uint8_t *table;
Aaron Durbin09c0c112015-09-30 12:33:01 -05001427 size_t offset;
Stefan Reinauerc0199072013-01-07 16:26:10 -08001428
Aaron Durbin46300aa2017-09-26 16:22:38 -06001429 table = mapping_virt(&lbtable_mapping);
Aaron Durbin09c0c112015-09-30 12:33:01 -05001430
1431 if (table == NULL)
Stefan Reinauerc0199072013-01-07 16:26:10 -08001432 return;
Aaron Durbin09c0c112015-09-30 12:33:01 -05001433
1434 printf("CBMEM table of contents:\n");
Martin Roth90e4f3d2022-10-20 21:11:30 -06001435 printf(" %-20s %-8s %-8s %-8s\n", "NAME", "ID", "START",
1436 "LENGTH");
Aaron Durbin09c0c112015-09-30 12:33:01 -05001437
1438 i = 0;
1439 offset = 0;
1440
Aaron Durbin46300aa2017-09-26 16:22:38 -06001441 while (offset < mapping_size(&lbtable_mapping)) {
Aaron Durbinf2a38222017-09-26 17:44:28 -06001442 const struct lb_record *lbr;
Yidi Lin0811a642022-09-15 15:47:59 +08001443 struct lb_cbmem_entry lbe;
Aaron Durbin09c0c112015-09-30 12:33:01 -05001444
Aaron Durbinf2a38222017-09-26 17:44:28 -06001445 lbr = (const void *)(table + offset);
Aaron Durbin09c0c112015-09-30 12:33:01 -05001446 offset += lbr->size;
1447
1448 if (lbr->tag != LB_TAG_CBMEM_ENTRY)
1449 continue;
1450
Yidi Lin0811a642022-09-15 15:47:59 +08001451 aligned_memcpy(&lbe, lbr, sizeof(lbe));
1452 cbmem_print_entry(i, lbe.id, lbe.address, lbe.entry_size);
Aaron Durbin09c0c112015-09-30 12:33:01 -05001453 i++;
Stefan Reinauerc0199072013-01-07 16:26:10 -08001454 }
Stefan Reinauerc0199072013-01-07 16:26:10 -08001455}
Stefan Reinauer19f87562013-01-07 13:37:12 -08001456
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001457#define COVERAGE_MAGIC 0x584d4153
1458struct file {
1459 uint32_t magic;
1460 uint32_t next;
1461 uint32_t filename;
1462 uint32_t data;
1463 int offset;
1464 int len;
1465};
1466
1467static int mkpath(char *path, mode_t mode)
1468{
1469 assert (path && *path);
1470 char *p;
1471 for (p = strchr(path+1, '/'); p; p = strchr(p + 1, '/')) {
1472 *p = '\0';
1473 if (mkdir(path, mode) == -1) {
1474 if (errno != EEXIST) {
1475 *p = '/';
1476 return -1;
1477 }
1478 }
1479 *p = '/';
1480 }
1481 return 0;
1482}
1483
1484static void dump_coverage(void)
1485{
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001486 uint64_t start;
Aaron Durbin09c0c112015-09-30 12:33:01 -05001487 size_t size;
Aaron Durbinf2a38222017-09-26 17:44:28 -06001488 const void *coverage;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001489 struct mapping coverage_mapping;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001490 unsigned long phys_offset;
1491#define phys_to_virt(x) ((void *)(unsigned long)(x) + phys_offset)
1492
Aaron Durbin09c0c112015-09-30 12:33:01 -05001493 if (find_cbmem_entry(CBMEM_ID_COVERAGE, &start, &size)) {
1494 fprintf(stderr, "No coverage information found\n");
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001495 return;
1496 }
1497
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001498 /* Map coverage area */
Aaron Durbin46300aa2017-09-26 16:22:38 -06001499 coverage = map_memory(&coverage_mapping, start, size);
1500 if (!coverage)
1501 die("Unable to map coverage area.\n");
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001502 phys_offset = (unsigned long)coverage - (unsigned long)start;
1503
1504 printf("Dumping coverage data...\n");
1505
1506 struct file *file = (struct file *)coverage;
1507 while (file && file->magic == COVERAGE_MAGIC) {
1508 FILE *f;
1509 char *filename;
1510
1511 debug(" -> %s\n", (char *)phys_to_virt(file->filename));
1512 filename = strdup((char *)phys_to_virt(file->filename));
1513 if (mkpath(filename, 0755) == -1) {
1514 perror("Directory for coverage data could "
1515 "not be created");
1516 exit(1);
1517 }
1518 f = fopen(filename, "wb");
1519 if (!f) {
1520 printf("Could not open %s: %s\n",
1521 filename, strerror(errno));
1522 exit(1);
1523 }
1524 if (fwrite((void *)phys_to_virt(file->data),
1525 file->len, 1, f) != 1) {
1526 printf("Could not write to %s: %s\n",
1527 filename, strerror(errno));
1528 exit(1);
1529 }
1530 fclose(f);
1531 free(filename);
1532
1533 if (file->next)
1534 file = (struct file *)phys_to_virt(file->next);
1535 else
1536 file = NULL;
1537 }
Aaron Durbin46300aa2017-09-26 16:22:38 -06001538 unmap_memory(&coverage_mapping);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001539}
1540
1541static void print_version(void)
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001542{
1543 printf("cbmem v%s -- ", CBMEM_VERSION);
1544 printf("Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.\n\n");
1545 printf(
1546 "This program is free software: you can redistribute it and/or modify\n"
1547 "it under the terms of the GNU General Public License as published by\n"
1548 "the Free Software Foundation, version 2 of the License.\n\n"
1549 "This program is distributed in the hope that it will be useful,\n"
1550 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1551 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001552 "GNU General Public License for more details.\n\n");
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001553}
1554
Martin Roth8448ac42016-09-11 15:43:22 -06001555static void print_usage(const char *name, int exit_code)
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001556{
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001557 printf("usage: %s [-cCltTLxVvh?]\n", name);
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001558 printf("\n"
Stefan Reinauer19f87562013-01-07 13:37:12 -08001559 " -c | --console: print cbmem console\n"
Julius Wernerb7b64a92017-04-28 16:31:46 -07001560 " -1 | --oneboot: print cbmem console for last boot only\n"
Julius Werner8202fc42021-09-08 16:10:15 -07001561 " -2 | --2ndtolast: print cbmem console for the boot that came before the last one only\n"
Julius Wernerb8258bd2022-02-09 17:26:39 -08001562 " -B | --loglevel: maximum loglevel to print; prefix `+` (e.g. -B +INFO) to also print lines that have no level\n"
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001563 " -C | --coverage: dump coverage information\n"
Stefan Reinauerc0199072013-01-07 16:26:10 -08001564 " -l | --list: print cbmem table of contents\n"
Stefan Reinauera9c83612013-07-16 17:47:35 -07001565 " -x | --hexdump: print hexdump of cbmem area\n"
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001566 " -r | --rawdump ID: print rawdump of specific ID (in hex) of cbtable\n"
Stefan Reinauer19f87562013-01-07 13:37:12 -08001567 " -t | --timestamps: print timestamp information\n"
Aaron Durbinfbff3012015-08-30 22:00:12 -05001568 " -T | --parseable-timestamps: print parseable timestamps\n"
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001569 " -S | --stacked-timestamps: print stacked timestamps (e.g. for flame graph tools)\n"
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001570 " -a | --add-timestamp ID: append timestamp with ID\n"
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001571 " -L | --tcpa-log print TPM log\n"
Stefan Reinauer19f87562013-01-07 13:37:12 -08001572 " -V | --verbose: verbose (debugging) output\n"
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001573 " -v | --version: print the version\n"
1574 " -h | --help: print this help\n"
1575 "\n");
Martin Roth8448ac42016-09-11 15:43:22 -06001576 exit(exit_code);
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001577}
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001578
Adam Kallai66c22502018-11-30 11:31:50 +01001579#if defined(__arm__) || defined(__aarch64__)
Julius Werner337de4c2014-06-16 23:02:03 -07001580static void dt_update_cells(const char *name, int *addr_cells_ptr,
1581 int *size_cells_ptr)
1582{
1583 if (*addr_cells_ptr >= 0 && *size_cells_ptr >= 0)
1584 return;
1585
1586 int buffer;
1587 size_t nlen = strlen(name);
1588 char *prop = alloca(nlen + sizeof("/#address-cells"));
1589 strcpy(prop, name);
1590
1591 if (*addr_cells_ptr < 0) {
1592 strcpy(prop + nlen, "/#address-cells");
1593 int fd = open(prop, O_RDONLY);
1594 if (fd < 0 && errno != ENOENT) {
1595 perror(prop);
1596 } else if (fd >= 0) {
1597 if (read(fd, &buffer, sizeof(int)) < 0)
1598 perror(prop);
1599 else
1600 *addr_cells_ptr = ntohl(buffer);
1601 close(fd);
1602 }
1603 }
1604
1605 if (*size_cells_ptr < 0) {
1606 strcpy(prop + nlen, "/#size-cells");
1607 int fd = open(prop, O_RDONLY);
1608 if (fd < 0 && errno != ENOENT) {
1609 perror(prop);
1610 } else if (fd >= 0) {
1611 if (read(fd, &buffer, sizeof(int)) < 0)
1612 perror(prop);
1613 else
1614 *size_cells_ptr = ntohl(buffer);
1615 close(fd);
1616 }
1617 }
1618}
1619
1620static char *dt_find_compat(const char *parent, const char *compat,
1621 int *addr_cells_ptr, int *size_cells_ptr)
1622{
1623 char *ret = NULL;
1624 struct dirent *entry;
1625 DIR *dir;
1626
1627 if (!(dir = opendir(parent))) {
1628 perror(parent);
1629 return NULL;
1630 }
1631
1632 /* Loop through all files in the directory (DT node). */
1633 while ((entry = readdir(dir))) {
1634 /* We only care about compatible props or subnodes. */
1635 if (entry->d_name[0] == '.' || !((entry->d_type & DT_DIR) ||
1636 !strcmp(entry->d_name, "compatible")))
1637 continue;
1638
1639 /* Assemble the file name (on the stack, for speed). */
1640 size_t plen = strlen(parent);
1641 char *name = alloca(plen + strlen(entry->d_name) + 2);
1642
1643 strcpy(name, parent);
1644 name[plen] = '/';
1645 strcpy(name + plen + 1, entry->d_name);
1646
1647 /* If it's a subnode, recurse. */
1648 if (entry->d_type & DT_DIR) {
1649 ret = dt_find_compat(name, compat, addr_cells_ptr,
1650 size_cells_ptr);
1651
1652 /* There is only one matching node to find, abort. */
1653 if (ret) {
1654 /* Gather cells values on the way up. */
1655 dt_update_cells(parent, addr_cells_ptr,
1656 size_cells_ptr);
1657 break;
1658 }
1659 continue;
1660 }
1661
1662 /* If it's a compatible string, see if it's the right one. */
1663 int fd = open(name, O_RDONLY);
1664 int clen = strlen(compat);
1665 char *buffer = alloca(clen + 1);
1666
1667 if (fd < 0) {
1668 perror(name);
1669 continue;
1670 }
1671
1672 if (read(fd, buffer, clen + 1) < 0) {
1673 perror(name);
1674 close(fd);
1675 continue;
1676 }
1677 close(fd);
1678
1679 if (!strcmp(compat, buffer)) {
1680 /* Initialize these to "unset" for the way up. */
1681 *addr_cells_ptr = *size_cells_ptr = -1;
1682
1683 /* Can't leave string on the stack or we'll lose it! */
1684 ret = strdup(parent);
1685 break;
1686 }
1687 }
1688
1689 closedir(dir);
1690 return ret;
1691}
Adam Kallai66c22502018-11-30 11:31:50 +01001692#endif /* defined(__arm__) || defined(__aarch64__) */
Julius Werner337de4c2014-06-16 23:02:03 -07001693
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001694int main(int argc, char** argv)
1695{
Stefan Reinauer19f87562013-01-07 13:37:12 -08001696 int print_defaults = 1;
1697 int print_console = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001698 int print_coverage = 0;
Stefan Reinauerc0199072013-01-07 16:26:10 -08001699 int print_list = 0;
Stefan Reinauera9c83612013-07-16 17:47:35 -07001700 int print_hexdump = 0;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001701 int print_rawdump = 0;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001702 int print_tcpa_log = 0;
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001703 enum timestamps_print_type timestamp_type = TIMESTAMPS_PRINT_NONE;
Julius Werner8202fc42021-09-08 16:10:15 -07001704 enum console_print_type console_type = CONSOLE_PRINT_FULL;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001705 unsigned int rawdump_id = 0;
Julius Wernerb8258bd2022-02-09 17:26:39 -08001706 int max_loglevel = BIOS_NEVER;
1707 int print_unknown_logs = 1;
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001708 uint32_t timestamp_id = 0;
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001709
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001710 int opt, option_index = 0;
1711 static struct option long_options[] = {
Stefan Reinauer19f87562013-01-07 13:37:12 -08001712 {"console", 0, 0, 'c'},
Julius Wernerb7b64a92017-04-28 16:31:46 -07001713 {"oneboot", 0, 0, '1'},
Julius Werner8202fc42021-09-08 16:10:15 -07001714 {"2ndtolast", 0, 0, '2'},
Julius Wernerb8258bd2022-02-09 17:26:39 -08001715 {"loglevel", required_argument, 0, 'B'},
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001716 {"coverage", 0, 0, 'C'},
Stefan Reinauerc0199072013-01-07 16:26:10 -08001717 {"list", 0, 0, 'l'},
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001718 {"tcpa-log", 0, 0, 'L'},
Stefan Reinauer19f87562013-01-07 13:37:12 -08001719 {"timestamps", 0, 0, 't'},
Aaron Durbinfbff3012015-08-30 22:00:12 -05001720 {"parseable-timestamps", 0, 0, 'T'},
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001721 {"stacked-timestamps", 0, 0, 'S'},
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001722 {"add-timestamp", required_argument, 0, 'a'},
Stefan Reinauera9c83612013-07-16 17:47:35 -07001723 {"hexdump", 0, 0, 'x'},
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001724 {"rawdump", required_argument, 0, 'r'},
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001725 {"verbose", 0, 0, 'V'},
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001726 {"version", 0, 0, 'v'},
1727 {"help", 0, 0, 'h'},
1728 {0, 0, 0, 0}
1729 };
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001730 while ((opt = getopt_long(argc, argv, "c12B:CltTSa:LxVvh?r:",
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001731 long_options, &option_index)) != EOF) {
1732 switch (opt) {
Stefan Reinauer19f87562013-01-07 13:37:12 -08001733 case 'c':
1734 print_console = 1;
1735 print_defaults = 0;
1736 break;
Julius Wernerb7b64a92017-04-28 16:31:46 -07001737 case '1':
1738 print_console = 1;
Julius Werner8202fc42021-09-08 16:10:15 -07001739 console_type = CONSOLE_PRINT_LAST;
1740 print_defaults = 0;
1741 break;
1742 case '2':
1743 print_console = 1;
1744 console_type = CONSOLE_PRINT_PREVIOUS;
Julius Wernerb7b64a92017-04-28 16:31:46 -07001745 print_defaults = 0;
1746 break;
Julius Wernerb8258bd2022-02-09 17:26:39 -08001747 case 'B':
1748 max_loglevel = parse_loglevel(optarg, &print_unknown_logs);
1749 break;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001750 case 'C':
1751 print_coverage = 1;
1752 print_defaults = 0;
1753 break;
Stefan Reinauerc0199072013-01-07 16:26:10 -08001754 case 'l':
1755 print_list = 1;
1756 print_defaults = 0;
1757 break;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001758 case 'L':
1759 print_tcpa_log = 1;
1760 print_defaults = 0;
1761 break;
Stefan Reinauera9c83612013-07-16 17:47:35 -07001762 case 'x':
1763 print_hexdump = 1;
1764 print_defaults = 0;
1765 break;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001766 case 'r':
1767 print_rawdump = 1;
1768 print_defaults = 0;
1769 rawdump_id = strtoul(optarg, NULL, 16);
1770 break;
Stefan Reinauer19f87562013-01-07 13:37:12 -08001771 case 't':
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001772 timestamp_type = TIMESTAMPS_PRINT_NORMAL;
Stefan Reinauer19f87562013-01-07 13:37:12 -08001773 print_defaults = 0;
1774 break;
Aaron Durbinfbff3012015-08-30 22:00:12 -05001775 case 'T':
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001776 timestamp_type = TIMESTAMPS_PRINT_MACHINE_READABLE;
1777 print_defaults = 0;
1778 break;
1779 case 'S':
1780 timestamp_type = TIMESTAMPS_PRINT_STACKED;
Aaron Durbinfbff3012015-08-30 22:00:12 -05001781 print_defaults = 0;
1782 break;
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001783 case 'a':
1784 print_defaults = 0;
1785 timestamp_id = timestamp_enum_name_to_id(optarg);
1786 /* Parse numeric value if name is unknown */
1787 if (timestamp_id == 0)
1788 timestamp_id = strtoul(optarg, NULL, 0);
1789 break;
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001790 case 'V':
1791 verbose = 1;
1792 break;
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001793 case 'v':
1794 print_version();
1795 exit(0);
1796 break;
1797 case 'h':
Martin Roth8448ac42016-09-11 15:43:22 -06001798 print_usage(argv[0], 0);
1799 break;
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001800 case '?':
1801 default:
Martin Roth8448ac42016-09-11 15:43:22 -06001802 print_usage(argv[0], 1);
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001803 break;
1804 }
1805 }
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001806
Arthur Heymans8cd17ea2018-08-01 17:21:32 +02001807 if (optind < argc) {
1808 fprintf(stderr, "Error: Extra parameter found.\n");
1809 print_usage(argv[0], 1);
1810 }
1811
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001812 mem_fd = open("/dev/mem", timestamp_id ? O_RDWR : O_RDONLY, 0);
Julius Werner337de4c2014-06-16 23:02:03 -07001813 if (mem_fd < 0) {
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001814 fprintf(stderr, "Failed to gain memory access: %s\n",
1815 strerror(errno));
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001816 return 1;
1817 }
1818
Adam Kallai66c22502018-11-30 11:31:50 +01001819#if defined(__arm__) || defined(__aarch64__)
Julius Werner337de4c2014-06-16 23:02:03 -07001820 int addr_cells, size_cells;
1821 char *coreboot_node = dt_find_compat("/proc/device-tree", "coreboot",
1822 &addr_cells, &size_cells);
Stefan Reinauer7f681502013-06-19 15:39:09 -07001823
Julius Werner337de4c2014-06-16 23:02:03 -07001824 if (!coreboot_node) {
1825 fprintf(stderr, "Could not find 'coreboot' compatible node!\n");
Stefan Reinauer7f681502013-06-19 15:39:09 -07001826 return 1;
1827 }
1828
Julius Werner337de4c2014-06-16 23:02:03 -07001829 if (addr_cells < 0) {
1830 fprintf(stderr, "Warning: no #address-cells node in tree!\n");
1831 addr_cells = 1;
1832 }
1833
1834 int nlen = strlen(coreboot_node);
1835 char *reg = alloca(nlen + sizeof("/reg"));
1836
1837 strcpy(reg, coreboot_node);
1838 strcpy(reg + nlen, "/reg");
1839 free(coreboot_node);
1840
1841 int fd = open(reg, O_RDONLY);
1842 if (fd < 0) {
1843 perror(reg);
Stefan Reinauer7f681502013-06-19 15:39:09 -07001844 return 1;
1845 }
Stefan Reinauer7f681502013-06-19 15:39:09 -07001846
Julius Werner337de4c2014-06-16 23:02:03 -07001847 int i;
Aaron Durbinb58f9e32014-10-07 14:56:35 -05001848 size_t size_to_read = addr_cells * 4 + size_cells * 4;
1849 u8 *dtbuffer = alloca(size_to_read);
1850 if (read(fd, dtbuffer, size_to_read) < 0) {
Julius Werner337de4c2014-06-16 23:02:03 -07001851 perror(reg);
1852 return 1;
1853 }
1854 close(fd);
1855
1856 /* No variable-length byte swap function anywhere in C... how sad. */
1857 u64 baseaddr = 0;
1858 for (i = 0; i < addr_cells * 4; i++) {
1859 baseaddr <<= 8;
Aaron Durbinb58f9e32014-10-07 14:56:35 -05001860 baseaddr |= *dtbuffer;
1861 dtbuffer++;
1862 }
1863 u64 cb_table_size = 0;
1864 for (i = 0; i < size_cells * 4; i++) {
1865 cb_table_size <<= 8;
1866 cb_table_size |= *dtbuffer;
1867 dtbuffer++;
Julius Werner337de4c2014-06-16 23:02:03 -07001868 }
1869
Aaron Durbin46300aa2017-09-26 16:22:38 -06001870 parse_cbtable(baseaddr, cb_table_size);
Stefan Reinauer7f681502013-06-19 15:39:09 -07001871#else
Aaron Durbin46300aa2017-09-26 16:22:38 -06001872 unsigned long long possible_base_addresses[] = { 0, 0xf0000 };
Stefan Reinauer7f681502013-06-19 15:39:09 -07001873
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001874 /* Find and parse coreboot table */
Jacob Garber414d5d82019-06-27 16:02:32 -06001875 for (size_t j = 0; j < ARRAY_SIZE(possible_base_addresses); j++) {
Aaron Durbin46300aa2017-09-26 16:22:38 -06001876 if (!parse_cbtable(possible_base_addresses[j], 0))
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001877 break;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001878 }
Stefan Reinauer7f681502013-06-19 15:39:09 -07001879#endif
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001880
Aaron Durbin46300aa2017-09-26 16:22:38 -06001881 if (mapping_virt(&lbtable_mapping) == NULL)
1882 die("Table not found.\n");
1883
Stefan Reinauer19f87562013-01-07 13:37:12 -08001884 if (print_console)
Julius Wernerb8258bd2022-02-09 17:26:39 -08001885 dump_console(console_type, max_loglevel, print_unknown_logs);
Stefan Reinauer19f87562013-01-07 13:37:12 -08001886
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001887 if (print_coverage)
1888 dump_coverage();
1889
Stefan Reinauerc0199072013-01-07 16:26:10 -08001890 if (print_list)
1891 dump_cbmem_toc();
1892
Stefan Reinauera9c83612013-07-16 17:47:35 -07001893 if (print_hexdump)
1894 dump_cbmem_hex();
1895
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001896 if (print_rawdump)
1897 dump_cbmem_raw(rawdump_id);
1898
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001899 if (timestamp_id)
1900 timestamp_add_now(timestamp_id);
1901
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001902 if (print_defaults)
1903 timestamp_type = TIMESTAMPS_PRINT_NORMAL;
1904
1905 if (timestamp_type != TIMESTAMPS_PRINT_NONE)
1906 dump_timestamps(timestamp_type);
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001907
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001908 if (print_tcpa_log)
Sergii Dmytruk6da62682022-10-23 00:55:03 +03001909 dump_tpm_log();
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001910
Aaron Durbin46300aa2017-09-26 16:22:38 -06001911 unmap_memory(&lbtable_mapping);
1912
Julius Werner337de4c2014-06-16 23:02:03 -07001913 close(mem_fd);
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001914 return 0;
1915}