1 /* SPDX-License-Identifier: GPL-2.0-only */
14 #include <arpa/inet.h>
15 #include <sys/types.h>
21 #include <commonlib/bsd/cbmem_id.h>
22 #include <commonlib/bsd/ipchksum.h>
23 #include <commonlib/bsd/tpm_log_defs.h>
24 #include <commonlib/loglevel.h>
25 #include <commonlib/timestamp_serialized.h>
26 #include <commonlib/tpm_log_serialized.h>
27 #include <commonlib/coreboot_tables.h>
30 #include <sys/param.h>
31 #include <sys/sysctl.h>
34 #if defined(__i386__) || defined(__x86_64__)
35 #include <x86intrin.h>
43 /* Return < 0 on error, 0 on success. */
44 static int parse_cbtable(u64 address
, size_t table_size
);
50 unsigned long long phys
;
54 #define CBMEM_VERSION "1.1"
57 static int verbose
= 0;
58 #define debug(x...) if(verbose) printf(x)
60 /* File handle used to access /dev/mem */
62 static struct mapping lbtable_mapping
;
64 /* TSC frequency from the LB_TAG_TSC_INFO record. 0 if not present. */
65 static uint32_t tsc_freq_khz
= 0;
67 static void die(const char *msg
)
74 static unsigned long long system_page_size(void)
76 static unsigned long long page_size
;
79 page_size
= getpagesize();
84 static inline size_t size_to_mib(size_t sz
)
89 /* Return mapping of physical address requested. */
90 static void *mapping_virt(const struct mapping
*mapping
)
92 char *v
= mapping
->virt
;
97 return v
+ mapping
->offset
;
100 /* Returns virtual address on success, NULL on error. mapping is filled in. */
101 static void *map_memory_with_prot(struct mapping
*mapping
,
102 unsigned long long phys
, size_t sz
, int prot
)
105 unsigned long long page_size
;
107 page_size
= system_page_size();
109 mapping
->virt
= NULL
;
110 mapping
->offset
= phys
% page_size
;
111 mapping
->virt_size
= sz
+ mapping
->offset
;
113 mapping
->phys
= phys
;
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
);
119 debug("Mapping %zuMB of physical memory at 0x%llx (requested 0x%llx).\n",
120 size_to_mib(mapping
->virt_size
), phys
- mapping
->offset
,
124 v
= mmap(NULL
, mapping
->virt_size
, prot
, MAP_SHARED
, mem_fd
,
125 phys
- mapping
->offset
);
127 if (v
== MAP_FAILED
) {
128 debug("Mapping failed %zuB of physical memory at 0x%llx.\n",
129 mapping
->virt_size
, phys
- mapping
->offset
);
135 if (mapping
->offset
!= 0)
136 debug(" ... padding virtual address with 0x%zx bytes.\n",
139 return mapping_virt(mapping
);
142 /* Convenience helper for the common case of read-only mappings. */
143 static const void *map_memory(struct mapping
*mapping
, unsigned long long phys
,
146 return map_memory_with_prot(mapping
, phys
, sz
, PROT_READ
);
150 /* Returns 0 on success, < 0 on error. mapping is cleared if successful. */
151 static int unmap_memory(struct mapping
*mapping
)
153 if (mapping
->virt
== NULL
)
156 munmap(mapping
->virt
, mapping
->virt_size
);
157 mapping
->virt
= NULL
;
159 mapping
->virt_size
= 0;
164 /* Return size of physical address mapping requested. */
165 static size_t mapping_size(const struct mapping
*mapping
)
167 if (mapping
->virt
== NULL
)
170 return mapping
->size
;
174 * 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).
179 static void *aligned_memcpy(void *dest
, const void *src
, size_t n
)
182 const volatile u8
*s
= src
; /* volatile to prevent optimization */
184 while ((uintptr_t)s
& (sizeof(size_t) - 1)) {
190 while (n
>= sizeof(size_t)) {
191 *(size_t *)d
= *(const volatile size_t *)s
;
203 /* Find the first cbmem entry filling in the details. */
204 static int find_cbmem_entry(uint32_t id
, uint64_t *addr
, size_t *size
)
206 const uint8_t *table
;
210 table
= mapping_virt(&lbtable_mapping
);
217 while (offset
< mapping_size(&lbtable_mapping
)) {
218 const struct lb_record
*lbr
;
219 struct lb_cbmem_entry lbe
;
221 lbr
= (const void *)(table
+ offset
);
224 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
227 aligned_memcpy(&lbe
, lbr
, sizeof(lbe
));
232 *size
= lbe
.entry_size
;
241 * 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
245 * Returns pointer to a memory buffer containing the timestamp table or zero if
249 static struct lb_cbmem_ref timestamps
;
250 static struct lb_cbmem_ref console
;
251 static struct lb_cbmem_ref tpm_cb_log
;
252 static struct lb_memory_range cbmem
;
254 /* 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.
261 static struct lb_cbmem_ref
parse_cbmem_ref(const struct lb_cbmem_ref
*cbmem_ref
)
263 struct lb_cbmem_ref ret
;
265 aligned_memcpy(&ret
, cbmem_ref
, sizeof(ret
));
267 if (cbmem_ref
->size
< sizeof(*cbmem_ref
))
268 ret
.cbmem_addr
= (uint32_t)ret
.cbmem_addr
;
270 debug(" cbmem_addr = %" PRIx64
"\n", ret
.cbmem_addr
);
275 static void parse_memory_tags(const struct lb_memory
*mem
)
280 /* Peel off the header size and calculate the number of entries. */
281 num_entries
= (mem
->size
- sizeof(*mem
)) / sizeof(mem
->map
[0]);
283 for (i
= 0; i
< num_entries
; i
++) {
284 if (mem
->map
[i
].type
!= LB_MEM_TABLE
)
286 debug(" LB_MEM_TABLE found.\n");
287 /* The last one found is CBMEM */
288 aligned_memcpy(&cbmem
, &mem
->map
[i
], sizeof(cbmem
));
292 /* Return < 0 on error, 0 on success, 1 if forwarding table entry found. */
293 static int parse_cbtable_entries(const struct mapping
*table_mapping
)
296 const struct lb_record
*lbr_p
;
297 size_t table_size
= mapping_size(table_mapping
);
298 const void *lbtable
= mapping_virt(table_mapping
);
299 int forwarding_table_found
= 0;
301 for (i
= 0; i
< table_size
; i
+= lbr_p
->size
) {
303 debug(" coreboot table entry 0x%02x\n", lbr_p
->tag
);
304 switch (lbr_p
->tag
) {
306 debug(" Found memory map.\n");
307 parse_memory_tags(lbtable
+ i
);
309 case LB_TAG_TIMESTAMPS
: {
310 debug(" Found timestamp table.\n");
312 parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
315 case LB_TAG_CBMEM_CONSOLE
: {
316 debug(" Found cbmem console.\n");
317 console
= parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
320 case LB_TAG_TPM_CB_LOG
: {
321 debug(" Found TPM CB log table.\n");
323 parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
326 case LB_TAG_TSC_INFO
:
327 debug(" Found TSC info.\n");
328 tsc_freq_khz
= ((struct lb_tsc_info
*)lbr_p
)->freq_khz
;
330 case LB_TAG_FORWARD
: {
333 * This is a forwarding entry - repeat the
334 * search at the new address.
336 struct lb_forward lbf_p
=
337 *(const struct lb_forward
*)lbr_p
;
338 debug(" Found forwarding entry.\n");
339 ret
= parse_cbtable(lbf_p
.forward
, 0);
341 /* Assume the forwarding entry is valid. If this fails
342 * then there's a total failure. */
345 forwarding_table_found
= 1;
352 return forwarding_table_found
;
355 /* Return < 0 on error, 0 on success. */
356 static int parse_cbtable(u64 address
, size_t table_size
)
359 struct mapping header_mapping
;
363 req_size
= table_size
;
364 /* Default to 4 KiB search space. */
368 debug("Looking for coreboot table at %" PRIx64
" %zd bytes.\n",
371 buf
= map_memory(&header_mapping
, address
, req_size
);
376 /* look at every 16 bytes */
377 for (i
= 0; i
<= req_size
- sizeof(struct lb_header
); i
+= 16) {
379 const struct lb_header
*lbh
;
380 struct mapping table_mapping
;
383 if (memcmp(lbh
->signature
, "LBIO", sizeof(lbh
->signature
)) ||
384 !lbh
->header_bytes
||
385 ipchksum(lbh
, sizeof(*lbh
))) {
389 /* Map in the whole table to parse. */
390 if (!map_memory(&table_mapping
, address
+ i
+ lbh
->header_bytes
,
392 debug("Couldn't map in table\n");
396 if (ipchksum(mapping_virt(&table_mapping
), lbh
->table_bytes
) !=
397 lbh
->table_checksum
) {
398 debug("Signature found, but wrong checksum.\n");
399 unmap_memory(&table_mapping
);
405 ret
= parse_cbtable_entries(&table_mapping
);
407 /* Table parsing failed. */
409 unmap_memory(&table_mapping
);
413 /* Succeeded in parsing the table. Header not needed anymore. */
414 unmap_memory(&header_mapping
);
417 * Table parsing succeeded. If forwarding table not found update
418 * coreboot table mapping for future use.
421 lbtable_mapping
= table_mapping
;
423 unmap_memory(&table_mapping
);
428 unmap_memory(&header_mapping
);
433 #if defined(linux) && (defined(__i386__) || defined(__x86_64__))
435 * read CPU frequency from a sysfs file, return an frequency in Megahertz as
436 * an int or exit on any error.
438 static unsigned long arch_tick_frequency(void)
446 const char* freq_file
=
447 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
449 cpuf
= fopen(freq_file
, "r");
451 fprintf(stderr
, "Could not open %s: %s\n",
452 freq_file
, strerror(errno
));
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",
464 rv
= strtoull(freqs
, &endp
, 10);
466 if (*endp
== '\0' || *endp
== '\n')
467 /* cpuinfo_max_freq is in kHz. Convert it to MHz. */
469 fprintf(stderr
, "Wrong formatted value ^%s^ read from %s\n",
473 #elif defined(__OpenBSD__) && (defined(__i386__) || defined(__x86_64__))
474 static unsigned long arch_tick_frequency(void)
476 int mib
[2] = { CTL_HW
, HW_CPUSPEED
};
477 static int value
= 0;
478 size_t value_len
= sizeof(value
);
480 /* Return 1 MHz when sysctl fails. */
481 if ((value
== 0) && (sysctl(mib
, 2, &value
, &value_len
, NULL
, 0) == -1))
487 static unsigned long arch_tick_frequency(void)
494 static unsigned long tick_freq_mhz
;
496 static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz
)
498 tick_freq_mhz
= table_tick_freq_mhz
;
500 /* Honor table frequency if present. */
502 tick_freq_mhz
= arch_tick_frequency();
504 if (!tick_freq_mhz
) {
505 fprintf(stderr
, "Cannot determine timestamp tick frequency.\n");
509 debug("Timestamp tick frequency: %ld MHz\n", tick_freq_mhz
);
512 static u64
arch_convert_raw_ts_entry(u64 ts
)
514 return ts
/ tick_freq_mhz
;
518 * Print an integer in 'normalized' form - with commas separating every three
521 static void print_norm(u64 v
)
524 /* print the higher order sections first */
525 print_norm(v
/ 1000);
526 printf(",%3.3u", (u32
)(v
% 1000));
528 printf("%u", (u32
)(v
% 1000));
532 static uint64_t timestamp_get(uint64_t table_tick_freq_mhz
)
534 #if defined(__i386__) || defined(__x86_64__)
535 uint64_t tsc
= __rdtsc();
537 /* No tick frequency specified means raw TSC values. */
538 if (!table_tick_freq_mhz
)
542 return tsc
* table_tick_freq_mhz
* 1000 / tsc_freq_khz
;
544 (void)table_tick_freq_mhz
;
546 die("Don't know how to obtain timestamps on this platform.\n");
550 static const char *timestamp_name(uint32_t id
)
552 for (size_t i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++) {
553 if (timestamp_ids
[i
].id
== id
)
554 return timestamp_ids
[i
].name
;
559 static uint32_t timestamp_enum_name_to_id(const char *name
)
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
;
568 static uint64_t timestamp_print_parseable_entry(uint32_t id
, uint64_t stamp
,
574 name
= timestamp_name(id
);
576 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
578 /* ID<tab>absolute time<tab>relative time<tab>description */
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
);
587 static uint64_t timestamp_print_entry(uint32_t id
, uint64_t stamp
, uint64_t prev_stamp
)
592 name
= timestamp_name(id
);
595 printf("%-50s", name
);
596 print_norm(arch_convert_raw_ts_entry(stamp
));
597 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
600 print_norm(step_time
);
608 static int compare_timestamp_entries(const void *a
, const void *b
)
610 const struct timestamp_entry
*tse_a
= (struct timestamp_entry
*)a
;
611 const struct timestamp_entry
*tse_b
= (struct timestamp_entry
*)b
;
613 if (tse_a
->entry_stamp
> tse_b
->entry_stamp
)
615 else if (tse_a
->entry_stamp
< tse_b
->entry_stamp
)
621 static int find_matching_end(struct timestamp_table
*sorted_tst_p
, uint32_t start
, uint32_t end
)
623 uint32_t id
= sorted_tst_p
->entries
[start
].entry_id
;
624 uint32_t possible_match
= 0;
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
;
633 /* No match found or timestamp not defined in IDs table */
637 for (uint32_t i
= start
+ 1; i
< end
; i
++)
638 if (sorted_tst_p
->entries
[i
].entry_id
== possible_match
)
644 static const char *get_timestamp_name(const uint32_t id
)
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
;
653 struct ts_range_stack
{
655 const char *end_name
;
659 static void print_with_path(struct ts_range_stack
*range_stack
, const int stacklvl
,
660 const uint64_t stamp
, const char *last_part
)
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
)
668 printf("%s", last_part
);
669 printf(" %llu\n", (long long)arch_convert_raw_ts_entry(stamp
));
672 enum timestamps_print_type
{
673 TIMESTAMPS_PRINT_NONE
,
674 TIMESTAMPS_PRINT_NORMAL
,
675 TIMESTAMPS_PRINT_MACHINE_READABLE
,
676 TIMESTAMPS_PRINT_STACKED
,
679 /* dump the timestamp table */
680 static void dump_timestamps(enum timestamps_print_type output_type
)
682 const struct timestamp_table
*tst_p
;
683 struct timestamp_table
*sorted_tst_p
;
685 uint64_t prev_stamp
= 0;
686 uint64_t total_time
= 0;
687 struct mapping timestamp_mapping
;
689 if (timestamps
.tag
!= LB_TAG_TIMESTAMPS
) {
690 fprintf(stderr
, "No timestamps found in coreboot table.\n");
694 size
= sizeof(*tst_p
);
695 tst_p
= map_memory(×tamp_mapping
, timestamps
.cbmem_addr
, size
);
697 die("Unable to map timestamp header\n");
699 timestamp_set_tick_freq(tst_p
->tick_freq_mhz
);
701 if (output_type
== TIMESTAMPS_PRINT_NORMAL
)
702 printf("%d entries total:\n\n", tst_p
->num_entries
);
703 size
+= tst_p
->num_entries
* sizeof(tst_p
->entries
[0]);
705 unmap_memory(×tamp_mapping
);
707 tst_p
= map_memory(×tamp_mapping
, timestamps
.cbmem_addr
, size
);
709 die("Unable to map full timestamp table\n");
711 sorted_tst_p
= malloc(size
+ sizeof(struct timestamp_entry
));
713 die("Failed to allocate memory");
714 aligned_memcpy(sorted_tst_p
, tst_p
, size
);
717 * Insert a timestamp to represent the base time (start of coreboot),
718 * in case we have to rebase for negative timestamps below.
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;
724 qsort(&sorted_tst_p
->entries
[0], sorted_tst_p
->num_entries
,
725 sizeof(struct timestamp_entry
), compare_timestamp_entries
);
728 * If there are negative timestamp entries, rebase all of the
729 * timestamps to the lowest one in the list.
731 if (sorted_tst_p
->entries
[0].entry_stamp
< 0) {
732 sorted_tst_p
->base_time
= -sorted_tst_p
->entries
[0].entry_stamp
;
735 prev_stamp
= tst_p
->base_time
;
738 struct ts_range_stack range_stack
[20];
739 range_stack
[0].end
= sorted_tst_p
->num_entries
;
742 for (uint32_t i
= 0; i
< sorted_tst_p
->num_entries
; i
++) {
744 const struct timestamp_entry
*tse
= &sorted_tst_p
->entries
[i
];
746 /* Make all timestamps absolute. */
747 stamp
= tse
->entry_stamp
+ sorted_tst_p
->base_time
;
748 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
) {
763 find_matching_end(sorted_tst_p
, i
, range_stack
[stacklvl
].end
);
765 const uint64_t match_stamp
=
766 sorted_tst_p
->entries
[match
].entry_stamp
767 + sorted_tst_p
->base_time
;
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
,
776 } else if (!end_of_range
) {
777 print_with_path(range_stack
, stacklvl
, stamp
- prev_stamp
,
778 get_timestamp_name(tse
->entry_id
));
780 /* else: No match && end_of_range == true */
785 if (output_type
== TIMESTAMPS_PRINT_NORMAL
) {
786 printf("\nTotal Time: ");
787 print_norm(total_time
);
791 unmap_memory(×tamp_mapping
);
795 /* add a timestamp entry */
796 static void timestamp_add_now(uint32_t timestamp_id
)
798 struct timestamp_table
*tst_p
;
799 struct mapping timestamp_mapping
;
801 if (timestamps
.tag
!= LB_TAG_TIMESTAMPS
) {
802 die("No timestamps found in coreboot table.\n");
805 tst_p
= map_memory_with_prot(×tamp_mapping
, timestamps
.cbmem_addr
,
806 timestamps
.size
, PROT_READ
| PROT_WRITE
);
808 die("Unable to map timestamp table\n");
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.
814 if (tst_p
->num_entries
>= tst_p
->max_entries
) {
815 die("Not enough space to add timestamp.\n");
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;
824 unmap_memory(×tamp_mapping
);
827 static bool can_print(const uint8_t *data
, size_t len
)
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
++) {
843 static void print_hex_string(const uint8_t *hex
, size_t len
)
846 for (i
= 0; i
< len
; i
++)
847 printf("%02x", hex
[i
]);
850 static void print_hex_line(const uint8_t *hex
, size_t len
)
852 print_hex_string(hex
, len
);
856 static void print_event_type(uint32_t event_type
)
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
);
862 printf("%s", tpm_event_types
[event_type
]);
865 static void parse_tpm12_log(const struct tcpa_spec_entry
*spec_log
)
867 const uint8_t zero_block
[sizeof(struct tcpa_spec_entry
)] = {0};
870 uint32_t counter
= 0;
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");
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
))) {
884 struct tcpa_log_entry
*log_entry
= (void *)current
;
885 uint32_t event_type
= le32toh(log_entry
->event_type
);
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
);
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
);
898 printf("\tEvent data: ");
899 if (can_print(log_entry
->event
, len
))
900 printf("%.*s\n", len
, log_entry
->event
);
902 print_hex_line(log_entry
->event
, len
);
904 printf("\tEvent data not provided\n");
909 static uint32_t print_tpm2_digests(struct tcg_pcr_event2_header
*log_entry
)
912 uintptr_t current
= (uintptr_t)log_entry
->digests
;
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
)) {
918 printf("\t\t SHA1: ");
919 print_hex_line(hash
->digest
.sha1
, SHA1_DIGEST_SIZE
);
920 current
+= sizeof(hash
->hashAlg
) + SHA1_DIGEST_SIZE
;
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
;
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
;
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
;
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
;
943 die("Unknown hash algorithm\n");
947 return current
- (uintptr_t)&log_entry
->digest_count
;
950 static void parse_tpm2_log(const struct tcg_efi_spec_id_event
*tpm2_log
)
952 const uint8_t zero_block
[12] = {0}; /* Only PCR index, event type and digest count */
955 uint32_t counter
= 0;
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");
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
;
971 while (memcmp((const void *)current
, (const void *)zero_block
, sizeof(zero_block
))) {
973 struct tcg_pcr_event2_header
*log_entry
= (void *)current
;
974 uint32_t event_type
= le32toh(log_entry
->event_type
);
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
);
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
);
987 printf("\tNo digests in this log entry\n");
988 current
+= sizeof(log_entry
->digest_count
);
990 /* Now event size and event are left to be parsed */
991 len
= le32toh(*(uint32_t *)current
);
992 current
+= sizeof(uint32_t);
994 printf("\tEvent data: %.*s\n", len
, (const char *)current
);
997 printf("\tEvent data not provided\n");
1002 /* Dump the TPM log table in format defined by specifications */
1003 static void dump_tpm_std_log(uint64_t addr
, size_t size
)
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
;
1010 event_log
= map_memory(&log_mapping
, addr
, size
);
1012 die("Unable to map TPM eventlog\n");
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
);
1022 fprintf(stderr
, "Unknown TPM1.2 log specification\n");
1024 unmap_memory(&log_mapping
);
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
);
1035 fprintf(stderr
, "Unknown TPM2 log specification.\n");
1037 unmap_memory(&log_mapping
);
1041 fprintf(stderr
, "Unknown TPM log specification: %.*s\n",
1042 (int)sizeof(tcg_spec_entry
->signature
),
1043 (const char *)tcg_spec_entry
->signature
);
1045 unmap_memory(&log_mapping
);
1048 /* dump the TPM CB log table */
1049 static void dump_tpm_cb_log(void)
1051 const struct tpm_cb_log_table
*tclt_p
;
1053 struct mapping log_mapping
;
1055 if (tpm_cb_log
.tag
!= LB_TAG_TPM_CB_LOG
) {
1056 fprintf(stderr
, "No TPM log found in coreboot table.\n");
1060 size
= sizeof(*tclt_p
);
1061 tclt_p
= map_memory(&log_mapping
, tpm_cb_log
.cbmem_addr
, size
);
1063 die("Unable to map TPM log header\n");
1065 size
+= tclt_p
->num_entries
* sizeof(tclt_p
->entries
[0]);
1067 unmap_memory(&log_mapping
);
1069 tclt_p
= map_memory(&log_mapping
, tpm_cb_log
.cbmem_addr
, size
);
1071 die("Unable to map full TPM log table\n");
1073 printf("coreboot TPM log:\n\n");
1075 for (uint16_t i
= 0; i
< tclt_p
->num_entries
; i
++) {
1076 const struct tpm_cb_log_entry
*tce
= &tclt_p
->entries
[i
];
1078 printf(" PCR-%u ", tce
->pcr
);
1079 print_hex_string(tce
->digest
, tce
->digest_length
);
1080 printf(" %s [%s]\n", tce
->digest_type
, tce
->name
);
1083 unmap_memory(&log_mapping
);
1086 static void dump_tpm_log(void)
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
);
1098 struct cbmem_console
{
1102 } __attribute__ ((__packed__
));
1104 #define CBMC_CURSOR_MASK ((1 << 28) - 1)
1105 #define CBMC_OVERFLOW (1 << 31)
1107 enum console_print_type
{
1108 CONSOLE_PRINT_FULL
= 0,
1110 CONSOLE_PRINT_PREVIOUS
,
1113 static int parse_loglevel(char *arg
, int *print_unknown_logs
)
1115 if (arg
[0] == '+') {
1116 *print_unknown_logs
= 1;
1119 *print_unknown_logs
= 0;
1123 int loglevel
= strtol(arg
, &endptr
, 0);
1124 if (*endptr
== '\0' && loglevel
>= BIOS_EMERG
&& loglevel
<= BIOS_LOG_PREFIX_MAX_LEVEL
)
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))
1132 *print_unknown_logs
= 1;
1136 /* dump the cbmem console */
1137 static void dump_console(enum console_print_type type
, int max_loglevel
, int print_unknown_logs
)
1139 const struct cbmem_console
*console_p
;
1141 size_t size
, cursor
, previous
;
1142 struct mapping console_mapping
;
1144 if (console
.tag
!= LB_TAG_CBMEM_CONSOLE
) {
1145 fprintf(stderr
, "No console found in coreboot table.\n");
1149 size
= sizeof(*console_p
);
1150 console_p
= map_memory(&console_mapping
, console
.cbmem_addr
, size
);
1152 die("Unable to map console object.\n");
1154 cursor
= console_p
->cursor
& CBMC_CURSOR_MASK
;
1155 if (!(console_p
->cursor
& CBMC_OVERFLOW
) && cursor
< console_p
->size
)
1158 size
= console_p
->size
;
1159 unmap_memory(&console_mapping
);
1161 console_c
= malloc(size
+ 1);
1163 fprintf(stderr
, "Not enough memory for console.\n");
1166 console_c
[size
] = '\0';
1168 console_p
= map_memory(&console_mapping
, console
.cbmem_addr
,
1169 size
+ sizeof(*console_p
));
1172 die("Unable to map full console object.\n");
1174 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");
1180 aligned_memcpy(console_c
, console_p
->body
+ cursor
,
1182 aligned_memcpy(console_c
+ size
- cursor
,
1183 console_p
->body
, cursor
);
1185 aligned_memcpy(console_c
, console_p
->body
, size
);
1188 /* 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
++)
1191 if (!isprint(console_c
[cursor
]) && !isspace(console_c
[cursor
])
1192 && !BIOS_LOG_IS_MARKER(console_c
[cursor
]))
1193 console_c
[cursor
] = '?';
1195 /* We detect the reboot cutoff by looking for a bootblock, romstage or
1196 ramstage banner, in that order (to account for platforms without
1197 CONFIG_BOOTBLOCK_CONSOLE and/or CONFIG_EARLY_CONSOLE). Once we find
1198 a banner, store the last two matches for that stage and stop. */
1199 cursor
= previous
= 0;
1200 if (type
!= CONSOLE_PRINT_FULL
) {
1201 #define BANNER_REGEX(stage) \
1202 "\n\n.?coreboot-[^\n]* " stage " starting.*\\.\\.\\.\n"
1203 #define OVERFLOW_REGEX(stage) "\n.?\\*\\*\\* Pre-CBMEM " stage " console overflow"
1204 const char *regex
[] = { BANNER_REGEX("verstage-before-bootblock"),
1205 BANNER_REGEX("bootblock"),
1206 BANNER_REGEX("verstage"),
1207 OVERFLOW_REGEX("romstage"),
1208 BANNER_REGEX("romstage"),
1209 OVERFLOW_REGEX("ramstage"),
1210 BANNER_REGEX("ramstage") };
1212 for (size_t i
= 0; !cursor
&& i
< ARRAY_SIZE(regex
); i
++) {
1215 int res
= regcomp(&re
, regex
[i
], REG_EXTENDED
| REG_NEWLINE
);
1218 /* Keep looking for matches so we find the last one. */
1219 while (!regexec(&re
, console_c
+ cursor
, 1, &match
, 0)) {
1221 cursor
+= match
.rm_so
+ 1;
1227 if (type
== CONSOLE_PRINT_PREVIOUS
) {
1228 console_c
[cursor
] = '\0';
1234 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
);
1238 if (lvl
> max_loglevel
) {
1244 printf(BIOS_LOG_ESCAPE_PATTERN
, bios_log_escape
[lvl
]);
1245 printf(BIOS_LOG_PREFIX_PATTERN
, bios_log_prefix
[lvl
]);
1250 if (tty
&& !suppressed
)
1251 printf(BIOS_LOG_ESCAPE_RESET
);
1252 suppressed
= !print_unknown_logs
;
1257 printf(BIOS_LOG_ESCAPE_RESET
);
1260 unmap_memory(&console_mapping
);
1263 static void hexdump(unsigned long memory
, int length
)
1268 struct mapping hexdump_mapping
;
1270 m
= map_memory(&hexdump_mapping
, memory
, length
);
1272 die("Unable to map hexdump memory.\n");
1274 for (i
= 0; i
< length
; i
+= 16) {
1278 for (j
= 0; j
< 16; j
++) {
1286 printf("%08lx:", memory
+ i
);
1287 for (j
= 0; j
< 16; j
++)
1288 printf(" %02x", m
[i
+j
]);
1290 for (j
= 0; j
< 16; j
++)
1291 printf("%c", isprint(m
[i
+j
]) ? m
[i
+j
] : '.');
1293 } else if (all_zero
== 2) {
1298 unmap_memory(&hexdump_mapping
);
1301 static void dump_cbmem_hex(void)
1303 if (cbmem
.type
!= LB_MEM_TABLE
) {
1304 fprintf(stderr
, "No coreboot CBMEM area found!\n");
1308 hexdump(cbmem
.start
, cbmem
.size
);
1311 static void rawdump(uint64_t base
, uint64_t size
)
1314 struct mapping dump_mapping
;
1316 m
= map_memory(&dump_mapping
, base
, size
);
1318 die("Unable to map rawdump memory\n");
1320 for (uint64_t i
= 0 ; i
< size
; i
++)
1323 unmap_memory(&dump_mapping
);
1326 static void dump_cbmem_raw(unsigned int id
)
1328 const uint8_t *table
;
1333 table
= mapping_virt(&lbtable_mapping
);
1340 while (offset
< mapping_size(&lbtable_mapping
)) {
1341 const struct lb_record
*lbr
;
1342 struct lb_cbmem_entry lbe
;
1344 lbr
= (const void *)(table
+ offset
);
1345 offset
+= lbr
->size
;
1347 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
1350 aligned_memcpy(&lbe
, lbr
, sizeof(lbe
));
1352 debug("found id for raw dump %0x", lbe
.id
);
1354 size
= lbe
.entry_size
;
1360 fprintf(stderr
, "id %0x not found in cbtable\n", id
);
1362 rawdump(base
, size
);
1365 struct cbmem_id_to_name
{
1369 static const struct cbmem_id_to_name cbmem_ids
[] = { CBMEM_ID_TO_NAME_TABLE
};
1371 #define MAX_STAGEx 10
1372 static void cbmem_print_entry(int n
, uint32_t id
, uint64_t base
, uint64_t size
)
1378 for (size_t i
= 0; i
< ARRAY_SIZE(cbmem_ids
); i
++) {
1379 if (cbmem_ids
[i
].id
== id
) {
1380 name
= cbmem_ids
[i
].name
;
1383 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
));
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
));
1400 printf("%-20s %08x", name
, id
);
1401 printf(" %08" PRIx64
" ", base
);
1402 printf(" %08" PRIx64
"\n", size
);
1405 static void dump_cbmem_toc(void)
1408 const uint8_t *table
;
1411 table
= mapping_virt(&lbtable_mapping
);
1416 printf("CBMEM table of contents:\n");
1417 printf(" %-20s %-8s %-8s %-8s\n", "NAME", "ID", "START",
1423 while (offset
< mapping_size(&lbtable_mapping
)) {
1424 const struct lb_record
*lbr
;
1425 struct lb_cbmem_entry lbe
;
1427 lbr
= (const void *)(table
+ offset
);
1428 offset
+= lbr
->size
;
1430 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
1433 aligned_memcpy(&lbe
, lbr
, sizeof(lbe
));
1434 cbmem_print_entry(i
, lbe
.id
, lbe
.address
, lbe
.entry_size
);
1439 #define COVERAGE_MAGIC 0x584d4153
1449 static int mkpath(char *path
, mode_t mode
)
1451 assert (path
&& *path
);
1453 for (p
= strchr(path
+1, '/'); p
; p
= strchr(p
+ 1, '/')) {
1455 if (mkdir(path
, mode
) == -1) {
1456 if (errno
!= EEXIST
) {
1466 static void dump_coverage(void)
1470 const void *coverage
;
1471 struct mapping coverage_mapping
;
1472 unsigned long phys_offset
;
1473 #define phys_to_virt(x) ((void *)(unsigned long)(x) + phys_offset)
1475 if (find_cbmem_entry(CBMEM_ID_COVERAGE
, &start
, &size
)) {
1476 fprintf(stderr
, "No coverage information found\n");
1480 /* Map coverage area */
1481 coverage
= map_memory(&coverage_mapping
, start
, size
);
1483 die("Unable to map coverage area.\n");
1484 phys_offset
= (unsigned long)coverage
- (unsigned long)start
;
1486 printf("Dumping coverage data...\n");
1488 struct file
*file
= (struct file
*)coverage
;
1489 while (file
&& file
->magic
== COVERAGE_MAGIC
) {
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 "
1500 f
= fopen(filename
, "wb");
1502 printf("Could not open %s: %s\n",
1503 filename
, strerror(errno
));
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
));
1516 file
= (struct file
*)phys_to_virt(file
->next
);
1520 unmap_memory(&coverage_mapping
);
1523 static void print_version(void)
1525 printf("cbmem v%s -- ", CBMEM_VERSION
);
1526 printf("Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.\n\n");
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"
1534 "GNU General Public License for more details.\n\n");
1537 static void print_usage(const char *name
, int exit_code
)
1539 printf("usage: %s [-cCltTLxVvh?]\n", name
);
1541 " -c | --console: print cbmem console\n"
1542 " -1 | --oneboot: print cbmem console for last boot only\n"
1543 " -2 | --2ndtolast: print cbmem console for the boot that came before the last one only\n"
1544 " -B | --loglevel: maximum loglevel to print; prefix `+` (e.g. -B +INFO) to also print lines that have no level\n"
1545 " -C | --coverage: dump coverage information\n"
1546 " -l | --list: print cbmem table of contents\n"
1547 " -x | --hexdump: print hexdump of cbmem area\n"
1548 " -r | --rawdump ID: print rawdump of specific ID (in hex) of cbtable\n"
1549 " -t | --timestamps: print timestamp information\n"
1550 " -T | --parseable-timestamps: print parseable timestamps\n"
1551 " -S | --stacked-timestamps: print stacked timestamps (e.g. for flame graph tools)\n"
1552 " -a | --add-timestamp ID: append timestamp with ID\n"
1553 " -L | --tcpa-log print TPM log\n"
1554 " -V | --verbose: verbose (debugging) output\n"
1555 " -v | --version: print the version\n"
1556 " -h | --help: print this help\n"
1561 #if defined(__arm__) || defined(__aarch64__)
1562 static void dt_update_cells(const char *name
, int *addr_cells_ptr
,
1563 int *size_cells_ptr
)
1565 if (*addr_cells_ptr
>= 0 && *size_cells_ptr
>= 0)
1569 size_t nlen
= strlen(name
);
1570 char *prop
= alloca(nlen
+ sizeof("/#address-cells"));
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
) {
1578 } else if (fd
>= 0) {
1579 if (read(fd
, &buffer
, sizeof(int)) < 0)
1582 *addr_cells_ptr
= ntohl(buffer
);
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
) {
1592 } else if (fd
>= 0) {
1593 if (read(fd
, &buffer
, sizeof(int)) < 0)
1596 *size_cells_ptr
= ntohl(buffer
);
1602 static char *dt_find_compat(const char *parent
, const char *compat
,
1603 int *addr_cells_ptr
, int *size_cells_ptr
)
1606 struct dirent
*entry
;
1609 if (!(dir
= opendir(parent
))) {
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")))
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);
1625 strcpy(name
, parent
);
1627 strcpy(name
+ plen
+ 1, entry
->d_name
);
1629 /* If it's a subnode, recurse. */
1630 if (entry
->d_type
& DT_DIR
) {
1631 ret
= dt_find_compat(name
, compat
, addr_cells_ptr
,
1634 /* There is only one matching node to find, abort. */
1636 /* Gather cells values on the way up. */
1637 dt_update_cells(parent
, addr_cells_ptr
,
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);
1654 if (read(fd
, buffer
, clen
+ 1) < 0) {
1661 if (!strcmp(compat
, buffer
)) {
1662 /* Initialize these to "unset" for the way up. */
1663 *addr_cells_ptr
= *size_cells_ptr
= -1;
1665 /* Can't leave string on the stack or we'll lose it! */
1666 ret
= strdup(parent
);
1674 #endif /* defined(__arm__) || defined(__aarch64__) */
1676 int main(int argc
, char** argv
)
1678 int print_defaults
= 1;
1679 int print_console
= 0;
1680 int print_coverage
= 0;
1682 int print_hexdump
= 0;
1683 int print_rawdump
= 0;
1684 int print_tcpa_log
= 0;
1685 enum timestamps_print_type timestamp_type
= TIMESTAMPS_PRINT_NONE
;
1686 enum console_print_type console_type
= CONSOLE_PRINT_FULL
;
1687 unsigned int rawdump_id
= 0;
1688 int max_loglevel
= BIOS_NEVER
;
1689 int print_unknown_logs
= 1;
1690 uint32_t timestamp_id
= 0;
1692 int opt
, option_index
= 0;
1693 static struct option long_options
[] = {
1694 {"console", 0, 0, 'c'},
1695 {"oneboot", 0, 0, '1'},
1696 {"2ndtolast", 0, 0, '2'},
1697 {"loglevel", required_argument
, 0, 'B'},
1698 {"coverage", 0, 0, 'C'},
1699 {"list", 0, 0, 'l'},
1700 {"tcpa-log", 0, 0, 'L'},
1701 {"timestamps", 0, 0, 't'},
1702 {"parseable-timestamps", 0, 0, 'T'},
1703 {"stacked-timestamps", 0, 0, 'S'},
1704 {"add-timestamp", required_argument
, 0, 'a'},
1705 {"hexdump", 0, 0, 'x'},
1706 {"rawdump", required_argument
, 0, 'r'},
1707 {"verbose", 0, 0, 'V'},
1708 {"version", 0, 0, 'v'},
1709 {"help", 0, 0, 'h'},
1712 while ((opt
= getopt_long(argc
, argv
, "c12B:CltTSa:LxVvh?r:",
1713 long_options
, &option_index
)) != EOF
) {
1721 console_type
= CONSOLE_PRINT_LAST
;
1726 console_type
= CONSOLE_PRINT_PREVIOUS
;
1730 max_loglevel
= parse_loglevel(optarg
, &print_unknown_logs
);
1751 rawdump_id
= strtoul(optarg
, NULL
, 16);
1754 timestamp_type
= TIMESTAMPS_PRINT_NORMAL
;
1758 timestamp_type
= TIMESTAMPS_PRINT_MACHINE_READABLE
;
1762 timestamp_type
= TIMESTAMPS_PRINT_STACKED
;
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);
1780 print_usage(argv
[0], 0);
1784 print_usage(argv
[0], 1);
1789 if (optind
< argc
) {
1790 fprintf(stderr
, "Error: Extra parameter found.\n");
1791 print_usage(argv
[0], 1);
1794 mem_fd
= open("/dev/mem", timestamp_id
? O_RDWR
: O_RDONLY
, 0);
1796 fprintf(stderr
, "Failed to gain memory access: %s\n",
1801 #if defined(__arm__) || defined(__aarch64__)
1802 int addr_cells
, size_cells
;
1803 char *coreboot_node
= dt_find_compat("/proc/device-tree", "coreboot",
1804 &addr_cells
, &size_cells
);
1806 if (!coreboot_node
) {
1807 fprintf(stderr
, "Could not find 'coreboot' compatible node!\n");
1811 if (addr_cells
< 0) {
1812 fprintf(stderr
, "Warning: no #address-cells node in tree!\n");
1816 int nlen
= strlen(coreboot_node
);
1817 char *reg
= alloca(nlen
+ sizeof("/reg"));
1819 strcpy(reg
, coreboot_node
);
1820 strcpy(reg
+ nlen
, "/reg");
1821 free(coreboot_node
);
1823 int fd
= open(reg
, O_RDONLY
);
1830 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) {
1838 /* No variable-length byte swap function anywhere in C... how sad. */
1840 for (i
= 0; i
< addr_cells
* 4; i
++) {
1842 baseaddr
|= *dtbuffer
;
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
;
1852 parse_cbtable(baseaddr
, cb_table_size
);
1854 unsigned long long possible_base_addresses
[] = { 0, 0xf0000 };
1856 /* Find and parse coreboot table */
1857 for (size_t j
= 0; j
< ARRAY_SIZE(possible_base_addresses
); j
++) {
1858 if (!parse_cbtable(possible_base_addresses
[j
], 0))
1863 if (mapping_virt(&lbtable_mapping
) == NULL
)
1864 die("Table not found.\n");
1867 dump_console(console_type
, max_loglevel
, print_unknown_logs
);
1879 dump_cbmem_raw(rawdump_id
);
1882 timestamp_add_now(timestamp_id
);
1885 timestamp_type
= TIMESTAMPS_PRINT_NORMAL
;
1887 if (timestamp_type
!= TIMESTAMPS_PRINT_NONE
)
1888 dump_timestamps(timestamp_type
);
1893 unmap_memory(&lbtable_mapping
);