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/loglevel.h>
23 #include <commonlib/timestamp_serialized.h>
24 #include <commonlib/tpm_log_serialized.h>
25 #include <commonlib/coreboot_tables.h>
28 #include <sys/param.h>
29 #include <sys/sysctl.h>
32 #if defined(__i386__) || defined(__x86_64__)
33 #include <x86intrin.h>
36 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
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
;
204 * calculate ip checksum (16 bit quantities) on a passed in buffer. In case
205 * the buffer length is odd last byte is excluded from the calculation
207 static u16
ipchcksum(const void *addr
, unsigned size
)
210 unsigned i
, n
= size
/ 2; /* don't expect odd sized blocks */
213 for (i
= 0; i
< n
; i
++)
216 sum
= (sum
>> 16) + (sum
& 0xffff);
222 /* Find the first cbmem entry filling in the details. */
223 static int find_cbmem_entry(uint32_t id
, uint64_t *addr
, size_t *size
)
225 const uint8_t *table
;
229 table
= mapping_virt(&lbtable_mapping
);
236 while (offset
< mapping_size(&lbtable_mapping
)) {
237 const struct lb_record
*lbr
;
238 struct lb_cbmem_entry lbe
;
240 lbr
= (const void *)(table
+ offset
);
243 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
246 aligned_memcpy(&lbe
, lbr
, sizeof(lbe
));
251 *size
= lbe
.entry_size
;
260 * Try finding the timestamp table and coreboot cbmem console starting from the
261 * passed in memory offset. Could be called recursively in case a forwarding
264 * Returns pointer to a memory buffer containing the timestamp table or zero if
268 static struct lb_cbmem_ref timestamps
;
269 static struct lb_cbmem_ref console
;
270 static struct lb_cbmem_ref tpm_cb_log
;
271 static struct lb_memory_range cbmem
;
273 /* This is a work-around for a nasty problem introduced by initially having
274 * pointer sized entries in the lb_cbmem_ref structures. This caused problems
275 * on 64bit x86 systems because coreboot is 32bit on those systems.
276 * When the problem was found, it was corrected, but there are a lot of
277 * systems out there with a firmware that does not produce the right
278 * lb_cbmem_ref structure. Hence we try to autocorrect this issue here.
280 static struct lb_cbmem_ref
parse_cbmem_ref(const struct lb_cbmem_ref
*cbmem_ref
)
282 struct lb_cbmem_ref ret
;
284 aligned_memcpy(&ret
, cbmem_ref
, sizeof(ret
));
286 if (cbmem_ref
->size
< sizeof(*cbmem_ref
))
287 ret
.cbmem_addr
= (uint32_t)ret
.cbmem_addr
;
289 debug(" cbmem_addr = %" PRIx64
"\n", ret
.cbmem_addr
);
294 static void parse_memory_tags(const struct lb_memory
*mem
)
299 /* Peel off the header size and calculate the number of entries. */
300 num_entries
= (mem
->size
- sizeof(*mem
)) / sizeof(mem
->map
[0]);
302 for (i
= 0; i
< num_entries
; i
++) {
303 if (mem
->map
[i
].type
!= LB_MEM_TABLE
)
305 debug(" LB_MEM_TABLE found.\n");
306 /* The last one found is CBMEM */
307 aligned_memcpy(&cbmem
, &mem
->map
[i
], sizeof(cbmem
));
311 /* Return < 0 on error, 0 on success, 1 if forwarding table entry found. */
312 static int parse_cbtable_entries(const struct mapping
*table_mapping
)
315 const struct lb_record
*lbr_p
;
316 size_t table_size
= mapping_size(table_mapping
);
317 const void *lbtable
= mapping_virt(table_mapping
);
318 int forwarding_table_found
= 0;
320 for (i
= 0; i
< table_size
; i
+= lbr_p
->size
) {
322 debug(" coreboot table entry 0x%02x\n", lbr_p
->tag
);
323 switch (lbr_p
->tag
) {
325 debug(" Found memory map.\n");
326 parse_memory_tags(lbtable
+ i
);
328 case LB_TAG_TIMESTAMPS
: {
329 debug(" Found timestamp table.\n");
331 parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
334 case LB_TAG_CBMEM_CONSOLE
: {
335 debug(" Found cbmem console.\n");
336 console
= parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
339 case LB_TAG_TPM_CB_LOG
: {
340 debug(" Found TPM CB log table.\n");
342 parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
345 case LB_TAG_TSC_INFO
:
346 debug(" Found TSC info.\n");
347 tsc_freq_khz
= ((struct lb_tsc_info
*)lbr_p
)->freq_khz
;
349 case LB_TAG_FORWARD
: {
352 * This is a forwarding entry - repeat the
353 * search at the new address.
355 struct lb_forward lbf_p
=
356 *(const struct lb_forward
*)lbr_p
;
357 debug(" Found forwarding entry.\n");
358 ret
= parse_cbtable(lbf_p
.forward
, 0);
360 /* Assume the forwarding entry is valid. If this fails
361 * then there's a total failure. */
364 forwarding_table_found
= 1;
371 return forwarding_table_found
;
374 /* Return < 0 on error, 0 on success. */
375 static int parse_cbtable(u64 address
, size_t table_size
)
378 struct mapping header_mapping
;
382 req_size
= table_size
;
383 /* Default to 4 KiB search space. */
387 debug("Looking for coreboot table at %" PRIx64
" %zd bytes.\n",
390 buf
= map_memory(&header_mapping
, address
, req_size
);
395 /* look at every 16 bytes */
396 for (i
= 0; i
<= req_size
- sizeof(struct lb_header
); i
+= 16) {
398 const struct lb_header
*lbh
;
399 struct mapping table_mapping
;
402 if (memcmp(lbh
->signature
, "LBIO", sizeof(lbh
->signature
)) ||
403 !lbh
->header_bytes
||
404 ipchcksum(lbh
, sizeof(*lbh
))) {
408 /* Map in the whole table to parse. */
409 if (!map_memory(&table_mapping
, address
+ i
+ lbh
->header_bytes
,
411 debug("Couldn't map in table\n");
415 if (ipchcksum(mapping_virt(&table_mapping
), lbh
->table_bytes
) !=
416 lbh
->table_checksum
) {
417 debug("Signature found, but wrong checksum.\n");
418 unmap_memory(&table_mapping
);
424 ret
= parse_cbtable_entries(&table_mapping
);
426 /* Table parsing failed. */
428 unmap_memory(&table_mapping
);
432 /* Succeeded in parsing the table. Header not needed anymore. */
433 unmap_memory(&header_mapping
);
436 * Table parsing succeeded. If forwarding table not found update
437 * coreboot table mapping for future use.
440 lbtable_mapping
= table_mapping
;
442 unmap_memory(&table_mapping
);
447 unmap_memory(&header_mapping
);
452 #if defined(linux) && (defined(__i386__) || defined(__x86_64__))
454 * read CPU frequency from a sysfs file, return an frequency in Megahertz as
455 * an int or exit on any error.
457 static unsigned long arch_tick_frequency(void)
465 const char* freq_file
=
466 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
468 cpuf
= fopen(freq_file
, "r");
470 fprintf(stderr
, "Could not open %s: %s\n",
471 freq_file
, strerror(errno
));
475 memset(freqs
, 0, sizeof(freqs
));
476 size
= fread(freqs
, 1, sizeof(freqs
), cpuf
);
477 if (!size
|| (size
== sizeof(freqs
))) {
478 fprintf(stderr
, "Wrong number of bytes(%d) read from %s\n",
483 rv
= strtoull(freqs
, &endp
, 10);
485 if (*endp
== '\0' || *endp
== '\n')
486 /* cpuinfo_max_freq is in kHz. Convert it to MHz. */
488 fprintf(stderr
, "Wrong formatted value ^%s^ read from %s\n",
492 #elif defined(__OpenBSD__) && (defined(__i386__) || defined(__x86_64__))
493 static unsigned long arch_tick_frequency(void)
495 int mib
[2] = { CTL_HW
, HW_CPUSPEED
};
496 static int value
= 0;
497 size_t value_len
= sizeof(value
);
499 /* Return 1 MHz when sysctl fails. */
500 if ((value
== 0) && (sysctl(mib
, 2, &value
, &value_len
, NULL
, 0) == -1))
506 static unsigned long arch_tick_frequency(void)
513 static unsigned long tick_freq_mhz
;
515 static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz
)
517 tick_freq_mhz
= table_tick_freq_mhz
;
519 /* Honor table frequency if present. */
521 tick_freq_mhz
= arch_tick_frequency();
523 if (!tick_freq_mhz
) {
524 fprintf(stderr
, "Cannot determine timestamp tick frequency.\n");
528 debug("Timestamp tick frequency: %ld MHz\n", tick_freq_mhz
);
531 static u64
arch_convert_raw_ts_entry(u64 ts
)
533 return ts
/ tick_freq_mhz
;
537 * Print an integer in 'normalized' form - with commas separating every three
540 static void print_norm(u64 v
)
543 /* print the higher order sections first */
544 print_norm(v
/ 1000);
545 printf(",%3.3u", (u32
)(v
% 1000));
547 printf("%u", (u32
)(v
% 1000));
551 static uint64_t timestamp_get(uint64_t table_tick_freq_mhz
)
553 #if defined(__i386__) || defined(__x86_64__)
554 uint64_t tsc
= __rdtsc();
556 /* No tick frequency specified means raw TSC values. */
557 if (!table_tick_freq_mhz
)
561 return tsc
* table_tick_freq_mhz
* 1000 / tsc_freq_khz
;
563 (void)table_tick_freq_mhz
;
565 die("Don't know how to obtain timestamps on this platform.\n");
569 static const char *timestamp_name(uint32_t id
)
571 for (size_t i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++) {
572 if (timestamp_ids
[i
].id
== id
)
573 return timestamp_ids
[i
].name
;
578 static uint32_t timestamp_enum_name_to_id(const char *name
)
580 for (size_t i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++) {
581 if (!strcmp(timestamp_ids
[i
].enum_name
, name
))
582 return timestamp_ids
[i
].id
;
587 static uint64_t timestamp_print_parseable_entry(uint32_t id
, uint64_t stamp
,
593 name
= timestamp_name(id
);
595 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
597 /* ID<tab>absolute time<tab>relative time<tab>description */
599 printf("%llu\t", (long long)arch_convert_raw_ts_entry(stamp
));
600 printf("%llu\t", (long long)step_time
);
601 printf("%s\n", name
);
606 static uint64_t timestamp_print_entry(uint32_t id
, uint64_t stamp
, uint64_t prev_stamp
)
611 name
= timestamp_name(id
);
614 printf("%-50s", name
);
615 print_norm(arch_convert_raw_ts_entry(stamp
));
616 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
619 print_norm(step_time
);
627 static int compare_timestamp_entries(const void *a
, const void *b
)
629 const struct timestamp_entry
*tse_a
= (struct timestamp_entry
*)a
;
630 const struct timestamp_entry
*tse_b
= (struct timestamp_entry
*)b
;
632 if (tse_a
->entry_stamp
> tse_b
->entry_stamp
)
634 else if (tse_a
->entry_stamp
< tse_b
->entry_stamp
)
640 static int find_matching_end(struct timestamp_table
*sorted_tst_p
, uint32_t start
, uint32_t end
)
642 uint32_t id
= sorted_tst_p
->entries
[start
].entry_id
;
643 uint32_t possible_match
= 0;
645 for (uint32_t i
= 0; i
< ARRAY_SIZE(timestamp_ids
); ++i
) {
646 if (timestamp_ids
[i
].id
== id
) {
647 possible_match
= timestamp_ids
[i
].id_end
;
652 /* No match found or timestamp not defined in IDs table */
656 for (uint32_t i
= start
+ 1; i
< end
; i
++)
657 if (sorted_tst_p
->entries
[i
].entry_id
== possible_match
)
663 static const char *get_timestamp_name(const uint32_t id
)
665 for (uint32_t i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++)
666 if (timestamp_ids
[i
].id
== id
)
667 return timestamp_ids
[i
].enum_name
;
672 struct ts_range_stack
{
674 const char *end_name
;
678 static void print_with_path(struct ts_range_stack
*range_stack
, const int stacklvl
,
679 const uint64_t stamp
, const char *last_part
)
681 for (int i
= 1; i
<= stacklvl
; ++i
) {
682 printf("%s -> %s", range_stack
[i
].name
, range_stack
[i
].end_name
);
683 if (i
< stacklvl
|| last_part
)
687 printf("%s", last_part
);
688 printf(" %llu\n", (long long)arch_convert_raw_ts_entry(stamp
));
691 enum timestamps_print_type
{
692 TIMESTAMPS_PRINT_NONE
,
693 TIMESTAMPS_PRINT_NORMAL
,
694 TIMESTAMPS_PRINT_MACHINE_READABLE
,
695 TIMESTAMPS_PRINT_STACKED
,
698 /* dump the timestamp table */
699 static void dump_timestamps(enum timestamps_print_type output_type
)
701 const struct timestamp_table
*tst_p
;
702 struct timestamp_table
*sorted_tst_p
;
704 uint64_t prev_stamp
= 0;
705 uint64_t total_time
= 0;
706 struct mapping timestamp_mapping
;
708 if (timestamps
.tag
!= LB_TAG_TIMESTAMPS
) {
709 fprintf(stderr
, "No timestamps found in coreboot table.\n");
713 size
= sizeof(*tst_p
);
714 tst_p
= map_memory(×tamp_mapping
, timestamps
.cbmem_addr
, size
);
716 die("Unable to map timestamp header\n");
718 timestamp_set_tick_freq(tst_p
->tick_freq_mhz
);
720 if (output_type
== TIMESTAMPS_PRINT_NORMAL
)
721 printf("%d entries total:\n\n", tst_p
->num_entries
);
722 size
+= tst_p
->num_entries
* sizeof(tst_p
->entries
[0]);
724 unmap_memory(×tamp_mapping
);
726 tst_p
= map_memory(×tamp_mapping
, timestamps
.cbmem_addr
, size
);
728 die("Unable to map full timestamp table\n");
730 sorted_tst_p
= malloc(size
+ sizeof(struct timestamp_entry
));
732 die("Failed to allocate memory");
733 aligned_memcpy(sorted_tst_p
, tst_p
, size
);
736 * Insert a timestamp to represent the base time (start of coreboot),
737 * in case we have to rebase for negative timestamps below.
739 sorted_tst_p
->entries
[tst_p
->num_entries
].entry_id
= 0;
740 sorted_tst_p
->entries
[tst_p
->num_entries
].entry_stamp
= 0;
741 sorted_tst_p
->num_entries
+= 1;
743 qsort(&sorted_tst_p
->entries
[0], sorted_tst_p
->num_entries
,
744 sizeof(struct timestamp_entry
), compare_timestamp_entries
);
747 * If there are negative timestamp entries, rebase all of the
748 * timestamps to the lowest one in the list.
750 if (sorted_tst_p
->entries
[0].entry_stamp
< 0) {
751 sorted_tst_p
->base_time
= -sorted_tst_p
->entries
[0].entry_stamp
;
754 prev_stamp
= tst_p
->base_time
;
757 struct ts_range_stack range_stack
[20];
758 range_stack
[0].end
= sorted_tst_p
->num_entries
;
761 for (uint32_t i
= 0; i
< sorted_tst_p
->num_entries
; i
++) {
763 const struct timestamp_entry
*tse
= &sorted_tst_p
->entries
[i
];
765 /* Make all timestamps absolute. */
766 stamp
= tse
->entry_stamp
+ sorted_tst_p
->base_time
;
767 if (output_type
== TIMESTAMPS_PRINT_MACHINE_READABLE
) {
768 timestamp_print_parseable_entry(tse
->entry_id
, stamp
, prev_stamp
);
769 } else if (output_type
== TIMESTAMPS_PRINT_NORMAL
) {
770 total_time
+= timestamp_print_entry(tse
->entry_id
, stamp
, prev_stamp
);
771 } else if (output_type
== TIMESTAMPS_PRINT_STACKED
) {
772 bool end_of_range
= false;
773 /* Iterate over stacked entries to pop all ranges, which are closed by
774 current element. For example, assuming two ranges: (TS_A, TS_C),
775 (TS_B, TS_C) it will pop all of them instead of just last one. */
776 while (stacklvl
> 0 && range_stack
[stacklvl
].end
== i
) {
782 find_matching_end(sorted_tst_p
, i
, range_stack
[stacklvl
].end
);
784 const uint64_t match_stamp
=
785 sorted_tst_p
->entries
[match
].entry_stamp
786 + sorted_tst_p
->base_time
;
788 assert(stacklvl
< (int)ARRAY_SIZE(range_stack
));
789 range_stack
[stacklvl
].name
= get_timestamp_name(tse
->entry_id
);
790 range_stack
[stacklvl
].end_name
= get_timestamp_name(
791 sorted_tst_p
->entries
[match
].entry_id
);
792 range_stack
[stacklvl
].end
= match
;
793 print_with_path(range_stack
, stacklvl
, match_stamp
- stamp
,
795 } else if (!end_of_range
) {
796 print_with_path(range_stack
, stacklvl
, stamp
- prev_stamp
,
797 get_timestamp_name(tse
->entry_id
));
799 /* else: No match && end_of_range == true */
804 if (output_type
== TIMESTAMPS_PRINT_NORMAL
) {
805 printf("\nTotal Time: ");
806 print_norm(total_time
);
810 unmap_memory(×tamp_mapping
);
814 /* add a timestamp entry */
815 static void timestamp_add_now(uint32_t timestamp_id
)
817 struct timestamp_table
*tst_p
;
818 struct mapping timestamp_mapping
;
820 if (timestamps
.tag
!= LB_TAG_TIMESTAMPS
) {
821 die("No timestamps found in coreboot table.\n");
824 tst_p
= map_memory_with_prot(×tamp_mapping
, timestamps
.cbmem_addr
,
825 timestamps
.size
, PROT_READ
| PROT_WRITE
);
827 die("Unable to map timestamp table\n");
830 * Note that coreboot sizes the cbmem entry in the table according to
831 * max_entries, so it's OK to just add more entries if there's room.
833 if (tst_p
->num_entries
>= tst_p
->max_entries
) {
834 die("Not enough space to add timestamp.\n");
837 timestamp_get(tst_p
->tick_freq_mhz
) - tst_p
->base_time
;
838 tst_p
->entries
[tst_p
->num_entries
].entry_id
= timestamp_id
;
839 tst_p
->entries
[tst_p
->num_entries
].entry_stamp
= time
;
840 tst_p
->num_entries
+= 1;
843 unmap_memory(×tamp_mapping
);
846 /* dump the TPM CB log table */
847 static void dump_tpm_cb_log(void)
849 const struct tpm_cb_log_table
*tclt_p
;
851 struct mapping log_mapping
;
853 if (tpm_cb_log
.tag
!= LB_TAG_TPM_CB_LOG
) {
854 fprintf(stderr
, "No TPM log found in coreboot table.\n");
858 size
= sizeof(*tclt_p
);
859 tclt_p
= map_memory(&log_mapping
, tpm_cb_log
.cbmem_addr
, size
);
861 die("Unable to map TPM log header\n");
863 size
+= tclt_p
->num_entries
* sizeof(tclt_p
->entries
[0]);
865 unmap_memory(&log_mapping
);
867 tclt_p
= map_memory(&log_mapping
, tpm_cb_log
.cbmem_addr
, size
);
869 die("Unable to map full TPM log table\n");
871 printf("coreboot TPM log:\n\n");
873 for (uint16_t i
= 0; i
< tclt_p
->num_entries
; i
++) {
874 const struct tpm_cb_log_entry
*tce
= &tclt_p
->entries
[i
];
876 printf(" PCR-%u ", tce
->pcr
);
878 for (uint32_t j
= 0; j
< tce
->digest_length
; j
++)
879 printf("%02x", tce
->digest
[j
]);
881 printf(" %s [%s]\n", tce
->digest_type
, tce
->name
);
884 unmap_memory(&log_mapping
);
887 struct cbmem_console
{
891 } __attribute__ ((__packed__
));
893 #define CBMC_CURSOR_MASK ((1 << 28) - 1)
894 #define CBMC_OVERFLOW (1 << 31)
896 enum console_print_type
{
897 CONSOLE_PRINT_FULL
= 0,
899 CONSOLE_PRINT_PREVIOUS
,
902 static int parse_loglevel(char *arg
, int *print_unknown_logs
)
905 *print_unknown_logs
= 1;
908 *print_unknown_logs
= 0;
912 int loglevel
= strtol(arg
, &endptr
, 0);
913 if (*endptr
== '\0' && loglevel
>= BIOS_EMERG
&& loglevel
<= BIOS_LOG_PREFIX_MAX_LEVEL
)
916 /* Only match first 3 characters so `NOTE` and `NOTICE` both match. */
917 for (int i
= BIOS_EMERG
; i
<= BIOS_LOG_PREFIX_MAX_LEVEL
; i
++)
918 if (!strncasecmp(arg
, bios_log_prefix
[i
], 3))
921 *print_unknown_logs
= 1;
925 /* dump the cbmem console */
926 static void dump_console(enum console_print_type type
, int max_loglevel
, int print_unknown_logs
)
928 const struct cbmem_console
*console_p
;
930 size_t size
, cursor
, previous
;
931 struct mapping console_mapping
;
933 if (console
.tag
!= LB_TAG_CBMEM_CONSOLE
) {
934 fprintf(stderr
, "No console found in coreboot table.\n");
938 size
= sizeof(*console_p
);
939 console_p
= map_memory(&console_mapping
, console
.cbmem_addr
, size
);
941 die("Unable to map console object.\n");
943 cursor
= console_p
->cursor
& CBMC_CURSOR_MASK
;
944 if (!(console_p
->cursor
& CBMC_OVERFLOW
) && cursor
< console_p
->size
)
947 size
= console_p
->size
;
948 unmap_memory(&console_mapping
);
950 console_c
= malloc(size
+ 1);
952 fprintf(stderr
, "Not enough memory for console.\n");
955 console_c
[size
] = '\0';
957 console_p
= map_memory(&console_mapping
, console
.cbmem_addr
,
958 size
+ sizeof(*console_p
));
961 die("Unable to map full console object.\n");
963 if (console_p
->cursor
& CBMC_OVERFLOW
) {
964 if (cursor
>= size
) {
965 printf("cbmem: ERROR: CBMEM console struct is illegal, "
966 "output may be corrupt or out of order!\n\n");
969 aligned_memcpy(console_c
, console_p
->body
+ cursor
,
971 aligned_memcpy(console_c
+ size
- cursor
,
972 console_p
->body
, cursor
);
974 aligned_memcpy(console_c
, console_p
->body
, size
);
977 /* Slight memory corruption may occur between reboots and give us a few
978 unprintable characters like '\0'. Replace them with '?' on output. */
979 for (cursor
= 0; cursor
< size
; cursor
++)
980 if (!isprint(console_c
[cursor
]) && !isspace(console_c
[cursor
])
981 && !BIOS_LOG_IS_MARKER(console_c
[cursor
]))
982 console_c
[cursor
] = '?';
984 /* We detect the reboot cutoff by looking for a bootblock, romstage or
985 ramstage banner, in that order (to account for platforms without
986 CONFIG_BOOTBLOCK_CONSOLE and/or CONFIG_EARLY_CONSOLE). Once we find
987 a banner, store the last two matches for that stage and stop. */
988 cursor
= previous
= 0;
989 if (type
!= CONSOLE_PRINT_FULL
) {
990 #define BANNER_REGEX(stage) \
991 "\n\n.?coreboot-[^\n]* " stage " starting.*\\.\\.\\.\n"
992 #define OVERFLOW_REGEX(stage) "\n.?\\*\\*\\* Pre-CBMEM " stage " console overflow"
993 const char *regex
[] = { BANNER_REGEX("verstage-before-bootblock"),
994 BANNER_REGEX("bootblock"),
995 BANNER_REGEX("verstage"),
996 OVERFLOW_REGEX("romstage"),
997 BANNER_REGEX("romstage"),
998 OVERFLOW_REGEX("ramstage"),
999 BANNER_REGEX("ramstage") };
1001 for (size_t i
= 0; !cursor
&& i
< ARRAY_SIZE(regex
); i
++) {
1004 int res
= regcomp(&re
, regex
[i
], REG_EXTENDED
| REG_NEWLINE
);
1007 /* Keep looking for matches so we find the last one. */
1008 while (!regexec(&re
, console_c
+ cursor
, 1, &match
, 0)) {
1010 cursor
+= match
.rm_so
+ 1;
1016 if (type
== CONSOLE_PRINT_PREVIOUS
) {
1017 console_c
[cursor
] = '\0';
1023 int tty
= isatty(fileno(stdout
));
1024 while ((c
= console_c
[cursor
++])) {
1025 if (BIOS_LOG_IS_MARKER(c
)) {
1026 int lvl
= BIOS_LOG_MARKER_TO_LEVEL(c
);
1027 if (lvl
> max_loglevel
) {
1033 printf(BIOS_LOG_ESCAPE_PATTERN
, bios_log_escape
[lvl
]);
1034 printf(BIOS_LOG_PREFIX_PATTERN
, bios_log_prefix
[lvl
]);
1039 if (tty
&& !suppressed
)
1040 printf(BIOS_LOG_ESCAPE_RESET
);
1041 suppressed
= !print_unknown_logs
;
1046 printf(BIOS_LOG_ESCAPE_RESET
);
1049 unmap_memory(&console_mapping
);
1052 static void hexdump(unsigned long memory
, int length
)
1057 struct mapping hexdump_mapping
;
1059 m
= map_memory(&hexdump_mapping
, memory
, length
);
1061 die("Unable to map hexdump memory.\n");
1063 for (i
= 0; i
< length
; i
+= 16) {
1067 for (j
= 0; j
< 16; j
++) {
1075 printf("%08lx:", memory
+ i
);
1076 for (j
= 0; j
< 16; j
++)
1077 printf(" %02x", m
[i
+j
]);
1079 for (j
= 0; j
< 16; j
++)
1080 printf("%c", isprint(m
[i
+j
]) ? m
[i
+j
] : '.');
1082 } else if (all_zero
== 2) {
1087 unmap_memory(&hexdump_mapping
);
1090 static void dump_cbmem_hex(void)
1092 if (cbmem
.type
!= LB_MEM_TABLE
) {
1093 fprintf(stderr
, "No coreboot CBMEM area found!\n");
1097 hexdump(cbmem
.start
, cbmem
.size
);
1100 static void rawdump(uint64_t base
, uint64_t size
)
1103 struct mapping dump_mapping
;
1105 m
= map_memory(&dump_mapping
, base
, size
);
1107 die("Unable to map rawdump memory\n");
1109 for (uint64_t i
= 0 ; i
< size
; i
++)
1112 unmap_memory(&dump_mapping
);
1115 static void dump_cbmem_raw(unsigned int id
)
1117 const uint8_t *table
;
1122 table
= mapping_virt(&lbtable_mapping
);
1129 while (offset
< mapping_size(&lbtable_mapping
)) {
1130 const struct lb_record
*lbr
;
1131 struct lb_cbmem_entry lbe
;
1133 lbr
= (const void *)(table
+ offset
);
1134 offset
+= lbr
->size
;
1136 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
1139 aligned_memcpy(&lbe
, lbr
, sizeof(lbe
));
1141 debug("found id for raw dump %0x", lbe
.id
);
1143 size
= lbe
.entry_size
;
1149 fprintf(stderr
, "id %0x not found in cbtable\n", id
);
1151 rawdump(base
, size
);
1154 struct cbmem_id_to_name
{
1158 static const struct cbmem_id_to_name cbmem_ids
[] = { CBMEM_ID_TO_NAME_TABLE
};
1160 #define MAX_STAGEx 10
1161 static void cbmem_print_entry(int n
, uint32_t id
, uint64_t base
, uint64_t size
)
1167 for (size_t i
= 0; i
< ARRAY_SIZE(cbmem_ids
); i
++) {
1168 if (cbmem_ids
[i
].id
== id
) {
1169 name
= cbmem_ids
[i
].name
;
1172 if (id
>= CBMEM_ID_STAGEx_META
&&
1173 id
< CBMEM_ID_STAGEx_META
+ MAX_STAGEx
) {
1174 snprintf(stage_x
, sizeof(stage_x
), "STAGE%d META",
1175 (id
- CBMEM_ID_STAGEx_META
));
1178 if (id
>= CBMEM_ID_STAGEx_CACHE
&&
1179 id
< CBMEM_ID_STAGEx_CACHE
+ MAX_STAGEx
) {
1180 snprintf(stage_x
, sizeof(stage_x
), "STAGE%d $ ",
1181 (id
- CBMEM_ID_STAGEx_CACHE
));
1189 printf("%-20s %08x", name
, id
);
1190 printf(" %08" PRIx64
" ", base
);
1191 printf(" %08" PRIx64
"\n", size
);
1194 static void dump_cbmem_toc(void)
1197 const uint8_t *table
;
1200 table
= mapping_virt(&lbtable_mapping
);
1205 printf("CBMEM table of contents:\n");
1206 printf(" %-20s %-8s %-8s %-8s\n", "NAME", "ID", "START",
1212 while (offset
< mapping_size(&lbtable_mapping
)) {
1213 const struct lb_record
*lbr
;
1214 struct lb_cbmem_entry lbe
;
1216 lbr
= (const void *)(table
+ offset
);
1217 offset
+= lbr
->size
;
1219 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
1222 aligned_memcpy(&lbe
, lbr
, sizeof(lbe
));
1223 cbmem_print_entry(i
, lbe
.id
, lbe
.address
, lbe
.entry_size
);
1228 #define COVERAGE_MAGIC 0x584d4153
1238 static int mkpath(char *path
, mode_t mode
)
1240 assert (path
&& *path
);
1242 for (p
= strchr(path
+1, '/'); p
; p
= strchr(p
+ 1, '/')) {
1244 if (mkdir(path
, mode
) == -1) {
1245 if (errno
!= EEXIST
) {
1255 static void dump_coverage(void)
1259 const void *coverage
;
1260 struct mapping coverage_mapping
;
1261 unsigned long phys_offset
;
1262 #define phys_to_virt(x) ((void *)(unsigned long)(x) + phys_offset)
1264 if (find_cbmem_entry(CBMEM_ID_COVERAGE
, &start
, &size
)) {
1265 fprintf(stderr
, "No coverage information found\n");
1269 /* Map coverage area */
1270 coverage
= map_memory(&coverage_mapping
, start
, size
);
1272 die("Unable to map coverage area.\n");
1273 phys_offset
= (unsigned long)coverage
- (unsigned long)start
;
1275 printf("Dumping coverage data...\n");
1277 struct file
*file
= (struct file
*)coverage
;
1278 while (file
&& file
->magic
== COVERAGE_MAGIC
) {
1282 debug(" -> %s\n", (char *)phys_to_virt(file
->filename
));
1283 filename
= strdup((char *)phys_to_virt(file
->filename
));
1284 if (mkpath(filename
, 0755) == -1) {
1285 perror("Directory for coverage data could "
1289 f
= fopen(filename
, "wb");
1291 printf("Could not open %s: %s\n",
1292 filename
, strerror(errno
));
1295 if (fwrite((void *)phys_to_virt(file
->data
),
1296 file
->len
, 1, f
) != 1) {
1297 printf("Could not write to %s: %s\n",
1298 filename
, strerror(errno
));
1305 file
= (struct file
*)phys_to_virt(file
->next
);
1309 unmap_memory(&coverage_mapping
);
1312 static void print_version(void)
1314 printf("cbmem v%s -- ", CBMEM_VERSION
);
1315 printf("Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.\n\n");
1317 "This program is free software: you can redistribute it and/or modify\n"
1318 "it under the terms of the GNU General Public License as published by\n"
1319 "the Free Software Foundation, version 2 of the License.\n\n"
1320 "This program is distributed in the hope that it will be useful,\n"
1321 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1322 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1323 "GNU General Public License for more details.\n\n");
1326 static void print_usage(const char *name
, int exit_code
)
1328 printf("usage: %s [-cCltTLxVvh?]\n", name
);
1330 " -c | --console: print cbmem console\n"
1331 " -1 | --oneboot: print cbmem console for last boot only\n"
1332 " -2 | --2ndtolast: print cbmem console for the boot that came before the last one only\n"
1333 " -B | --loglevel: maximum loglevel to print; prefix `+` (e.g. -B +INFO) to also print lines that have no level\n"
1334 " -C | --coverage: dump coverage information\n"
1335 " -l | --list: print cbmem table of contents\n"
1336 " -x | --hexdump: print hexdump of cbmem area\n"
1337 " -r | --rawdump ID: print rawdump of specific ID (in hex) of cbtable\n"
1338 " -t | --timestamps: print timestamp information\n"
1339 " -T | --parseable-timestamps: print parseable timestamps\n"
1340 " -S | --stacked-timestamps: print stacked timestamps (e.g. for flame graph tools)\n"
1341 " -a | --add-timestamp ID: append timestamp with ID\n"
1342 " -L | --tcpa-log print TPM log\n"
1343 " -V | --verbose: verbose (debugging) output\n"
1344 " -v | --version: print the version\n"
1345 " -h | --help: print this help\n"
1350 #if defined(__arm__) || defined(__aarch64__)
1351 static void dt_update_cells(const char *name
, int *addr_cells_ptr
,
1352 int *size_cells_ptr
)
1354 if (*addr_cells_ptr
>= 0 && *size_cells_ptr
>= 0)
1358 size_t nlen
= strlen(name
);
1359 char *prop
= alloca(nlen
+ sizeof("/#address-cells"));
1362 if (*addr_cells_ptr
< 0) {
1363 strcpy(prop
+ nlen
, "/#address-cells");
1364 int fd
= open(prop
, O_RDONLY
);
1365 if (fd
< 0 && errno
!= ENOENT
) {
1367 } else if (fd
>= 0) {
1368 if (read(fd
, &buffer
, sizeof(int)) < 0)
1371 *addr_cells_ptr
= ntohl(buffer
);
1376 if (*size_cells_ptr
< 0) {
1377 strcpy(prop
+ nlen
, "/#size-cells");
1378 int fd
= open(prop
, O_RDONLY
);
1379 if (fd
< 0 && errno
!= ENOENT
) {
1381 } else if (fd
>= 0) {
1382 if (read(fd
, &buffer
, sizeof(int)) < 0)
1385 *size_cells_ptr
= ntohl(buffer
);
1391 static char *dt_find_compat(const char *parent
, const char *compat
,
1392 int *addr_cells_ptr
, int *size_cells_ptr
)
1395 struct dirent
*entry
;
1398 if (!(dir
= opendir(parent
))) {
1403 /* Loop through all files in the directory (DT node). */
1404 while ((entry
= readdir(dir
))) {
1405 /* We only care about compatible props or subnodes. */
1406 if (entry
->d_name
[0] == '.' || !((entry
->d_type
& DT_DIR
) ||
1407 !strcmp(entry
->d_name
, "compatible")))
1410 /* Assemble the file name (on the stack, for speed). */
1411 size_t plen
= strlen(parent
);
1412 char *name
= alloca(plen
+ strlen(entry
->d_name
) + 2);
1414 strcpy(name
, parent
);
1416 strcpy(name
+ plen
+ 1, entry
->d_name
);
1418 /* If it's a subnode, recurse. */
1419 if (entry
->d_type
& DT_DIR
) {
1420 ret
= dt_find_compat(name
, compat
, addr_cells_ptr
,
1423 /* There is only one matching node to find, abort. */
1425 /* Gather cells values on the way up. */
1426 dt_update_cells(parent
, addr_cells_ptr
,
1433 /* If it's a compatible string, see if it's the right one. */
1434 int fd
= open(name
, O_RDONLY
);
1435 int clen
= strlen(compat
);
1436 char *buffer
= alloca(clen
+ 1);
1443 if (read(fd
, buffer
, clen
+ 1) < 0) {
1450 if (!strcmp(compat
, buffer
)) {
1451 /* Initialize these to "unset" for the way up. */
1452 *addr_cells_ptr
= *size_cells_ptr
= -1;
1454 /* Can't leave string on the stack or we'll lose it! */
1455 ret
= strdup(parent
);
1463 #endif /* defined(__arm__) || defined(__aarch64__) */
1465 int main(int argc
, char** argv
)
1467 int print_defaults
= 1;
1468 int print_console
= 0;
1469 int print_coverage
= 0;
1471 int print_hexdump
= 0;
1472 int print_rawdump
= 0;
1473 int print_tcpa_log
= 0;
1474 enum timestamps_print_type timestamp_type
= TIMESTAMPS_PRINT_NONE
;
1475 enum console_print_type console_type
= CONSOLE_PRINT_FULL
;
1476 unsigned int rawdump_id
= 0;
1477 int max_loglevel
= BIOS_NEVER
;
1478 int print_unknown_logs
= 1;
1479 uint32_t timestamp_id
= 0;
1481 int opt
, option_index
= 0;
1482 static struct option long_options
[] = {
1483 {"console", 0, 0, 'c'},
1484 {"oneboot", 0, 0, '1'},
1485 {"2ndtolast", 0, 0, '2'},
1486 {"loglevel", required_argument
, 0, 'B'},
1487 {"coverage", 0, 0, 'C'},
1488 {"list", 0, 0, 'l'},
1489 {"tcpa-log", 0, 0, 'L'},
1490 {"timestamps", 0, 0, 't'},
1491 {"parseable-timestamps", 0, 0, 'T'},
1492 {"stacked-timestamps", 0, 0, 'S'},
1493 {"add-timestamp", required_argument
, 0, 'a'},
1494 {"hexdump", 0, 0, 'x'},
1495 {"rawdump", required_argument
, 0, 'r'},
1496 {"verbose", 0, 0, 'V'},
1497 {"version", 0, 0, 'v'},
1498 {"help", 0, 0, 'h'},
1501 while ((opt
= getopt_long(argc
, argv
, "c12B:CltTSa:LxVvh?r:",
1502 long_options
, &option_index
)) != EOF
) {
1510 console_type
= CONSOLE_PRINT_LAST
;
1515 console_type
= CONSOLE_PRINT_PREVIOUS
;
1519 max_loglevel
= parse_loglevel(optarg
, &print_unknown_logs
);
1540 rawdump_id
= strtoul(optarg
, NULL
, 16);
1543 timestamp_type
= TIMESTAMPS_PRINT_NORMAL
;
1547 timestamp_type
= TIMESTAMPS_PRINT_MACHINE_READABLE
;
1551 timestamp_type
= TIMESTAMPS_PRINT_STACKED
;
1556 timestamp_id
= timestamp_enum_name_to_id(optarg
);
1557 /* Parse numeric value if name is unknown */
1558 if (timestamp_id
== 0)
1559 timestamp_id
= strtoul(optarg
, NULL
, 0);
1569 print_usage(argv
[0], 0);
1573 print_usage(argv
[0], 1);
1578 if (optind
< argc
) {
1579 fprintf(stderr
, "Error: Extra parameter found.\n");
1580 print_usage(argv
[0], 1);
1583 mem_fd
= open("/dev/mem", timestamp_id
? O_RDWR
: O_RDONLY
, 0);
1585 fprintf(stderr
, "Failed to gain memory access: %s\n",
1590 #if defined(__arm__) || defined(__aarch64__)
1591 int addr_cells
, size_cells
;
1592 char *coreboot_node
= dt_find_compat("/proc/device-tree", "coreboot",
1593 &addr_cells
, &size_cells
);
1595 if (!coreboot_node
) {
1596 fprintf(stderr
, "Could not find 'coreboot' compatible node!\n");
1600 if (addr_cells
< 0) {
1601 fprintf(stderr
, "Warning: no #address-cells node in tree!\n");
1605 int nlen
= strlen(coreboot_node
);
1606 char *reg
= alloca(nlen
+ sizeof("/reg"));
1608 strcpy(reg
, coreboot_node
);
1609 strcpy(reg
+ nlen
, "/reg");
1610 free(coreboot_node
);
1612 int fd
= open(reg
, O_RDONLY
);
1619 size_t size_to_read
= addr_cells
* 4 + size_cells
* 4;
1620 u8
*dtbuffer
= alloca(size_to_read
);
1621 if (read(fd
, dtbuffer
, size_to_read
) < 0) {
1627 /* No variable-length byte swap function anywhere in C... how sad. */
1629 for (i
= 0; i
< addr_cells
* 4; i
++) {
1631 baseaddr
|= *dtbuffer
;
1634 u64 cb_table_size
= 0;
1635 for (i
= 0; i
< size_cells
* 4; i
++) {
1636 cb_table_size
<<= 8;
1637 cb_table_size
|= *dtbuffer
;
1641 parse_cbtable(baseaddr
, cb_table_size
);
1643 unsigned long long possible_base_addresses
[] = { 0, 0xf0000 };
1645 /* Find and parse coreboot table */
1646 for (size_t j
= 0; j
< ARRAY_SIZE(possible_base_addresses
); j
++) {
1647 if (!parse_cbtable(possible_base_addresses
[j
], 0))
1652 if (mapping_virt(&lbtable_mapping
) == NULL
)
1653 die("Table not found.\n");
1656 dump_console(console_type
, max_loglevel
, print_unknown_logs
);
1668 dump_cbmem_raw(rawdump_id
);
1671 timestamp_add_now(timestamp_id
);
1674 timestamp_type
= TIMESTAMPS_PRINT_NORMAL
;
1676 if (timestamp_type
!= TIMESTAMPS_PRINT_NONE
)
1677 dump_timestamps(timestamp_type
);
1682 unmap_memory(&lbtable_mapping
);