blob: 15b677031526f8e2b451e80099485eacd7769062 [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>
Julius Wernerc228bef2024-01-30 19:33:40 -080022#include <commonlib/bsd/ipchksum.h>
Sergii Dmytruk6da62682022-10-23 00:55:03 +030023#include <commonlib/bsd/tpm_log_defs.h>
Julius Werner984d03c2022-01-21 15:33:47 -080024#include <commonlib/loglevel.h>
Aaron Durbindc9f5cd2015-09-08 13:34:43 -050025#include <commonlib/timestamp_serialized.h>
Sergii Dmytruk2710df72022-11-10 00:40:51 +020026#include <commonlib/tpm_log_serialized.h>
Aaron Durbindc9f5cd2015-09-08 13:34:43 -050027#include <commonlib/coreboot_tables.h>
Vadim Bendebury6d18fd02012-09-27 19:24:07 -070028
Patrick Georgid00f1802015-07-13 16:53:50 +020029#ifdef __OpenBSD__
30#include <sys/param.h>
31#include <sys/sysctl.h>
32#endif
33
Mattias Nisslerecc165b2022-02-08 23:01:50 +000034#if defined(__i386__) || defined(__x86_64__)
35#include <x86intrin.h>
36#endif
37
Julius Werner337de4c2014-06-16 23:02:03 -070038typedef uint8_t u8;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -070039typedef uint16_t u16;
40typedef uint32_t u32;
41typedef uint64_t u64;
42
Aaron Durbin46300aa2017-09-26 16:22:38 -060043/* Return < 0 on error, 0 on success. */
44static int parse_cbtable(u64 address, size_t table_size);
45
46struct mapping {
47 void *virt;
48 size_t offset;
49 size_t virt_size;
50 unsigned long long phys;
51 size_t size;
52};
53
Stefan Reinauera9c83612013-07-16 17:47:35 -070054#define CBMEM_VERSION "1.1"
Stefan Reinauer1e0e5562013-01-02 15:43:56 -080055
Stefan Reinauer05cbce62013-01-03 14:30:33 -080056/* verbose output? */
57static int verbose = 0;
58#define debug(x...) if(verbose) printf(x)
59
60/* File handle used to access /dev/mem */
Julius Werner337de4c2014-06-16 23:02:03 -070061static int mem_fd;
Aaron Durbin46300aa2017-09-26 16:22:38 -060062static struct mapping lbtable_mapping;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -070063
Mattias Nisslerecc165b2022-02-08 23:01:50 +000064/* TSC frequency from the LB_TAG_TSC_INFO record. 0 if not present. */
65static uint32_t tsc_freq_khz = 0;
66
Aaron Durbin46300aa2017-09-26 16:22:38 -060067static void die(const char *msg)
68{
69 if (msg)
70 fputs(msg, stderr);
71 exit(1);
72}
73
74static unsigned long long system_page_size(void)
75{
76 static unsigned long long page_size;
77
78 if (!page_size)
79 page_size = getpagesize();
80
81 return page_size;
82}
83
84static inline size_t size_to_mib(size_t sz)
85{
86 return sz >> 20;
87}
88
89/* Return mapping of physical address requested. */
Mattias Nisslerecc165b2022-02-08 23:01:50 +000090static void *mapping_virt(const struct mapping *mapping)
Aaron Durbin46300aa2017-09-26 16:22:38 -060091{
Mattias Nisslerecc165b2022-02-08 23:01:50 +000092 char *v = mapping->virt;
Aaron Durbin46300aa2017-09-26 16:22:38 -060093
94 if (v == NULL)
95 return NULL;
96
97 return v + mapping->offset;
98}
99
Aaron Durbincf20c902017-09-28 17:52:59 -0600100/* Returns virtual address on success, NULL on error. mapping is filled in. */
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000101static void *map_memory_with_prot(struct mapping *mapping,
102 unsigned long long phys, size_t sz, int prot)
Aaron Durbin46300aa2017-09-26 16:22:38 -0600103{
104 void *v;
105 unsigned long long page_size;
106
107 page_size = system_page_size();
108
109 mapping->virt = NULL;
110 mapping->offset = phys % page_size;
111 mapping->virt_size = sz + mapping->offset;
112 mapping->size = sz;
113 mapping->phys = phys;
114
115 if (size_to_mib(mapping->virt_size) == 0) {
116 debug("Mapping %zuB of physical memory at 0x%llx (requested 0x%llx).\n",
117 mapping->virt_size, phys - mapping->offset, phys);
118 } else {
119 debug("Mapping %zuMB of physical memory at 0x%llx (requested 0x%llx).\n",
120 size_to_mib(mapping->virt_size), phys - mapping->offset,
121 phys);
122 }
123
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000124 v = mmap(NULL, mapping->virt_size, prot, MAP_SHARED, mem_fd,
Aaron Durbin46300aa2017-09-26 16:22:38 -0600125 phys - mapping->offset);
126
127 if (v == MAP_FAILED) {
128 debug("Mapping failed %zuB of physical memory at 0x%llx.\n",
129 mapping->virt_size, phys - mapping->offset);
130 return NULL;
131 }
132
133 mapping->virt = v;
134
135 if (mapping->offset != 0)
136 debug(" ... padding virtual address with 0x%zx bytes.\n",
137 mapping->offset);
138
139 return mapping_virt(mapping);
140}
141
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000142/* Convenience helper for the common case of read-only mappings. */
143static const void *map_memory(struct mapping *mapping, unsigned long long phys,
144 size_t sz)
145{
146 return map_memory_with_prot(mapping, phys, sz, PROT_READ);
147}
148
149
Aaron Durbin46300aa2017-09-26 16:22:38 -0600150/* Returns 0 on success, < 0 on error. mapping is cleared if successful. */
151static int unmap_memory(struct mapping *mapping)
152{
153 if (mapping->virt == NULL)
154 return -1;
155
156 munmap(mapping->virt, mapping->virt_size);
157 mapping->virt = NULL;
158 mapping->offset = 0;
159 mapping->virt_size = 0;
160
161 return 0;
162}
163
164/* Return size of physical address mapping requested. */
165static size_t mapping_size(const struct mapping *mapping)
166{
167 if (mapping->virt == NULL)
168 return 0;
169
170 return mapping->size;
171}
Timothy Pearsondf699d52015-05-16 14:55:54 -0500172
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700173/*
Julius Werner127a79e2017-02-03 12:50:03 -0800174 * Some architectures map /dev/mem memory in a way that doesn't support
175 * unaligned accesses. Most normal libc memcpy()s aren't safe to use in this
176 * case, so build our own which makes sure to never do unaligned accesses on
177 * *src (*dest is fine since we never map /dev/mem for writing).
178 */
179static void *aligned_memcpy(void *dest, const void *src, size_t n)
180{
181 u8 *d = dest;
182 const volatile u8 *s = src; /* volatile to prevent optimization */
183
184 while ((uintptr_t)s & (sizeof(size_t) - 1)) {
185 if (n-- == 0)
186 return dest;
187 *d++ = *s++;
188 }
189
190 while (n >= sizeof(size_t)) {
191 *(size_t *)d = *(const volatile size_t *)s;
192 d += sizeof(size_t);
193 s += sizeof(size_t);
194 n -= sizeof(size_t);
195 }
196
197 while (n-- > 0)
198 *d++ = *s++;
199
200 return dest;
201}
202
Aaron Durbin09c0c112015-09-30 12:33:01 -0500203/* Find the first cbmem entry filling in the details. */
204static int find_cbmem_entry(uint32_t id, uint64_t *addr, size_t *size)
205{
Aaron Durbinf2a38222017-09-26 17:44:28 -0600206 const uint8_t *table;
Aaron Durbin09c0c112015-09-30 12:33:01 -0500207 size_t offset;
208 int ret = -1;
209
Aaron Durbin46300aa2017-09-26 16:22:38 -0600210 table = mapping_virt(&lbtable_mapping);
Aaron Durbin09c0c112015-09-30 12:33:01 -0500211
212 if (table == NULL)
213 return -1;
214
215 offset = 0;
216
Aaron Durbin46300aa2017-09-26 16:22:38 -0600217 while (offset < mapping_size(&lbtable_mapping)) {
Aaron Durbinf2a38222017-09-26 17:44:28 -0600218 const struct lb_record *lbr;
Yidi Lin0811a642022-09-15 15:47:59 +0800219 struct lb_cbmem_entry lbe;
Aaron Durbin09c0c112015-09-30 12:33:01 -0500220
Aaron Durbinf2a38222017-09-26 17:44:28 -0600221 lbr = (const void *)(table + offset);
Aaron Durbin09c0c112015-09-30 12:33:01 -0500222 offset += lbr->size;
223
224 if (lbr->tag != LB_TAG_CBMEM_ENTRY)
225 continue;
226
Yidi Lin0811a642022-09-15 15:47:59 +0800227 aligned_memcpy(&lbe, lbr, sizeof(lbe));
228 if (lbe.id != id)
Aaron Durbin09c0c112015-09-30 12:33:01 -0500229 continue;
230
Yidi Lin0811a642022-09-15 15:47:59 +0800231 *addr = lbe.address;
232 *size = lbe.entry_size;
Aaron Durbin09c0c112015-09-30 12:33:01 -0500233 ret = 0;
234 break;
235 }
236
Aaron Durbin09c0c112015-09-30 12:33:01 -0500237 return ret;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700238}
239
240/*
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800241 * Try finding the timestamp table and coreboot cbmem console starting from the
242 * passed in memory offset. Could be called recursively in case a forwarding
243 * entry is found.
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700244 *
Patrick Georgi220c2092020-01-30 12:58:08 +0100245 * Returns pointer to a memory buffer containing the timestamp table or zero if
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700246 * none found.
247 */
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800248
249static struct lb_cbmem_ref timestamps;
250static struct lb_cbmem_ref console;
Sergii Dmytruk2710df72022-11-10 00:40:51 +0200251static struct lb_cbmem_ref tpm_cb_log;
Stefan Reinauerc0199072013-01-07 16:26:10 -0800252static struct lb_memory_range cbmem;
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800253
Stefan Reinauer8c594772013-04-19 14:22:29 -0700254/* This is a work-around for a nasty problem introduced by initially having
255 * pointer sized entries in the lb_cbmem_ref structures. This caused problems
256 * on 64bit x86 systems because coreboot is 32bit on those systems.
257 * When the problem was found, it was corrected, but there are a lot of
258 * systems out there with a firmware that does not produce the right
259 * lb_cbmem_ref structure. Hence we try to autocorrect this issue here.
260 */
Aaron Durbinf2a38222017-09-26 17:44:28 -0600261static struct lb_cbmem_ref parse_cbmem_ref(const struct lb_cbmem_ref *cbmem_ref)
Stefan Reinauer8c594772013-04-19 14:22:29 -0700262{
263 struct lb_cbmem_ref ret;
264
Julius Wernere3c23912018-11-26 15:57:59 -0800265 aligned_memcpy(&ret, cbmem_ref, sizeof(ret));
Stefan Reinauer8c594772013-04-19 14:22:29 -0700266
267 if (cbmem_ref->size < sizeof(*cbmem_ref))
268 ret.cbmem_addr = (uint32_t)ret.cbmem_addr;
269
Stefan Reinauera9c83612013-07-16 17:47:35 -0700270 debug(" cbmem_addr = %" PRIx64 "\n", ret.cbmem_addr);
271
Stefan Reinauer8c594772013-04-19 14:22:29 -0700272 return ret;
273}
274
Aaron Durbin46300aa2017-09-26 16:22:38 -0600275static void parse_memory_tags(const struct lb_memory *mem)
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700276{
Aaron Durbin46300aa2017-09-26 16:22:38 -0600277 int num_entries;
278 int i;
279
280 /* Peel off the header size and calculate the number of entries. */
281 num_entries = (mem->size - sizeof(*mem)) / sizeof(mem->map[0]);
282
283 for (i = 0; i < num_entries; i++) {
284 if (mem->map[i].type != LB_MEM_TABLE)
285 continue;
286 debug(" LB_MEM_TABLE found.\n");
287 /* The last one found is CBMEM */
Aaron Durbineb722282019-01-31 09:40:26 -0700288 aligned_memcpy(&cbmem, &mem->map[i], sizeof(cbmem));
Aaron Durbin46300aa2017-09-26 16:22:38 -0600289 }
290}
291
292/* Return < 0 on error, 0 on success, 1 if forwarding table entry found. */
293static int parse_cbtable_entries(const struct mapping *table_mapping)
294{
295 size_t i;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200296 const struct lb_record *lbr_p;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600297 size_t table_size = mapping_size(table_mapping);
298 const void *lbtable = mapping_virt(table_mapping);
299 int forwarding_table_found = 0;
300
301 for (i = 0; i < table_size; i += lbr_p->size) {
302 lbr_p = lbtable + i;
303 debug(" coreboot table entry 0x%02x\n", lbr_p->tag);
304 switch (lbr_p->tag) {
305 case LB_TAG_MEMORY:
306 debug(" Found memory map.\n");
307 parse_memory_tags(lbtable + i);
308 continue;
309 case LB_TAG_TIMESTAMPS: {
310 debug(" Found timestamp table.\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200311 timestamps =
312 parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p);
Aaron Durbin46300aa2017-09-26 16:22:38 -0600313 continue;
314 }
315 case LB_TAG_CBMEM_CONSOLE: {
316 debug(" Found cbmem console.\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200317 console = parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p);
318 continue;
319 }
Sergii Dmytruk2710df72022-11-10 00:40:51 +0200320 case LB_TAG_TPM_CB_LOG: {
321 debug(" Found TPM CB log table.\n");
322 tpm_cb_log =
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200323 parse_cbmem_ref((struct lb_cbmem_ref *)lbr_p);
Aaron Durbin46300aa2017-09-26 16:22:38 -0600324 continue;
325 }
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000326 case LB_TAG_TSC_INFO:
327 debug(" Found TSC info.\n");
328 tsc_freq_khz = ((struct lb_tsc_info *)lbr_p)->freq_khz;
329 continue;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600330 case LB_TAG_FORWARD: {
331 int ret;
332 /*
333 * This is a forwarding entry - repeat the
334 * search at the new address.
335 */
336 struct lb_forward lbf_p =
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +0200337 *(const struct lb_forward *)lbr_p;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600338 debug(" Found forwarding entry.\n");
339 ret = parse_cbtable(lbf_p.forward, 0);
340
341 /* Assume the forwarding entry is valid. If this fails
342 * then there's a total failure. */
343 if (ret < 0)
344 return -1;
345 forwarding_table_found = 1;
346 }
347 default:
348 break;
349 }
350 }
351
352 return forwarding_table_found;
353}
354
355/* Return < 0 on error, 0 on success. */
356static int parse_cbtable(u64 address, size_t table_size)
357{
Aaron Durbinf2a38222017-09-26 17:44:28 -0600358 const void *buf;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600359 struct mapping header_mapping;
360 size_t req_size;
361 size_t i;
362
363 req_size = table_size;
364 /* Default to 4 KiB search space. */
365 if (req_size == 0)
366 req_size = 4 * 1024;
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800367
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500368 debug("Looking for coreboot table at %" PRIx64 " %zd bytes.\n",
Aaron Durbin46300aa2017-09-26 16:22:38 -0600369 address, req_size);
370
371 buf = map_memory(&header_mapping, address, req_size);
372
Timothy Pearsonbea71402015-09-05 18:07:17 -0500373 if (!buf)
Aaron Durbin46300aa2017-09-26 16:22:38 -0600374 return -1;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700375
Aaron Durbin46300aa2017-09-26 16:22:38 -0600376 /* look at every 16 bytes */
Aaron Durbincf20c902017-09-28 17:52:59 -0600377 for (i = 0; i <= req_size - sizeof(struct lb_header); i += 16) {
Aaron Durbin46300aa2017-09-26 16:22:38 -0600378 int ret;
Aaron Durbinf2a38222017-09-26 17:44:28 -0600379 const struct lb_header *lbh;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600380 struct mapping table_mapping;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700381
Aaron Durbin46300aa2017-09-26 16:22:38 -0600382 lbh = buf + i;
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800383 if (memcmp(lbh->signature, "LBIO", sizeof(lbh->signature)) ||
384 !lbh->header_bytes ||
Julius Wernerc228bef2024-01-30 19:33:40 -0800385 ipchksum(lbh, sizeof(*lbh))) {
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700386 continue;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700387 }
388
Aaron Durbin46300aa2017-09-26 16:22:38 -0600389 /* Map in the whole table to parse. */
390 if (!map_memory(&table_mapping, address + i + lbh->header_bytes,
391 lbh->table_bytes)) {
392 debug("Couldn't map in table\n");
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700393 continue;
394 }
395
Julius Wernerc228bef2024-01-30 19:33:40 -0800396 if (ipchksum(mapping_virt(&table_mapping), lbh->table_bytes) !=
Aaron Durbin46300aa2017-09-26 16:22:38 -0600397 lbh->table_checksum) {
398 debug("Signature found, but wrong checksum.\n");
399 unmap_memory(&table_mapping);
400 continue;
401 }
402
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800403 debug("Found!\n");
404
Aaron Durbin46300aa2017-09-26 16:22:38 -0600405 ret = parse_cbtable_entries(&table_mapping);
Aaron Durbin09c0c112015-09-30 12:33:01 -0500406
Aaron Durbin46300aa2017-09-26 16:22:38 -0600407 /* Table parsing failed. */
408 if (ret < 0) {
409 unmap_memory(&table_mapping);
410 continue;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700411 }
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800412
Aaron Durbin46300aa2017-09-26 16:22:38 -0600413 /* Succeeded in parsing the table. Header not needed anymore. */
414 unmap_memory(&header_mapping);
415
416 /*
417 * Table parsing succeeded. If forwarding table not found update
418 * coreboot table mapping for future use.
419 */
420 if (ret == 0)
421 lbtable_mapping = table_mapping;
422 else
423 unmap_memory(&table_mapping);
424
425 return 0;
426 }
427
428 unmap_memory(&header_mapping);
429
430 return -1;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700431}
432
Patrick Georgid00f1802015-07-13 16:53:50 +0200433#if defined(linux) && (defined(__i386__) || defined(__x86_64__))
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700434/*
Aaron Durbin08e920e2016-03-12 08:41:34 +0100435 * read CPU frequency from a sysfs file, return an frequency in Megahertz as
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700436 * an int or exit on any error.
437 */
Aaron Durbinc49014e2015-08-30 21:19:55 -0500438static unsigned long arch_tick_frequency(void)
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700439{
440 FILE *cpuf;
441 char freqs[100];
442 int size;
443 char *endp;
444 u64 rv;
445
446 const char* freq_file =
447 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
448
449 cpuf = fopen(freq_file, "r");
450 if (!cpuf) {
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800451 fprintf(stderr, "Could not open %s: %s\n",
452 freq_file, strerror(errno));
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700453 exit(1);
454 }
455
456 memset(freqs, 0, sizeof(freqs));
457 size = fread(freqs, 1, sizeof(freqs), cpuf);
458 if (!size || (size == sizeof(freqs))) {
459 fprintf(stderr, "Wrong number of bytes(%d) read from %s\n",
460 size, freq_file);
461 exit(1);
462 }
463 fclose(cpuf);
464 rv = strtoull(freqs, &endp, 10);
465
466 if (*endp == '\0' || *endp == '\n')
Aaron Durbin08e920e2016-03-12 08:41:34 +0100467 /* cpuinfo_max_freq is in kHz. Convert it to MHz. */
468 return rv / 1000;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700469 fprintf(stderr, "Wrong formatted value ^%s^ read from %s\n",
470 freqs, freq_file);
471 exit(1);
472}
Patrick Georgid00f1802015-07-13 16:53:50 +0200473#elif defined(__OpenBSD__) && (defined(__i386__) || defined(__x86_64__))
Aaron Durbinc49014e2015-08-30 21:19:55 -0500474static unsigned long arch_tick_frequency(void)
Patrick Georgid00f1802015-07-13 16:53:50 +0200475{
476 int mib[2] = { CTL_HW, HW_CPUSPEED };
477 static int value = 0;
478 size_t value_len = sizeof(value);
479
Aaron Durbinc49014e2015-08-30 21:19:55 -0500480 /* Return 1 MHz when sysctl fails. */
Patrick Georgid00f1802015-07-13 16:53:50 +0200481 if ((value == 0) && (sysctl(mib, 2, &value, &value_len, NULL, 0) == -1))
Aaron Durbinc49014e2015-08-30 21:19:55 -0500482 return 1;
Patrick Georgid00f1802015-07-13 16:53:50 +0200483
Aaron Durbinc49014e2015-08-30 21:19:55 -0500484 return value;
Patrick Georgid00f1802015-07-13 16:53:50 +0200485}
Stefan Reinauerd8ef9e92013-07-31 15:44:37 -0700486#else
Aaron Durbinc49014e2015-08-30 21:19:55 -0500487static unsigned long arch_tick_frequency(void)
Stefan Reinauerd8ef9e92013-07-31 15:44:37 -0700488{
Aaron Durbinc49014e2015-08-30 21:19:55 -0500489 /* 1 MHz = 1us. */
490 return 1;
Stefan Reinauerd8ef9e92013-07-31 15:44:37 -0700491}
492#endif
493
Aaron Durbinc49014e2015-08-30 21:19:55 -0500494static unsigned long tick_freq_mhz;
495
496static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz)
497{
498 tick_freq_mhz = table_tick_freq_mhz;
499
Martin Rothac9d6b82017-12-11 13:27:56 -0700500 /* Honor table frequency if present. */
501 if (!tick_freq_mhz)
502 tick_freq_mhz = arch_tick_frequency();
Aaron Durbinc49014e2015-08-30 21:19:55 -0500503
504 if (!tick_freq_mhz) {
505 fprintf(stderr, "Cannot determine timestamp tick frequency.\n");
506 exit(1);
507 }
Martin Rothac9d6b82017-12-11 13:27:56 -0700508
509 debug("Timestamp tick frequency: %ld MHz\n", tick_freq_mhz);
Aaron Durbinc49014e2015-08-30 21:19:55 -0500510}
511
Jacob Garber79a2f472019-06-27 17:23:25 -0600512static u64 arch_convert_raw_ts_entry(u64 ts)
Aaron Durbinc49014e2015-08-30 21:19:55 -0500513{
514 return ts / tick_freq_mhz;
515}
516
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700517/*
518 * Print an integer in 'normalized' form - with commas separating every three
Julius Wernera7d92442014-12-02 20:51:19 -0800519 * decimal orders.
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700520 */
Julius Wernera7d92442014-12-02 20:51:19 -0800521static void print_norm(u64 v)
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700522{
Julius Wernera7d92442014-12-02 20:51:19 -0800523 if (v >= 1000) {
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700524 /* print the higher order sections first */
Julius Wernera7d92442014-12-02 20:51:19 -0800525 print_norm(v / 1000);
526 printf(",%3.3u", (u32)(v % 1000));
527 } else {
528 printf("%u", (u32)(v % 1000));
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700529 }
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700530}
531
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000532static uint64_t timestamp_get(uint64_t table_tick_freq_mhz)
533{
534#if defined(__i386__) || defined(__x86_64__)
535 uint64_t tsc = __rdtsc();
536
537 /* No tick frequency specified means raw TSC values. */
538 if (!table_tick_freq_mhz)
539 return tsc;
540
541 if (tsc_freq_khz)
542 return tsc * table_tick_freq_mhz * 1000 / tsc_freq_khz;
Nick Vaccaro946e2922022-04-26 17:14:03 -0700543#else
544 (void)table_tick_freq_mhz;
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000545#endif
546 die("Don't know how to obtain timestamps on this platform.\n");
547 return 0;
548}
549
Aaron Durbinfbff3012015-08-30 22:00:12 -0500550static const char *timestamp_name(uint32_t id)
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700551{
Jacob Garber414d5d82019-06-27 16:02:32 -0600552 for (size_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
Aaron Durbinfbff3012015-08-30 22:00:12 -0500553 if (timestamp_ids[i].id == id)
554 return timestamp_ids[i].name;
555 }
556 return "<unknown>";
557}
558
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000559static uint32_t timestamp_enum_name_to_id(const char *name)
560{
561 for (size_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
562 if (!strcmp(timestamp_ids[i].enum_name, name))
563 return timestamp_ids[i].id;
564 }
565 return 0;
566}
567
Aaron Durbinfbff3012015-08-30 22:00:12 -0500568static uint64_t timestamp_print_parseable_entry(uint32_t id, uint64_t stamp,
569 uint64_t prev_stamp)
570{
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700571 const char *name;
Aaron Durbin799bf782015-08-06 13:52:08 -0500572 uint64_t step_time;
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700573
Aaron Durbinfbff3012015-08-30 22:00:12 -0500574 name = timestamp_name(id);
575
576 step_time = arch_convert_raw_ts_entry(stamp - prev_stamp);
577
578 /* ID<tab>absolute time<tab>relative time<tab>description */
579 printf("%d\t", id);
580 printf("%llu\t", (long long)arch_convert_raw_ts_entry(stamp));
581 printf("%llu\t", (long long)step_time);
582 printf("%s\n", name);
583
584 return step_time;
585}
586
Jacob Garber79a2f472019-06-27 17:23:25 -0600587static uint64_t timestamp_print_entry(uint32_t id, uint64_t stamp, uint64_t prev_stamp)
Aaron Durbinfbff3012015-08-30 22:00:12 -0500588{
589 const char *name;
590 uint64_t step_time;
591
592 name = timestamp_name(id);
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700593
594 printf("%4d:", id);
Julius Wernera7d92442014-12-02 20:51:19 -0800595 printf("%-50s", name);
596 print_norm(arch_convert_raw_ts_entry(stamp));
Aaron Durbin799bf782015-08-06 13:52:08 -0500597 step_time = arch_convert_raw_ts_entry(stamp - prev_stamp);
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700598 if (prev_stamp) {
599 printf(" (");
Aaron Durbin799bf782015-08-06 13:52:08 -0500600 print_norm(step_time);
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700601 printf(")");
602 }
603 printf("\n");
Aaron Durbin799bf782015-08-06 13:52:08 -0500604
605 return step_time;
Stefan Reinauer0db924d2013-08-09 11:06:11 -0700606}
607
Raul E Rangeld4fec682018-05-11 11:08:07 -0600608static int compare_timestamp_entries(const void *a, const void *b)
609{
610 const struct timestamp_entry *tse_a = (struct timestamp_entry *)a;
611 const struct timestamp_entry *tse_b = (struct timestamp_entry *)b;
612
Furquan Shaikh8f567322018-05-17 15:08:03 -0700613 if (tse_a->entry_stamp > tse_b->entry_stamp)
614 return 1;
615 else if (tse_a->entry_stamp < tse_b->entry_stamp)
616 return -1;
617
618 return 0;
Raul E Rangeld4fec682018-05-11 11:08:07 -0600619}
620
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100621static int find_matching_end(struct timestamp_table *sorted_tst_p, uint32_t start, uint32_t end)
622{
623 uint32_t id = sorted_tst_p->entries[start].entry_id;
624 uint32_t possible_match = 0;
625
626 for (uint32_t i = 0; i < ARRAY_SIZE(timestamp_ids); ++i) {
627 if (timestamp_ids[i].id == id) {
628 possible_match = timestamp_ids[i].id_end;
629 break;
630 }
631 }
632
633 /* No match found or timestamp not defined in IDs table */
634 if (!possible_match)
635 return -1;
636
637 for (uint32_t i = start + 1; i < end; i++)
638 if (sorted_tst_p->entries[i].entry_id == possible_match)
639 return i;
640
641 return -1;
642}
643
644static const char *get_timestamp_name(const uint32_t id)
645{
646 for (uint32_t i = 0; i < ARRAY_SIZE(timestamp_ids); i++)
647 if (timestamp_ids[i].id == id)
648 return timestamp_ids[i].enum_name;
649
650 return "UNKNOWN";
651}
652
653struct ts_range_stack {
654 const char *name;
655 const char *end_name;
656 uint32_t end;
657};
658
659static void print_with_path(struct ts_range_stack *range_stack, const int stacklvl,
660 const uint64_t stamp, const char *last_part)
661{
662 for (int i = 1; i <= stacklvl; ++i) {
663 printf("%s -> %s", range_stack[i].name, range_stack[i].end_name);
664 if (i < stacklvl || last_part)
665 putchar(';');
666 }
667 if (last_part)
668 printf("%s", last_part);
Paul Fagerburgac683842022-04-02 08:28:40 -0600669 printf(" %llu\n", (long long)arch_convert_raw_ts_entry(stamp));
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100670}
671
672enum timestamps_print_type {
673 TIMESTAMPS_PRINT_NONE,
674 TIMESTAMPS_PRINT_NORMAL,
675 TIMESTAMPS_PRINT_MACHINE_READABLE,
676 TIMESTAMPS_PRINT_STACKED,
677};
678
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700679/* dump the timestamp table */
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100680static void dump_timestamps(enum timestamps_print_type output_type)
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700681{
Aaron Durbinf2a38222017-09-26 17:44:28 -0600682 const struct timestamp_table *tst_p;
Raul E Rangeld4fec682018-05-11 11:08:07 -0600683 struct timestamp_table *sorted_tst_p;
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500684 size_t size;
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100685 uint64_t prev_stamp = 0;
686 uint64_t total_time = 0;
Aaron Durbin46300aa2017-09-26 16:22:38 -0600687 struct mapping timestamp_mapping;
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800688
689 if (timestamps.tag != LB_TAG_TIMESTAMPS) {
690 fprintf(stderr, "No timestamps found in coreboot table.\n");
691 return;
692 }
693
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500694 size = sizeof(*tst_p);
Aaron Durbin46300aa2017-09-26 16:22:38 -0600695 tst_p = map_memory(&timestamp_mapping, timestamps.cbmem_addr, size);
696 if (!tst_p)
697 die("Unable to map timestamp header\n");
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700698
Aaron Durbinc49014e2015-08-30 21:19:55 -0500699 timestamp_set_tick_freq(tst_p->tick_freq_mhz);
700
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100701 if (output_type == TIMESTAMPS_PRINT_NORMAL)
Aaron Durbinfbff3012015-08-30 22:00:12 -0500702 printf("%d entries total:\n\n", tst_p->num_entries);
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500703 size += tst_p->num_entries * sizeof(tst_p->entries[0]);
704
Aaron Durbin46300aa2017-09-26 16:22:38 -0600705 unmap_memory(&timestamp_mapping);
706
707 tst_p = map_memory(&timestamp_mapping, timestamps.cbmem_addr, size);
708 if (!tst_p)
709 die("Unable to map full timestamp table\n");
Aaron Durbinb58f9e32014-10-07 14:56:35 -0500710
Bora Guvendike383b3d2021-11-22 16:12:48 -0800711 sorted_tst_p = malloc(size + sizeof(struct timestamp_entry));
Raul E Rangeld4fec682018-05-11 11:08:07 -0600712 if (!sorted_tst_p)
713 die("Failed to allocate memory");
Julius Wernere3c23912018-11-26 15:57:59 -0800714 aligned_memcpy(sorted_tst_p, tst_p, size);
Raul E Rangeld4fec682018-05-11 11:08:07 -0600715
Bora Guvendike383b3d2021-11-22 16:12:48 -0800716 /*
717 * Insert a timestamp to represent the base time (start of coreboot),
718 * in case we have to rebase for negative timestamps below.
719 */
720 sorted_tst_p->entries[tst_p->num_entries].entry_id = 0;
721 sorted_tst_p->entries[tst_p->num_entries].entry_stamp = 0;
722 sorted_tst_p->num_entries += 1;
723
Raul E Rangeld4fec682018-05-11 11:08:07 -0600724 qsort(&sorted_tst_p->entries[0], sorted_tst_p->num_entries,
725 sizeof(struct timestamp_entry), compare_timestamp_entries);
726
Bora Guvendike383b3d2021-11-22 16:12:48 -0800727 /*
728 * If there are negative timestamp entries, rebase all of the
729 * timestamps to the lowest one in the list.
730 */
Bora Guvendikc79da5f2022-02-10 20:13:50 -0800731 if (sorted_tst_p->entries[0].entry_stamp < 0) {
Bora Guvendike383b3d2021-11-22 16:12:48 -0800732 sorted_tst_p->base_time = -sorted_tst_p->entries[0].entry_stamp;
Bora Guvendikc79da5f2022-02-10 20:13:50 -0800733 prev_stamp = 0;
734 } else {
735 prev_stamp = tst_p->base_time;
736 }
Bora Guvendike383b3d2021-11-22 16:12:48 -0800737
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100738 struct ts_range_stack range_stack[20];
739 range_stack[0].end = sorted_tst_p->num_entries;
740 int stacklvl = 0;
741
Jacob Garber414d5d82019-06-27 16:02:32 -0600742 for (uint32_t i = 0; i < sorted_tst_p->num_entries; i++) {
Aaron Durbin31540fb2015-07-11 12:44:10 -0500743 uint64_t stamp;
Raul E Rangeld4fec682018-05-11 11:08:07 -0600744 const struct timestamp_entry *tse = &sorted_tst_p->entries[i];
Aaron Durbin31540fb2015-07-11 12:44:10 -0500745
746 /* Make all timestamps absolute. */
Raul E Rangeld4fec682018-05-11 11:08:07 -0600747 stamp = tse->entry_stamp + sorted_tst_p->base_time;
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100748 if (output_type == TIMESTAMPS_PRINT_MACHINE_READABLE) {
749 timestamp_print_parseable_entry(tse->entry_id, stamp, prev_stamp);
750 } else if (output_type == TIMESTAMPS_PRINT_NORMAL) {
751 total_time += timestamp_print_entry(tse->entry_id, stamp, prev_stamp);
752 } else if (output_type == TIMESTAMPS_PRINT_STACKED) {
753 bool end_of_range = false;
754 /* Iterate over stacked entries to pop all ranges, which are closed by
755 current element. For example, assuming two ranges: (TS_A, TS_C),
756 (TS_B, TS_C) it will pop all of them instead of just last one. */
757 while (stacklvl > 0 && range_stack[stacklvl].end == i) {
758 end_of_range = true;
759 stacklvl--;
760 }
761
762 int match =
763 find_matching_end(sorted_tst_p, i, range_stack[stacklvl].end);
764 if (match != -1) {
765 const uint64_t match_stamp =
766 sorted_tst_p->entries[match].entry_stamp
767 + sorted_tst_p->base_time;
768 stacklvl++;
769 assert(stacklvl < (int)ARRAY_SIZE(range_stack));
770 range_stack[stacklvl].name = get_timestamp_name(tse->entry_id);
771 range_stack[stacklvl].end_name = get_timestamp_name(
772 sorted_tst_p->entries[match].entry_id);
773 range_stack[stacklvl].end = match;
774 print_with_path(range_stack, stacklvl, match_stamp - stamp,
775 NULL);
776 } else if (!end_of_range) {
777 print_with_path(range_stack, stacklvl, stamp - prev_stamp,
778 get_timestamp_name(tse->entry_id));
779 }
780 /* else: No match && end_of_range == true */
781 }
Aaron Durbin31540fb2015-07-11 12:44:10 -0500782 prev_stamp = stamp;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700783 }
Stefan Reinauer05cbce62013-01-03 14:30:33 -0800784
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +0100785 if (output_type == TIMESTAMPS_PRINT_NORMAL) {
Aaron Durbinfbff3012015-08-30 22:00:12 -0500786 printf("\nTotal Time: ");
787 print_norm(total_time);
788 printf("\n");
789 }
Aaron Durbin799bf782015-08-06 13:52:08 -0500790
Aaron Durbin46300aa2017-09-26 16:22:38 -0600791 unmap_memory(&timestamp_mapping);
Raul E Rangeld4fec682018-05-11 11:08:07 -0600792 free(sorted_tst_p);
Vadim Bendebury6d18fd02012-09-27 19:24:07 -0700793}
794
Mattias Nisslerecc165b2022-02-08 23:01:50 +0000795/* add a timestamp entry */
796static void timestamp_add_now(uint32_t timestamp_id)
797{
798 struct timestamp_table *tst_p;
799 struct mapping timestamp_mapping;
800
801 if (timestamps.tag != LB_TAG_TIMESTAMPS) {
802 die("No timestamps found in coreboot table.\n");
803 }
804
805 tst_p = map_memory_with_prot(&timestamp_mapping, timestamps.cbmem_addr,
806 timestamps.size, PROT_READ | PROT_WRITE);
807 if (!tst_p)
808 die("Unable to map timestamp table\n");
809
810 /*
811 * Note that coreboot sizes the cbmem entry in the table according to
812 * max_entries, so it's OK to just add more entries if there's room.
813 */
814 if (tst_p->num_entries >= tst_p->max_entries) {
815 die("Not enough space to add timestamp.\n");
816 } else {
817 int64_t time =
818 timestamp_get(tst_p->tick_freq_mhz) - tst_p->base_time;
819 tst_p->entries[tst_p->num_entries].entry_id = timestamp_id;
820 tst_p->entries[tst_p->num_entries].entry_stamp = time;
821 tst_p->num_entries += 1;
822 }
823
824 unmap_memory(&timestamp_mapping);
825}
826
Sergii Dmytruk6da62682022-10-23 00:55:03 +0300827static bool can_print(const uint8_t *data, size_t len)
828{
829 unsigned int i;
830 for (i = 0; i < len; i++) {
831 if (!isprint(data[i]) && !isspace(data[i])) {
832 /* If printable prefix is followed by zeroes, this is a valid string */
833 for (; i < len; i++) {
834 if (data[i] != 0)
835 return false;
836 }
837 return true;
838 }
839 }
840 return true;
841}
842
843static void print_hex_string(const uint8_t *hex, size_t len)
844{
845 unsigned int i;
846 for (i = 0; i < len; i++)
847 printf("%02x", hex[i]);
848}
849
850static void print_hex_line(const uint8_t *hex, size_t len)
851{
852 print_hex_string(hex, len);
853 printf("\n");
854}
855
856static void print_event_type(uint32_t event_type)
857{
858 unsigned int known_event_count = ARRAY_SIZE(tpm_event_types);
859 if (event_type >= known_event_count)
860 printf("Unknown (0x%x >= %u)", event_type, known_event_count);
861 else
862 printf("%s", tpm_event_types[event_type]);
863}
864
865static void parse_tpm12_log(const struct tcpa_spec_entry *spec_log)
866{
867 const uint8_t zero_block[sizeof(struct tcpa_spec_entry)] = {0};
868
869 uintptr_t current;
870 uint32_t counter = 0;
871
872 printf("TCPA log:\n");
873 printf("\tSpecification: %d.%d%d\n",
874 spec_log->spec_version_major,
875 spec_log->spec_version_minor,
876 spec_log->spec_errata);
877 printf("\tPlatform class: %s\n",
878 le32toh(spec_log->platform_class) == 0 ? "PC Client" :
879 le32toh(spec_log->platform_class) == 1 ? "Server" : "Unknown");
880
881 current = (uintptr_t)&spec_log->vendor_info[spec_log->vendor_info_size];
882 while (memcmp((const void *)current, (const void *)zero_block, sizeof(zero_block))) {
883 uint32_t len;
884 struct tcpa_log_entry *log_entry = (void *)current;
885 uint32_t event_type = le32toh(log_entry->event_type);
886
887 printf("TCPA log entry %u:\n", ++counter);
888 printf("\tPCR: %d\n", le32toh(log_entry->pcr));
889 printf("\tEvent type: ");
890 print_event_type(event_type);
891 printf("\n");
892 printf("\tDigest: ");
893 print_hex_line(log_entry->digest, SHA1_DIGEST_SIZE);
894 current += sizeof(struct tcpa_log_entry);
895 len = le32toh(log_entry->event_data_size);
896 if (len != 0) {
897 current += len;
898 printf("\tEvent data: ");
899 if (can_print(log_entry->event, len))
900 printf("%.*s\n", len, log_entry->event);
901 else
902 print_hex_line(log_entry->event, len);
903 } else {
904 printf("\tEvent data not provided\n");
905 }
906 }
907}
908
909static uint32_t print_tpm2_digests(struct tcg_pcr_event2_header *log_entry)
910{
911 unsigned int i;
912 uintptr_t current = (uintptr_t)log_entry->digests;
913
914 for (i = 0; i < le32toh(log_entry->digest_count); i++) {
915 struct tpm_hash_algorithm *hash = (struct tpm_hash_algorithm *)current;
916 switch (le16toh(hash->hashAlg)) {
917 case TPM2_ALG_SHA1:
918 printf("\t\t SHA1: ");
919 print_hex_line(hash->digest.sha1, SHA1_DIGEST_SIZE);
920 current += sizeof(hash->hashAlg) + SHA1_DIGEST_SIZE;
921 break;
922 case TPM2_ALG_SHA256:
923 printf("\t\t SHA256: ");
924 print_hex_line(hash->digest.sha256, SHA256_DIGEST_SIZE);
925 current += sizeof(hash->hashAlg) + SHA256_DIGEST_SIZE;
926 break;
927 case TPM2_ALG_SHA384:
928 printf("\t\t SHA384: ");
929 print_hex_line(hash->digest.sha384, SHA384_DIGEST_SIZE);
930 current += sizeof(hash->hashAlg) + SHA384_DIGEST_SIZE;
931 break;
932 case TPM2_ALG_SHA512:
933 printf("\t\t SHA512: ");
934 print_hex_line(hash->digest.sha512, SHA512_DIGEST_SIZE);
935 current += sizeof(hash->hashAlg) + SHA512_DIGEST_SIZE;
936 break;
937 case TPM2_ALG_SM3_256:
938 printf("\t\t SM3: ");
939 print_hex_line(hash->digest.sm3_256, SM3_256_DIGEST_SIZE);
940 current += sizeof(hash->hashAlg) + SM3_256_DIGEST_SIZE;
941 break;
942 default:
943 die("Unknown hash algorithm\n");
944 }
945 }
946
947 return current - (uintptr_t)&log_entry->digest_count;
948}
949
950static void parse_tpm2_log(const struct tcg_efi_spec_id_event *tpm2_log)
951{
952 const uint8_t zero_block[12] = {0}; /* Only PCR index, event type and digest count */
953
954 uintptr_t current;
955 uint32_t counter = 0;
956
957 printf("TPM2 log:\n");
958 printf("\tSpecification: %d.%d%d\n",
959 tpm2_log->spec_version_major,
960 tpm2_log->spec_version_minor,
961 tpm2_log->spec_errata);
962 printf("\tPlatform class: %s\n",
963 le32toh(tpm2_log->platform_class) == 0 ? "PC Client" :
964 le32toh(tpm2_log->platform_class) == 1 ? "Server" : "Unknown");
965
966 /* Start after the first variable-sized part of the header */
967 current = (uintptr_t)&tpm2_log->digest_sizes[le32toh(tpm2_log->num_of_algorithms)];
968 /* current is at `uint8_t vendor_info_size` here */
969 current += 1 + *(uint8_t *)current;
970
971 while (memcmp((const void *)current, (const void *)zero_block, sizeof(zero_block))) {
972 uint32_t len;
973 struct tcg_pcr_event2_header *log_entry = (void *)current;
974 uint32_t event_type = le32toh(log_entry->event_type);
975
976 printf("TPM2 log entry %u:\n", ++counter);
977 printf("\tPCR: %d\n", le32toh(log_entry->pcr_index));
978 printf("\tEvent type: ");
979 print_event_type(event_type);
980 printf("\n");
981
982 current = (uintptr_t)&log_entry->digest_count;
983 if (le32toh(log_entry->digest_count) > 0) {
984 printf("\tDigests:\n");
985 current += print_tpm2_digests(log_entry);
986 } else {
987 printf("\tNo digests in this log entry\n");
988 current += sizeof(log_entry->digest_count);
989 }
990 /* Now event size and event are left to be parsed */
991 len = le32toh(*(uint32_t *)current);
992 current += sizeof(uint32_t);
993 if (len != 0) {
994 printf("\tEvent data: %.*s\n", len, (const char *)current);
995 current += len;
996 } else {
997 printf("\tEvent data not provided\n");
998 }
999 }
1000}
1001
1002/* Dump the TPM log table in format defined by specifications */
1003static void dump_tpm_std_log(uint64_t addr, size_t size)
1004{
1005 const void *event_log;
1006 const struct tcpa_spec_entry *tspec_entry;
1007 const struct tcg_efi_spec_id_event *tcg_spec_entry;
1008 struct mapping log_mapping;
1009
1010 event_log = map_memory(&log_mapping, addr, size);
1011 if (!event_log)
1012 die("Unable to map TPM eventlog\n");
1013
1014 tspec_entry = event_log;
1015 if (!strcmp((const char *)tspec_entry->signature, TCPA_SPEC_ID_EVENT_SIGNATURE)) {
1016 if (tspec_entry->spec_version_major == 1 &&
1017 tspec_entry->spec_version_minor == 2 &&
1018 tspec_entry->spec_errata >= 1 &&
1019 le32toh(tspec_entry->entry.event_type) == EV_NO_ACTION) {
1020 parse_tpm12_log(tspec_entry);
1021 } else {
1022 fprintf(stderr, "Unknown TPM1.2 log specification\n");
1023 }
1024 unmap_memory(&log_mapping);
1025 return;
1026 }
1027
1028 tcg_spec_entry = event_log;
1029 if (!strcmp((const char *)tcg_spec_entry->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE)) {
1030 if (tcg_spec_entry->spec_version_major == 2 &&
1031 tcg_spec_entry->spec_version_minor == 0 &&
1032 le32toh(tcg_spec_entry->event_type) == EV_NO_ACTION) {
1033 parse_tpm2_log(tcg_spec_entry);
1034 } else {
1035 fprintf(stderr, "Unknown TPM2 log specification.\n");
1036 }
1037 unmap_memory(&log_mapping);
1038 return;
1039 }
1040
1041 fprintf(stderr, "Unknown TPM log specification: %.*s\n",
1042 (int)sizeof(tcg_spec_entry->signature),
1043 (const char *)tcg_spec_entry->signature);
1044
1045 unmap_memory(&log_mapping);
1046}
1047
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001048/* dump the TPM CB log table */
1049static void dump_tpm_cb_log(void)
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001050{
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001051 const struct tpm_cb_log_table *tclt_p;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001052 size_t size;
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001053 struct mapping log_mapping;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001054
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001055 if (tpm_cb_log.tag != LB_TAG_TPM_CB_LOG) {
1056 fprintf(stderr, "No TPM log found in coreboot table.\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001057 return;
1058 }
1059
1060 size = sizeof(*tclt_p);
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001061 tclt_p = map_memory(&log_mapping, tpm_cb_log.cbmem_addr, size);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001062 if (!tclt_p)
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001063 die("Unable to map TPM log header\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001064
1065 size += tclt_p->num_entries * sizeof(tclt_p->entries[0]);
1066
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001067 unmap_memory(&log_mapping);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001068
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001069 tclt_p = map_memory(&log_mapping, tpm_cb_log.cbmem_addr, size);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001070 if (!tclt_p)
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001071 die("Unable to map full TPM log table\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001072
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001073 printf("coreboot TPM log:\n\n");
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001074
Jacob Garber414d5d82019-06-27 16:02:32 -06001075 for (uint16_t i = 0; i < tclt_p->num_entries; i++) {
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001076 const struct tpm_cb_log_entry *tce = &tclt_p->entries[i];
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001077
Philipp Deppenwiesec9b7d1f2018-11-10 00:35:02 +01001078 printf(" PCR-%u ", tce->pcr);
Sergii Dmytruk6da62682022-10-23 00:55:03 +03001079 print_hex_string(tce->digest, tce->digest_length);
Philipp Deppenwiesec9b7d1f2018-11-10 00:35:02 +01001080 printf(" %s [%s]\n", tce->digest_type, tce->name);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001081 }
1082
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001083 unmap_memory(&log_mapping);
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001084}
1085
Sergii Dmytruk6da62682022-10-23 00:55:03 +03001086static void dump_tpm_log(void)
1087{
1088 uint64_t start;
1089 size_t size;
1090
1091 if (!find_cbmem_entry(CBMEM_ID_TCPA_TCG_LOG, &start, &size) ||
1092 !find_cbmem_entry(CBMEM_ID_TPM2_TCG_LOG, &start, &size))
1093 dump_tpm_std_log(start, size);
1094 else
1095 dump_tpm_cb_log();
1096}
1097
Julius Wernerd67c6872017-02-02 17:32:00 -08001098struct cbmem_console {
1099 u32 size;
1100 u32 cursor;
Elyes Haouasfc2f3042023-07-30 13:06:10 +02001101 u8 body[];
Julius Wernerd67c6872017-02-02 17:32:00 -08001102} __attribute__ ((__packed__));
1103
1104#define CBMC_CURSOR_MASK ((1 << 28) - 1)
1105#define CBMC_OVERFLOW (1 << 31)
1106
Julius Werner8202fc42021-09-08 16:10:15 -07001107enum console_print_type {
1108 CONSOLE_PRINT_FULL = 0,
1109 CONSOLE_PRINT_LAST,
1110 CONSOLE_PRINT_PREVIOUS,
1111};
1112
Julius Wernerb8258bd2022-02-09 17:26:39 -08001113static int parse_loglevel(char *arg, int *print_unknown_logs)
1114{
1115 if (arg[0] == '+') {
1116 *print_unknown_logs = 1;
1117 arg++;
1118 } else {
1119 *print_unknown_logs = 0;
1120 }
1121
1122 char *endptr;
1123 int loglevel = strtol(arg, &endptr, 0);
1124 if (*endptr == '\0' && loglevel >= BIOS_EMERG && loglevel <= BIOS_LOG_PREFIX_MAX_LEVEL)
1125 return loglevel;
1126
1127 /* Only match first 3 characters so `NOTE` and `NOTICE` both match. */
1128 for (int i = BIOS_EMERG; i <= BIOS_LOG_PREFIX_MAX_LEVEL; i++)
1129 if (!strncasecmp(arg, bios_log_prefix[i], 3))
1130 return i;
1131
1132 *print_unknown_logs = 1;
1133 return BIOS_NEVER;
1134}
1135
Stefan Reinauer19f87562013-01-07 13:37:12 -08001136/* dump the cbmem console */
Julius Wernerb8258bd2022-02-09 17:26:39 -08001137static void dump_console(enum console_print_type type, int max_loglevel, int print_unknown_logs)
Stefan Reinauer19f87562013-01-07 13:37:12 -08001138{
Aaron Durbinf2a38222017-09-26 17:44:28 -06001139 const struct cbmem_console *console_p;
Stefan Reinauer19f87562013-01-07 13:37:12 -08001140 char *console_c;
Julius Werner8202fc42021-09-08 16:10:15 -07001141 size_t size, cursor, previous;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001142 struct mapping console_mapping;
Stefan Reinauer19f87562013-01-07 13:37:12 -08001143
1144 if (console.tag != LB_TAG_CBMEM_CONSOLE) {
1145 fprintf(stderr, "No console found in coreboot table.\n");
1146 return;
1147 }
1148
Julius Wernerd67c6872017-02-02 17:32:00 -08001149 size = sizeof(*console_p);
Aaron Durbin46300aa2017-09-26 16:22:38 -06001150 console_p = map_memory(&console_mapping, console.cbmem_addr, size);
1151 if (!console_p)
1152 die("Unable to map console object.\n");
1153
Julius Wernerd67c6872017-02-02 17:32:00 -08001154 cursor = console_p->cursor & CBMC_CURSOR_MASK;
1155 if (!(console_p->cursor & CBMC_OVERFLOW) && cursor < console_p->size)
Vladimir Serbinenkof4a0d012013-03-30 12:15:12 +01001156 size = cursor;
Julius Wernerd67c6872017-02-02 17:32:00 -08001157 else
1158 size = console_p->size;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001159 unmap_memory(&console_mapping);
Julius Wernerd67c6872017-02-02 17:32:00 -08001160
1161 console_c = malloc(size + 1);
Stefan Reinauer19f87562013-01-07 13:37:12 -08001162 if (!console_c) {
1163 fprintf(stderr, "Not enough memory for console.\n");
1164 exit(1);
1165 }
Julius Wernerd67c6872017-02-02 17:32:00 -08001166 console_c[size] = '\0';
Stefan Reinauer19f87562013-01-07 13:37:12 -08001167
Aaron Durbin46300aa2017-09-26 16:22:38 -06001168 console_p = map_memory(&console_mapping, console.cbmem_addr,
1169 size + sizeof(*console_p));
1170
1171 if (!console_p)
1172 die("Unable to map full console object.\n");
1173
Julius Wernerd67c6872017-02-02 17:32:00 -08001174 if (console_p->cursor & CBMC_OVERFLOW) {
1175 if (cursor >= size) {
1176 printf("cbmem: ERROR: CBMEM console struct is illegal, "
1177 "output may be corrupt or out of order!\n\n");
1178 cursor = 0;
1179 }
1180 aligned_memcpy(console_c, console_p->body + cursor,
1181 size - cursor);
1182 aligned_memcpy(console_c + size - cursor,
1183 console_p->body, cursor);
1184 } else {
1185 aligned_memcpy(console_c, console_p->body, size);
1186 }
Stefan Reinauer19f87562013-01-07 13:37:12 -08001187
Julius Wernerd67c6872017-02-02 17:32:00 -08001188 /* Slight memory corruption may occur between reboots and give us a few
1189 unprintable characters like '\0'. Replace them with '?' on output. */
1190 for (cursor = 0; cursor < size; cursor++)
Julius Werner984d03c2022-01-21 15:33:47 -08001191 if (!isprint(console_c[cursor]) && !isspace(console_c[cursor])
1192 && !BIOS_LOG_IS_MARKER(console_c[cursor]))
Julius Wernerd67c6872017-02-02 17:32:00 -08001193 console_c[cursor] = '?';
Stefan Reinauer19f87562013-01-07 13:37:12 -08001194
Julius Werner8202fc42021-09-08 16:10:15 -07001195 /* We detect the reboot cutoff by looking for a bootblock, romstage or
Julius Wernerb7b64a92017-04-28 16:31:46 -07001196 ramstage banner, in that order (to account for platforms without
1197 CONFIG_BOOTBLOCK_CONSOLE and/or CONFIG_EARLY_CONSOLE). Once we find
Julius Werner8202fc42021-09-08 16:10:15 -07001198 a banner, store the last two matches for that stage and stop. */
1199 cursor = previous = 0;
1200 if (type != CONSOLE_PRINT_FULL) {
You-Cheng Syu1430b392019-07-01 16:40:25 +08001201#define BANNER_REGEX(stage) \
Julius Wernerce878322022-03-09 16:51:43 -08001202 "\n\n.?coreboot-[^\n]* " stage " starting.*\\.\\.\\.\n"
1203#define OVERFLOW_REGEX(stage) "\n.?\\*\\*\\* Pre-CBMEM " stage " console overflow"
Kangheui Won4b5c8b52020-10-07 14:29:38 +11001204 const char *regex[] = { BANNER_REGEX("verstage-before-bootblock"),
1205 BANNER_REGEX("bootblock"),
You-Cheng Syu1430b392019-07-01 16:40:25 +08001206 BANNER_REGEX("verstage"),
Julius Wernerd906bb62017-05-16 13:54:18 -07001207 OVERFLOW_REGEX("romstage"),
Furquan Shaikh35972de2018-02-16 16:12:02 -08001208 BANNER_REGEX("romstage"),
1209 OVERFLOW_REGEX("ramstage"),
1210 BANNER_REGEX("ramstage") };
Julius Wernerb7b64a92017-04-28 16:31:46 -07001211
Jacob Garber414d5d82019-06-27 16:02:32 -06001212 for (size_t i = 0; !cursor && i < ARRAY_SIZE(regex); i++) {
Julius Wernerb7b64a92017-04-28 16:31:46 -07001213 regex_t re;
1214 regmatch_t match;
Konrad Adamczyk8120cb42023-04-24 10:06:30 +00001215 int res = regcomp(&re, regex[i], REG_EXTENDED | REG_NEWLINE);
Julius Wernerce878322022-03-09 16:51:43 -08001216 assert(res == 0);
Julius Wernerb7b64a92017-04-28 16:31:46 -07001217
1218 /* Keep looking for matches so we find the last one. */
Julius Werner8202fc42021-09-08 16:10:15 -07001219 while (!regexec(&re, console_c + cursor, 1, &match, 0)) {
1220 previous = cursor;
Julius Wernerb7b64a92017-04-28 16:31:46 -07001221 cursor += match.rm_so + 1;
Julius Werner8202fc42021-09-08 16:10:15 -07001222 }
Julius Wernerb7b64a92017-04-28 16:31:46 -07001223 regfree(&re);
1224 }
1225 }
1226
Julius Werner8202fc42021-09-08 16:10:15 -07001227 if (type == CONSOLE_PRINT_PREVIOUS) {
1228 console_c[cursor] = '\0';
1229 cursor = previous;
1230 }
1231
Julius Werner984d03c2022-01-21 15:33:47 -08001232 char c;
Julius Wernerb8258bd2022-02-09 17:26:39 -08001233 int suppressed = 0;
Julius Werner984d03c2022-01-21 15:33:47 -08001234 int tty = isatty(fileno(stdout));
1235 while ((c = console_c[cursor++])) {
1236 if (BIOS_LOG_IS_MARKER(c)) {
1237 int lvl = BIOS_LOG_MARKER_TO_LEVEL(c);
Julius Wernerb8258bd2022-02-09 17:26:39 -08001238 if (lvl > max_loglevel) {
1239 suppressed = 1;
1240 continue;
1241 }
1242 suppressed = 0;
Julius Werner984d03c2022-01-21 15:33:47 -08001243 if (tty)
1244 printf(BIOS_LOG_ESCAPE_PATTERN, bios_log_escape[lvl]);
1245 printf(BIOS_LOG_PREFIX_PATTERN, bios_log_prefix[lvl]);
1246 } else {
Julius Wernerb8258bd2022-02-09 17:26:39 -08001247 if (!suppressed)
1248 putchar(c);
1249 if (c == '\n') {
1250 if (tty && !suppressed)
1251 printf(BIOS_LOG_ESCAPE_RESET);
1252 suppressed = !print_unknown_logs;
1253 }
Julius Werner984d03c2022-01-21 15:33:47 -08001254 }
1255 }
1256 if (tty)
1257 printf(BIOS_LOG_ESCAPE_RESET);
1258
Stefan Reinauer19f87562013-01-07 13:37:12 -08001259 free(console_c);
Aaron Durbin46300aa2017-09-26 16:22:38 -06001260 unmap_memory(&console_mapping);
Stefan Reinauer19f87562013-01-07 13:37:12 -08001261}
1262
Stefan Reinauera9c83612013-07-16 17:47:35 -07001263static void hexdump(unsigned long memory, int length)
1264{
1265 int i;
Aaron Durbinf2a38222017-09-26 17:44:28 -06001266 const uint8_t *m;
Stefan Reinauera9c83612013-07-16 17:47:35 -07001267 int all_zero = 0;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001268 struct mapping hexdump_mapping;
Stefan Reinauera9c83612013-07-16 17:47:35 -07001269
Aaron Durbin46300aa2017-09-26 16:22:38 -06001270 m = map_memory(&hexdump_mapping, memory, length);
1271 if (!m)
1272 die("Unable to map hexdump memory.\n");
Stefan Reinauera9c83612013-07-16 17:47:35 -07001273
1274 for (i = 0; i < length; i += 16) {
1275 int j;
1276
1277 all_zero++;
1278 for (j = 0; j < 16; j++) {
1279 if(m[i+j] != 0) {
1280 all_zero = 0;
1281 break;
1282 }
1283 }
1284
1285 if (all_zero < 2) {
1286 printf("%08lx:", memory + i);
1287 for (j = 0; j < 16; j++)
1288 printf(" %02x", m[i+j]);
1289 printf(" ");
1290 for (j = 0; j < 16; j++)
1291 printf("%c", isprint(m[i+j]) ? m[i+j] : '.');
1292 printf("\n");
1293 } else if (all_zero == 2) {
1294 printf("...\n");
1295 }
1296 }
1297
Aaron Durbin46300aa2017-09-26 16:22:38 -06001298 unmap_memory(&hexdump_mapping);
Stefan Reinauera9c83612013-07-16 17:47:35 -07001299}
1300
1301static void dump_cbmem_hex(void)
1302{
1303 if (cbmem.type != LB_MEM_TABLE) {
1304 fprintf(stderr, "No coreboot CBMEM area found!\n");
1305 return;
1306 }
1307
Jianjun Wangb2537bd2022-04-08 16:57:28 +08001308 hexdump(cbmem.start, cbmem.size);
Stefan Reinauera9c83612013-07-16 17:47:35 -07001309}
1310
Jacob Garber79a2f472019-06-27 17:23:25 -06001311static void rawdump(uint64_t base, uint64_t size)
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001312{
Aaron Durbinf2a38222017-09-26 17:44:28 -06001313 const uint8_t *m;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001314 struct mapping dump_mapping;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001315
Aaron Durbin46300aa2017-09-26 16:22:38 -06001316 m = map_memory(&dump_mapping, base, size);
1317 if (!m)
1318 die("Unable to map rawdump memory\n");
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001319
Jacob Garber414d5d82019-06-27 16:02:32 -06001320 for (uint64_t i = 0 ; i < size; i++)
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001321 printf("%c", m[i]);
Aaron Durbin46300aa2017-09-26 16:22:38 -06001322
1323 unmap_memory(&dump_mapping);
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001324}
1325
1326static void dump_cbmem_raw(unsigned int id)
1327{
Aaron Durbinf2a38222017-09-26 17:44:28 -06001328 const uint8_t *table;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001329 size_t offset;
1330 uint64_t base = 0;
1331 uint64_t size = 0;
1332
Aaron Durbin46300aa2017-09-26 16:22:38 -06001333 table = mapping_virt(&lbtable_mapping);
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001334
1335 if (table == NULL)
1336 return;
1337
1338 offset = 0;
1339
Aaron Durbin46300aa2017-09-26 16:22:38 -06001340 while (offset < mapping_size(&lbtable_mapping)) {
Aaron Durbinf2a38222017-09-26 17:44:28 -06001341 const struct lb_record *lbr;
Yidi Lin0811a642022-09-15 15:47:59 +08001342 struct lb_cbmem_entry lbe;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001343
Aaron Durbinf2a38222017-09-26 17:44:28 -06001344 lbr = (const void *)(table + offset);
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001345 offset += lbr->size;
1346
1347 if (lbr->tag != LB_TAG_CBMEM_ENTRY)
1348 continue;
1349
Yidi Lin0811a642022-09-15 15:47:59 +08001350 aligned_memcpy(&lbe, lbr, sizeof(lbe));
1351 if (lbe.id == id) {
1352 debug("found id for raw dump %0x", lbe.id);
1353 base = lbe.address;
1354 size = lbe.entry_size;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001355 break;
1356 }
1357 }
1358
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001359 if (!base)
1360 fprintf(stderr, "id %0x not found in cbtable\n", id);
1361 else
1362 rawdump(base, size);
1363}
1364
Aaron Durbin0dff57d2015-03-05 21:18:33 -06001365struct cbmem_id_to_name {
1366 uint32_t id;
1367 const char *name;
1368};
Vadim Bendebury8b143c52014-05-14 10:12:55 -07001369static const struct cbmem_id_to_name cbmem_ids[] = { CBMEM_ID_TO_NAME_TABLE };
Stefan Reinauerc0199072013-01-07 16:26:10 -08001370
Kyösti Mälkkieab5c122017-09-04 11:10:17 +03001371#define MAX_STAGEx 10
Jacob Garber79a2f472019-06-27 17:23:25 -06001372static void cbmem_print_entry(int n, uint32_t id, uint64_t base, uint64_t size)
Stefan Reinauera9c83612013-07-16 17:47:35 -07001373{
Stefan Reinauera9c83612013-07-16 17:47:35 -07001374 const char *name;
Kyösti Mälkkieab5c122017-09-04 11:10:17 +03001375 char stage_x[20];
Stefan Reinauera9c83612013-07-16 17:47:35 -07001376
1377 name = NULL;
Jacob Garber414d5d82019-06-27 16:02:32 -06001378 for (size_t i = 0; i < ARRAY_SIZE(cbmem_ids); i++) {
Stefan Reinauera9c83612013-07-16 17:47:35 -07001379 if (cbmem_ids[i].id == id) {
1380 name = cbmem_ids[i].name;
1381 break;
1382 }
Kyösti Mälkkieab5c122017-09-04 11:10:17 +03001383 if (id >= CBMEM_ID_STAGEx_META &&
1384 id < CBMEM_ID_STAGEx_META + MAX_STAGEx) {
1385 snprintf(stage_x, sizeof(stage_x), "STAGE%d META",
1386 (id - CBMEM_ID_STAGEx_META));
1387 name = stage_x;
1388 }
1389 if (id >= CBMEM_ID_STAGEx_CACHE &&
1390 id < CBMEM_ID_STAGEx_CACHE + MAX_STAGEx) {
1391 snprintf(stage_x, sizeof(stage_x), "STAGE%d $ ",
1392 (id - CBMEM_ID_STAGEx_CACHE));
1393 name = stage_x;
1394 }
Stefan Reinauera9c83612013-07-16 17:47:35 -07001395 }
1396
1397 printf("%2d. ", n);
1398 if (name == NULL)
Martin Roth90e4f3d2022-10-20 21:11:30 -06001399 name = "(unknown)";
1400 printf("%-20s %08x", name, id);
Stefan Reinauera9c83612013-07-16 17:47:35 -07001401 printf(" %08" PRIx64 " ", base);
Martin Roth90e4f3d2022-10-20 21:11:30 -06001402 printf(" %08" PRIx64 "\n", size);
Stefan Reinauera9c83612013-07-16 17:47:35 -07001403}
1404
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001405static void dump_cbmem_toc(void)
Stefan Reinauerc0199072013-01-07 16:26:10 -08001406{
Aaron Durbin09c0c112015-09-30 12:33:01 -05001407 int i;
Aaron Durbinf2a38222017-09-26 17:44:28 -06001408 const uint8_t *table;
Aaron Durbin09c0c112015-09-30 12:33:01 -05001409 size_t offset;
Stefan Reinauerc0199072013-01-07 16:26:10 -08001410
Aaron Durbin46300aa2017-09-26 16:22:38 -06001411 table = mapping_virt(&lbtable_mapping);
Aaron Durbin09c0c112015-09-30 12:33:01 -05001412
1413 if (table == NULL)
Stefan Reinauerc0199072013-01-07 16:26:10 -08001414 return;
Aaron Durbin09c0c112015-09-30 12:33:01 -05001415
1416 printf("CBMEM table of contents:\n");
Martin Roth90e4f3d2022-10-20 21:11:30 -06001417 printf(" %-20s %-8s %-8s %-8s\n", "NAME", "ID", "START",
1418 "LENGTH");
Aaron Durbin09c0c112015-09-30 12:33:01 -05001419
1420 i = 0;
1421 offset = 0;
1422
Aaron Durbin46300aa2017-09-26 16:22:38 -06001423 while (offset < mapping_size(&lbtable_mapping)) {
Aaron Durbinf2a38222017-09-26 17:44:28 -06001424 const struct lb_record *lbr;
Yidi Lin0811a642022-09-15 15:47:59 +08001425 struct lb_cbmem_entry lbe;
Aaron Durbin09c0c112015-09-30 12:33:01 -05001426
Aaron Durbinf2a38222017-09-26 17:44:28 -06001427 lbr = (const void *)(table + offset);
Aaron Durbin09c0c112015-09-30 12:33:01 -05001428 offset += lbr->size;
1429
1430 if (lbr->tag != LB_TAG_CBMEM_ENTRY)
1431 continue;
1432
Yidi Lin0811a642022-09-15 15:47:59 +08001433 aligned_memcpy(&lbe, lbr, sizeof(lbe));
1434 cbmem_print_entry(i, lbe.id, lbe.address, lbe.entry_size);
Aaron Durbin09c0c112015-09-30 12:33:01 -05001435 i++;
Stefan Reinauerc0199072013-01-07 16:26:10 -08001436 }
Stefan Reinauerc0199072013-01-07 16:26:10 -08001437}
Stefan Reinauer19f87562013-01-07 13:37:12 -08001438
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001439#define COVERAGE_MAGIC 0x584d4153
1440struct file {
1441 uint32_t magic;
1442 uint32_t next;
1443 uint32_t filename;
1444 uint32_t data;
1445 int offset;
1446 int len;
1447};
1448
1449static int mkpath(char *path, mode_t mode)
1450{
1451 assert (path && *path);
1452 char *p;
1453 for (p = strchr(path+1, '/'); p; p = strchr(p + 1, '/')) {
1454 *p = '\0';
1455 if (mkdir(path, mode) == -1) {
1456 if (errno != EEXIST) {
1457 *p = '/';
1458 return -1;
1459 }
1460 }
1461 *p = '/';
1462 }
1463 return 0;
1464}
1465
1466static void dump_coverage(void)
1467{
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001468 uint64_t start;
Aaron Durbin09c0c112015-09-30 12:33:01 -05001469 size_t size;
Aaron Durbinf2a38222017-09-26 17:44:28 -06001470 const void *coverage;
Aaron Durbin46300aa2017-09-26 16:22:38 -06001471 struct mapping coverage_mapping;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001472 unsigned long phys_offset;
1473#define phys_to_virt(x) ((void *)(unsigned long)(x) + phys_offset)
1474
Aaron Durbin09c0c112015-09-30 12:33:01 -05001475 if (find_cbmem_entry(CBMEM_ID_COVERAGE, &start, &size)) {
1476 fprintf(stderr, "No coverage information found\n");
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001477 return;
1478 }
1479
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001480 /* Map coverage area */
Aaron Durbin46300aa2017-09-26 16:22:38 -06001481 coverage = map_memory(&coverage_mapping, start, size);
1482 if (!coverage)
1483 die("Unable to map coverage area.\n");
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001484 phys_offset = (unsigned long)coverage - (unsigned long)start;
1485
1486 printf("Dumping coverage data...\n");
1487
1488 struct file *file = (struct file *)coverage;
1489 while (file && file->magic == COVERAGE_MAGIC) {
1490 FILE *f;
1491 char *filename;
1492
1493 debug(" -> %s\n", (char *)phys_to_virt(file->filename));
1494 filename = strdup((char *)phys_to_virt(file->filename));
1495 if (mkpath(filename, 0755) == -1) {
1496 perror("Directory for coverage data could "
1497 "not be created");
1498 exit(1);
1499 }
1500 f = fopen(filename, "wb");
1501 if (!f) {
1502 printf("Could not open %s: %s\n",
1503 filename, strerror(errno));
1504 exit(1);
1505 }
1506 if (fwrite((void *)phys_to_virt(file->data),
1507 file->len, 1, f) != 1) {
1508 printf("Could not write to %s: %s\n",
1509 filename, strerror(errno));
1510 exit(1);
1511 }
1512 fclose(f);
1513 free(filename);
1514
1515 if (file->next)
1516 file = (struct file *)phys_to_virt(file->next);
1517 else
1518 file = NULL;
1519 }
Aaron Durbin46300aa2017-09-26 16:22:38 -06001520 unmap_memory(&coverage_mapping);
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001521}
1522
1523static void print_version(void)
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001524{
1525 printf("cbmem v%s -- ", CBMEM_VERSION);
1526 printf("Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.\n\n");
1527 printf(
1528 "This program is free software: you can redistribute it and/or modify\n"
1529 "it under the terms of the GNU General Public License as published by\n"
1530 "the Free Software Foundation, version 2 of the License.\n\n"
1531 "This program is distributed in the hope that it will be useful,\n"
1532 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1533 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001534 "GNU General Public License for more details.\n\n");
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001535}
1536
Martin Roth8448ac42016-09-11 15:43:22 -06001537static void print_usage(const char *name, int exit_code)
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001538{
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001539 printf("usage: %s [-cCltTLxVvh?]\n", name);
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001540 printf("\n"
Stefan Reinauer19f87562013-01-07 13:37:12 -08001541 " -c | --console: print cbmem console\n"
Julius Wernerb7b64a92017-04-28 16:31:46 -07001542 " -1 | --oneboot: print cbmem console for last boot only\n"
Julius Werner8202fc42021-09-08 16:10:15 -07001543 " -2 | --2ndtolast: print cbmem console for the boot that came before the last one only\n"
Julius Wernerb8258bd2022-02-09 17:26:39 -08001544 " -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 -08001545 " -C | --coverage: dump coverage information\n"
Stefan Reinauerc0199072013-01-07 16:26:10 -08001546 " -l | --list: print cbmem table of contents\n"
Stefan Reinauera9c83612013-07-16 17:47:35 -07001547 " -x | --hexdump: print hexdump of cbmem area\n"
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001548 " -r | --rawdump ID: print rawdump of specific ID (in hex) of cbtable\n"
Stefan Reinauer19f87562013-01-07 13:37:12 -08001549 " -t | --timestamps: print timestamp information\n"
Aaron Durbinfbff3012015-08-30 22:00:12 -05001550 " -T | --parseable-timestamps: print parseable timestamps\n"
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001551 " -S | --stacked-timestamps: print stacked timestamps (e.g. for flame graph tools)\n"
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001552 " -a | --add-timestamp ID: append timestamp with ID\n"
Sergii Dmytruk2710df72022-11-10 00:40:51 +02001553 " -L | --tcpa-log print TPM log\n"
Stefan Reinauer19f87562013-01-07 13:37:12 -08001554 " -V | --verbose: verbose (debugging) output\n"
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001555 " -v | --version: print the version\n"
1556 " -h | --help: print this help\n"
1557 "\n");
Martin Roth8448ac42016-09-11 15:43:22 -06001558 exit(exit_code);
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001559}
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001560
Adam Kallai66c22502018-11-30 11:31:50 +01001561#if defined(__arm__) || defined(__aarch64__)
Julius Werner337de4c2014-06-16 23:02:03 -07001562static void dt_update_cells(const char *name, int *addr_cells_ptr,
1563 int *size_cells_ptr)
1564{
1565 if (*addr_cells_ptr >= 0 && *size_cells_ptr >= 0)
1566 return;
1567
1568 int buffer;
1569 size_t nlen = strlen(name);
1570 char *prop = alloca(nlen + sizeof("/#address-cells"));
1571 strcpy(prop, name);
1572
1573 if (*addr_cells_ptr < 0) {
1574 strcpy(prop + nlen, "/#address-cells");
1575 int fd = open(prop, O_RDONLY);
1576 if (fd < 0 && errno != ENOENT) {
1577 perror(prop);
1578 } else if (fd >= 0) {
1579 if (read(fd, &buffer, sizeof(int)) < 0)
1580 perror(prop);
1581 else
1582 *addr_cells_ptr = ntohl(buffer);
1583 close(fd);
1584 }
1585 }
1586
1587 if (*size_cells_ptr < 0) {
1588 strcpy(prop + nlen, "/#size-cells");
1589 int fd = open(prop, O_RDONLY);
1590 if (fd < 0 && errno != ENOENT) {
1591 perror(prop);
1592 } else if (fd >= 0) {
1593 if (read(fd, &buffer, sizeof(int)) < 0)
1594 perror(prop);
1595 else
1596 *size_cells_ptr = ntohl(buffer);
1597 close(fd);
1598 }
1599 }
1600}
1601
1602static char *dt_find_compat(const char *parent, const char *compat,
1603 int *addr_cells_ptr, int *size_cells_ptr)
1604{
1605 char *ret = NULL;
1606 struct dirent *entry;
1607 DIR *dir;
1608
1609 if (!(dir = opendir(parent))) {
1610 perror(parent);
1611 return NULL;
1612 }
1613
1614 /* Loop through all files in the directory (DT node). */
1615 while ((entry = readdir(dir))) {
1616 /* We only care about compatible props or subnodes. */
1617 if (entry->d_name[0] == '.' || !((entry->d_type & DT_DIR) ||
1618 !strcmp(entry->d_name, "compatible")))
1619 continue;
1620
1621 /* Assemble the file name (on the stack, for speed). */
1622 size_t plen = strlen(parent);
1623 char *name = alloca(plen + strlen(entry->d_name) + 2);
1624
1625 strcpy(name, parent);
1626 name[plen] = '/';
1627 strcpy(name + plen + 1, entry->d_name);
1628
1629 /* If it's a subnode, recurse. */
1630 if (entry->d_type & DT_DIR) {
1631 ret = dt_find_compat(name, compat, addr_cells_ptr,
1632 size_cells_ptr);
1633
1634 /* There is only one matching node to find, abort. */
1635 if (ret) {
1636 /* Gather cells values on the way up. */
1637 dt_update_cells(parent, addr_cells_ptr,
1638 size_cells_ptr);
1639 break;
1640 }
1641 continue;
1642 }
1643
1644 /* If it's a compatible string, see if it's the right one. */
1645 int fd = open(name, O_RDONLY);
1646 int clen = strlen(compat);
1647 char *buffer = alloca(clen + 1);
1648
1649 if (fd < 0) {
1650 perror(name);
1651 continue;
1652 }
1653
1654 if (read(fd, buffer, clen + 1) < 0) {
1655 perror(name);
1656 close(fd);
1657 continue;
1658 }
1659 close(fd);
1660
1661 if (!strcmp(compat, buffer)) {
1662 /* Initialize these to "unset" for the way up. */
1663 *addr_cells_ptr = *size_cells_ptr = -1;
1664
1665 /* Can't leave string on the stack or we'll lose it! */
1666 ret = strdup(parent);
1667 break;
1668 }
1669 }
1670
1671 closedir(dir);
1672 return ret;
1673}
Adam Kallai66c22502018-11-30 11:31:50 +01001674#endif /* defined(__arm__) || defined(__aarch64__) */
Julius Werner337de4c2014-06-16 23:02:03 -07001675
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001676int main(int argc, char** argv)
1677{
Stefan Reinauer19f87562013-01-07 13:37:12 -08001678 int print_defaults = 1;
1679 int print_console = 0;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001680 int print_coverage = 0;
Stefan Reinauerc0199072013-01-07 16:26:10 -08001681 int print_list = 0;
Stefan Reinauera9c83612013-07-16 17:47:35 -07001682 int print_hexdump = 0;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001683 int print_rawdump = 0;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001684 int print_tcpa_log = 0;
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001685 enum timestamps_print_type timestamp_type = TIMESTAMPS_PRINT_NONE;
Julius Werner8202fc42021-09-08 16:10:15 -07001686 enum console_print_type console_type = CONSOLE_PRINT_FULL;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001687 unsigned int rawdump_id = 0;
Julius Wernerb8258bd2022-02-09 17:26:39 -08001688 int max_loglevel = BIOS_NEVER;
1689 int print_unknown_logs = 1;
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001690 uint32_t timestamp_id = 0;
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001691
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001692 int opt, option_index = 0;
1693 static struct option long_options[] = {
Stefan Reinauer19f87562013-01-07 13:37:12 -08001694 {"console", 0, 0, 'c'},
Julius Wernerb7b64a92017-04-28 16:31:46 -07001695 {"oneboot", 0, 0, '1'},
Julius Werner8202fc42021-09-08 16:10:15 -07001696 {"2ndtolast", 0, 0, '2'},
Julius Wernerb8258bd2022-02-09 17:26:39 -08001697 {"loglevel", required_argument, 0, 'B'},
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001698 {"coverage", 0, 0, 'C'},
Stefan Reinauerc0199072013-01-07 16:26:10 -08001699 {"list", 0, 0, 'l'},
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001700 {"tcpa-log", 0, 0, 'L'},
Stefan Reinauer19f87562013-01-07 13:37:12 -08001701 {"timestamps", 0, 0, 't'},
Aaron Durbinfbff3012015-08-30 22:00:12 -05001702 {"parseable-timestamps", 0, 0, 'T'},
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001703 {"stacked-timestamps", 0, 0, 'S'},
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001704 {"add-timestamp", required_argument, 0, 'a'},
Stefan Reinauera9c83612013-07-16 17:47:35 -07001705 {"hexdump", 0, 0, 'x'},
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001706 {"rawdump", required_argument, 0, 'r'},
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001707 {"verbose", 0, 0, 'V'},
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001708 {"version", 0, 0, 'v'},
1709 {"help", 0, 0, 'h'},
1710 {0, 0, 0, 0}
1711 };
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001712 while ((opt = getopt_long(argc, argv, "c12B:CltTSa:LxVvh?r:",
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001713 long_options, &option_index)) != EOF) {
1714 switch (opt) {
Stefan Reinauer19f87562013-01-07 13:37:12 -08001715 case 'c':
1716 print_console = 1;
1717 print_defaults = 0;
1718 break;
Julius Wernerb7b64a92017-04-28 16:31:46 -07001719 case '1':
1720 print_console = 1;
Julius Werner8202fc42021-09-08 16:10:15 -07001721 console_type = CONSOLE_PRINT_LAST;
1722 print_defaults = 0;
1723 break;
1724 case '2':
1725 print_console = 1;
1726 console_type = CONSOLE_PRINT_PREVIOUS;
Julius Wernerb7b64a92017-04-28 16:31:46 -07001727 print_defaults = 0;
1728 break;
Julius Wernerb8258bd2022-02-09 17:26:39 -08001729 case 'B':
1730 max_loglevel = parse_loglevel(optarg, &print_unknown_logs);
1731 break;
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001732 case 'C':
1733 print_coverage = 1;
1734 print_defaults = 0;
1735 break;
Stefan Reinauerc0199072013-01-07 16:26:10 -08001736 case 'l':
1737 print_list = 1;
1738 print_defaults = 0;
1739 break;
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001740 case 'L':
1741 print_tcpa_log = 1;
1742 print_defaults = 0;
1743 break;
Stefan Reinauera9c83612013-07-16 17:47:35 -07001744 case 'x':
1745 print_hexdump = 1;
1746 print_defaults = 0;
1747 break;
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001748 case 'r':
1749 print_rawdump = 1;
1750 print_defaults = 0;
1751 rawdump_id = strtoul(optarg, NULL, 16);
1752 break;
Stefan Reinauer19f87562013-01-07 13:37:12 -08001753 case 't':
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001754 timestamp_type = TIMESTAMPS_PRINT_NORMAL;
Stefan Reinauer19f87562013-01-07 13:37:12 -08001755 print_defaults = 0;
1756 break;
Aaron Durbinfbff3012015-08-30 22:00:12 -05001757 case 'T':
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001758 timestamp_type = TIMESTAMPS_PRINT_MACHINE_READABLE;
1759 print_defaults = 0;
1760 break;
1761 case 'S':
1762 timestamp_type = TIMESTAMPS_PRINT_STACKED;
Aaron Durbinfbff3012015-08-30 22:00:12 -05001763 print_defaults = 0;
1764 break;
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001765 case 'a':
1766 print_defaults = 0;
1767 timestamp_id = timestamp_enum_name_to_id(optarg);
1768 /* Parse numeric value if name is unknown */
1769 if (timestamp_id == 0)
1770 timestamp_id = strtoul(optarg, NULL, 0);
1771 break;
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001772 case 'V':
1773 verbose = 1;
1774 break;
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001775 case 'v':
1776 print_version();
1777 exit(0);
1778 break;
1779 case 'h':
Martin Roth8448ac42016-09-11 15:43:22 -06001780 print_usage(argv[0], 0);
1781 break;
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001782 case '?':
1783 default:
Martin Roth8448ac42016-09-11 15:43:22 -06001784 print_usage(argv[0], 1);
Stefan Reinauer1e0e5562013-01-02 15:43:56 -08001785 break;
1786 }
1787 }
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001788
Arthur Heymans8cd17ea2018-08-01 17:21:32 +02001789 if (optind < argc) {
1790 fprintf(stderr, "Error: Extra parameter found.\n");
1791 print_usage(argv[0], 1);
1792 }
1793
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001794 mem_fd = open("/dev/mem", timestamp_id ? O_RDWR : O_RDONLY, 0);
Julius Werner337de4c2014-06-16 23:02:03 -07001795 if (mem_fd < 0) {
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001796 fprintf(stderr, "Failed to gain memory access: %s\n",
1797 strerror(errno));
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001798 return 1;
1799 }
1800
Adam Kallai66c22502018-11-30 11:31:50 +01001801#if defined(__arm__) || defined(__aarch64__)
Julius Werner337de4c2014-06-16 23:02:03 -07001802 int addr_cells, size_cells;
1803 char *coreboot_node = dt_find_compat("/proc/device-tree", "coreboot",
1804 &addr_cells, &size_cells);
Stefan Reinauer7f681502013-06-19 15:39:09 -07001805
Julius Werner337de4c2014-06-16 23:02:03 -07001806 if (!coreboot_node) {
1807 fprintf(stderr, "Could not find 'coreboot' compatible node!\n");
Stefan Reinauer7f681502013-06-19 15:39:09 -07001808 return 1;
1809 }
1810
Julius Werner337de4c2014-06-16 23:02:03 -07001811 if (addr_cells < 0) {
1812 fprintf(stderr, "Warning: no #address-cells node in tree!\n");
1813 addr_cells = 1;
1814 }
1815
1816 int nlen = strlen(coreboot_node);
1817 char *reg = alloca(nlen + sizeof("/reg"));
1818
1819 strcpy(reg, coreboot_node);
1820 strcpy(reg + nlen, "/reg");
1821 free(coreboot_node);
1822
1823 int fd = open(reg, O_RDONLY);
1824 if (fd < 0) {
1825 perror(reg);
Stefan Reinauer7f681502013-06-19 15:39:09 -07001826 return 1;
1827 }
Stefan Reinauer7f681502013-06-19 15:39:09 -07001828
Julius Werner337de4c2014-06-16 23:02:03 -07001829 int i;
Aaron Durbinb58f9e32014-10-07 14:56:35 -05001830 size_t size_to_read = addr_cells * 4 + size_cells * 4;
1831 u8 *dtbuffer = alloca(size_to_read);
1832 if (read(fd, dtbuffer, size_to_read) < 0) {
Julius Werner337de4c2014-06-16 23:02:03 -07001833 perror(reg);
1834 return 1;
1835 }
1836 close(fd);
1837
1838 /* No variable-length byte swap function anywhere in C... how sad. */
1839 u64 baseaddr = 0;
1840 for (i = 0; i < addr_cells * 4; i++) {
1841 baseaddr <<= 8;
Aaron Durbinb58f9e32014-10-07 14:56:35 -05001842 baseaddr |= *dtbuffer;
1843 dtbuffer++;
1844 }
1845 u64 cb_table_size = 0;
1846 for (i = 0; i < size_cells * 4; i++) {
1847 cb_table_size <<= 8;
1848 cb_table_size |= *dtbuffer;
1849 dtbuffer++;
Julius Werner337de4c2014-06-16 23:02:03 -07001850 }
1851
Aaron Durbin46300aa2017-09-26 16:22:38 -06001852 parse_cbtable(baseaddr, cb_table_size);
Stefan Reinauer7f681502013-06-19 15:39:09 -07001853#else
Aaron Durbin46300aa2017-09-26 16:22:38 -06001854 unsigned long long possible_base_addresses[] = { 0, 0xf0000 };
Stefan Reinauer7f681502013-06-19 15:39:09 -07001855
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001856 /* Find and parse coreboot table */
Jacob Garber414d5d82019-06-27 16:02:32 -06001857 for (size_t j = 0; j < ARRAY_SIZE(possible_base_addresses); j++) {
Aaron Durbin46300aa2017-09-26 16:22:38 -06001858 if (!parse_cbtable(possible_base_addresses[j], 0))
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001859 break;
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001860 }
Stefan Reinauer7f681502013-06-19 15:39:09 -07001861#endif
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001862
Aaron Durbin46300aa2017-09-26 16:22:38 -06001863 if (mapping_virt(&lbtable_mapping) == NULL)
1864 die("Table not found.\n");
1865
Stefan Reinauer19f87562013-01-07 13:37:12 -08001866 if (print_console)
Julius Wernerb8258bd2022-02-09 17:26:39 -08001867 dump_console(console_type, max_loglevel, print_unknown_logs);
Stefan Reinauer19f87562013-01-07 13:37:12 -08001868
Stefan Reinauerd37ab452012-12-18 16:23:28 -08001869 if (print_coverage)
1870 dump_coverage();
1871
Stefan Reinauerc0199072013-01-07 16:26:10 -08001872 if (print_list)
1873 dump_cbmem_toc();
1874
Stefan Reinauera9c83612013-07-16 17:47:35 -07001875 if (print_hexdump)
1876 dump_cbmem_hex();
1877
Pratik Prajapatic29e57d2015-09-03 12:58:44 -07001878 if (print_rawdump)
1879 dump_cbmem_raw(rawdump_id);
1880
Mattias Nisslerecc165b2022-02-08 23:01:50 +00001881 if (timestamp_id)
1882 timestamp_add_now(timestamp_id);
1883
Jakub Czapiga48f6c2b2022-02-28 16:23:02 +01001884 if (print_defaults)
1885 timestamp_type = TIMESTAMPS_PRINT_NORMAL;
1886
1887 if (timestamp_type != TIMESTAMPS_PRINT_NONE)
1888 dump_timestamps(timestamp_type);
Stefan Reinauer05cbce62013-01-03 14:30:33 -08001889
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001890 if (print_tcpa_log)
Sergii Dmytruk6da62682022-10-23 00:55:03 +03001891 dump_tpm_log();
Philipp Deppenwiesefa1f6ff2018-05-13 12:42:42 +02001892
Aaron Durbin46300aa2017-09-26 16:22:38 -06001893 unmap_memory(&lbtable_mapping);
1894
Julius Werner337de4c2014-06-16 23:02:03 -07001895 close(mem_fd);
Vadim Bendebury6d18fd02012-09-27 19:24:07 -07001896 return 0;
1897}