2 * This file is part of the coreboot project.
4 * Copyright 2012 Google Inc.
5 * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
27 #include <arpa/inet.h>
28 #include <sys/types.h>
34 #include <commonlib/cbmem_id.h>
35 #include <commonlib/timestamp_serialized.h>
36 #include <commonlib/tcpa_log_serialized.h>
37 #include <commonlib/coreboot_tables.h>
40 #include <sys/param.h>
41 #include <sys/sysctl.h>
44 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
51 /* Return < 0 on error, 0 on success. */
52 static int parse_cbtable(u64 address
, size_t table_size
);
58 unsigned long long phys
;
62 #define CBMEM_VERSION "1.1"
65 static int verbose
= 0;
66 #define debug(x...) if(verbose) printf(x)
68 /* File handle used to access /dev/mem */
70 static struct mapping lbtable_mapping
;
72 static void die(const char *msg
)
79 static unsigned long long system_page_size(void)
81 static unsigned long long page_size
;
84 page_size
= getpagesize();
89 static inline size_t size_to_mib(size_t sz
)
94 /* Return mapping of physical address requested. */
95 static const void *mapping_virt(const struct mapping
*mapping
)
97 const char *v
= mapping
->virt
;
102 return v
+ mapping
->offset
;
105 /* Returns virtual address on success, NULL on error. mapping is filled in. */
106 static const void *map_memory(struct mapping
*mapping
, unsigned long long phys
,
110 unsigned long long page_size
;
112 page_size
= system_page_size();
114 mapping
->virt
= NULL
;
115 mapping
->offset
= phys
% page_size
;
116 mapping
->virt_size
= sz
+ mapping
->offset
;
118 mapping
->phys
= phys
;
120 if (size_to_mib(mapping
->virt_size
) == 0) {
121 debug("Mapping %zuB of physical memory at 0x%llx (requested 0x%llx).\n",
122 mapping
->virt_size
, phys
- mapping
->offset
, phys
);
124 debug("Mapping %zuMB of physical memory at 0x%llx (requested 0x%llx).\n",
125 size_to_mib(mapping
->virt_size
), phys
- mapping
->offset
,
129 v
= mmap(NULL
, mapping
->virt_size
, PROT_READ
, MAP_SHARED
, mem_fd
,
130 phys
- mapping
->offset
);
132 if (v
== MAP_FAILED
) {
133 debug("Mapping failed %zuB of physical memory at 0x%llx.\n",
134 mapping
->virt_size
, phys
- mapping
->offset
);
140 if (mapping
->offset
!= 0)
141 debug(" ... padding virtual address with 0x%zx bytes.\n",
144 return mapping_virt(mapping
);
147 /* Returns 0 on success, < 0 on error. mapping is cleared if successful. */
148 static int unmap_memory(struct mapping
*mapping
)
150 if (mapping
->virt
== NULL
)
153 munmap(mapping
->virt
, mapping
->virt_size
);
154 mapping
->virt
= NULL
;
156 mapping
->virt_size
= 0;
161 /* Return size of physical address mapping requested. */
162 static size_t mapping_size(const struct mapping
*mapping
)
164 if (mapping
->virt
== NULL
)
167 return mapping
->size
;
171 * Some architectures map /dev/mem memory in a way that doesn't support
172 * unaligned accesses. Most normal libc memcpy()s aren't safe to use in this
173 * case, so build our own which makes sure to never do unaligned accesses on
174 * *src (*dest is fine since we never map /dev/mem for writing).
176 static void *aligned_memcpy(void *dest
, const void *src
, size_t n
)
179 const volatile u8
*s
= src
; /* volatile to prevent optimization */
181 while ((uintptr_t)s
& (sizeof(size_t) - 1)) {
187 while (n
>= sizeof(size_t)) {
188 *(size_t *)d
= *(const volatile size_t *)s
;
201 * calculate ip checksum (16 bit quantities) on a passed in buffer. In case
202 * the buffer length is odd last byte is excluded from the calculation
204 static u16
ipchcksum(const void *addr
, unsigned size
)
207 unsigned i
, n
= size
/ 2; /* don't expect odd sized blocks */
210 for (i
= 0; i
< n
; i
++)
213 sum
= (sum
>> 16) + (sum
& 0xffff);
219 /* Find the first cbmem entry filling in the details. */
220 static int find_cbmem_entry(uint32_t id
, uint64_t *addr
, size_t *size
)
222 const uint8_t *table
;
226 table
= mapping_virt(&lbtable_mapping
);
233 while (offset
< mapping_size(&lbtable_mapping
)) {
234 const struct lb_record
*lbr
;
235 const struct lb_cbmem_entry
*lbe
;
237 lbr
= (const void *)(table
+ offset
);
240 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
243 lbe
= (const void *)lbr
;
247 *addr
= lbe
->address
;
248 *size
= lbe
->entry_size
;
257 * Try finding the timestamp table and coreboot cbmem console starting from the
258 * passed in memory offset. Could be called recursively in case a forwarding
261 * Returns pointer to a memory buffer containing the timestamp table or zero if
265 static struct lb_cbmem_ref timestamps
;
266 static struct lb_cbmem_ref console
;
267 static struct lb_cbmem_ref tcpa_log
;
268 static struct lb_memory_range cbmem
;
270 /* This is a work-around for a nasty problem introduced by initially having
271 * pointer sized entries in the lb_cbmem_ref structures. This caused problems
272 * on 64bit x86 systems because coreboot is 32bit on those systems.
273 * When the problem was found, it was corrected, but there are a lot of
274 * systems out there with a firmware that does not produce the right
275 * lb_cbmem_ref structure. Hence we try to autocorrect this issue here.
277 static struct lb_cbmem_ref
parse_cbmem_ref(const struct lb_cbmem_ref
*cbmem_ref
)
279 struct lb_cbmem_ref ret
;
281 aligned_memcpy(&ret
, cbmem_ref
, sizeof(ret
));
283 if (cbmem_ref
->size
< sizeof(*cbmem_ref
))
284 ret
.cbmem_addr
= (uint32_t)ret
.cbmem_addr
;
286 debug(" cbmem_addr = %" PRIx64
"\n", ret
.cbmem_addr
);
291 static void parse_memory_tags(const struct lb_memory
*mem
)
296 /* Peel off the header size and calculate the number of entries. */
297 num_entries
= (mem
->size
- sizeof(*mem
)) / sizeof(mem
->map
[0]);
299 for (i
= 0; i
< num_entries
; i
++) {
300 if (mem
->map
[i
].type
!= LB_MEM_TABLE
)
302 debug(" LB_MEM_TABLE found.\n");
303 /* The last one found is CBMEM */
304 aligned_memcpy(&cbmem
, &mem
->map
[i
], sizeof(cbmem
));
308 /* Return < 0 on error, 0 on success, 1 if forwarding table entry found. */
309 static int parse_cbtable_entries(const struct mapping
*table_mapping
)
312 const struct lb_record
*lbr_p
;
313 size_t table_size
= mapping_size(table_mapping
);
314 const void *lbtable
= mapping_virt(table_mapping
);
315 int forwarding_table_found
= 0;
317 for (i
= 0; i
< table_size
; i
+= lbr_p
->size
) {
319 debug(" coreboot table entry 0x%02x\n", lbr_p
->tag
);
320 switch (lbr_p
->tag
) {
322 debug(" Found memory map.\n");
323 parse_memory_tags(lbtable
+ i
);
325 case LB_TAG_TIMESTAMPS
: {
326 debug(" Found timestamp table.\n");
328 parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
331 case LB_TAG_CBMEM_CONSOLE
: {
332 debug(" Found cbmem console.\n");
333 console
= parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
336 case LB_TAG_TCPA_LOG
: {
337 debug(" Found tcpa log table.\n");
339 parse_cbmem_ref((struct lb_cbmem_ref
*)lbr_p
);
342 case LB_TAG_FORWARD
: {
345 * This is a forwarding entry - repeat the
346 * search at the new address.
348 struct lb_forward lbf_p
=
349 *(const struct lb_forward
*)lbr_p
;
350 debug(" Found forwarding entry.\n");
351 ret
= parse_cbtable(lbf_p
.forward
, 0);
353 /* Assume the forwarding entry is valid. If this fails
354 * then there's a total failure. */
357 forwarding_table_found
= 1;
364 return forwarding_table_found
;
367 /* Return < 0 on error, 0 on success. */
368 static int parse_cbtable(u64 address
, size_t table_size
)
371 struct mapping header_mapping
;
375 req_size
= table_size
;
376 /* Default to 4 KiB search space. */
380 debug("Looking for coreboot table at %" PRIx64
" %zd bytes.\n",
383 buf
= map_memory(&header_mapping
, address
, req_size
);
388 /* look at every 16 bytes */
389 for (i
= 0; i
<= req_size
- sizeof(struct lb_header
); i
+= 16) {
391 const struct lb_header
*lbh
;
392 struct mapping table_mapping
;
395 if (memcmp(lbh
->signature
, "LBIO", sizeof(lbh
->signature
)) ||
396 !lbh
->header_bytes
||
397 ipchcksum(lbh
, sizeof(*lbh
))) {
401 /* Map in the whole table to parse. */
402 if (!map_memory(&table_mapping
, address
+ i
+ lbh
->header_bytes
,
404 debug("Couldn't map in table\n");
408 if (ipchcksum(mapping_virt(&table_mapping
), lbh
->table_bytes
) !=
409 lbh
->table_checksum
) {
410 debug("Signature found, but wrong checksum.\n");
411 unmap_memory(&table_mapping
);
417 ret
= parse_cbtable_entries(&table_mapping
);
419 /* Table parsing failed. */
421 unmap_memory(&table_mapping
);
425 /* Succeeded in parsing the table. Header not needed anymore. */
426 unmap_memory(&header_mapping
);
429 * Table parsing succeeded. If forwarding table not found update
430 * coreboot table mapping for future use.
433 lbtable_mapping
= table_mapping
;
435 unmap_memory(&table_mapping
);
440 unmap_memory(&header_mapping
);
445 #if defined(linux) && (defined(__i386__) || defined(__x86_64__))
447 * read CPU frequency from a sysfs file, return an frequency in Megahertz as
448 * an int or exit on any error.
450 static unsigned long arch_tick_frequency(void)
458 const char* freq_file
=
459 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
461 cpuf
= fopen(freq_file
, "r");
463 fprintf(stderr
, "Could not open %s: %s\n",
464 freq_file
, strerror(errno
));
468 memset(freqs
, 0, sizeof(freqs
));
469 size
= fread(freqs
, 1, sizeof(freqs
), cpuf
);
470 if (!size
|| (size
== sizeof(freqs
))) {
471 fprintf(stderr
, "Wrong number of bytes(%d) read from %s\n",
476 rv
= strtoull(freqs
, &endp
, 10);
478 if (*endp
== '\0' || *endp
== '\n')
479 /* cpuinfo_max_freq is in kHz. Convert it to MHz. */
481 fprintf(stderr
, "Wrong formatted value ^%s^ read from %s\n",
485 #elif defined(__OpenBSD__) && (defined(__i386__) || defined(__x86_64__))
486 static unsigned long arch_tick_frequency(void)
488 int mib
[2] = { CTL_HW
, HW_CPUSPEED
};
489 static int value
= 0;
490 size_t value_len
= sizeof(value
);
492 /* Return 1 MHz when sysctl fails. */
493 if ((value
== 0) && (sysctl(mib
, 2, &value
, &value_len
, NULL
, 0) == -1))
499 static unsigned long arch_tick_frequency(void)
506 static unsigned long tick_freq_mhz
;
508 static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz
)
510 tick_freq_mhz
= table_tick_freq_mhz
;
512 /* Honor table frequency if present. */
514 tick_freq_mhz
= arch_tick_frequency();
516 if (!tick_freq_mhz
) {
517 fprintf(stderr
, "Cannot determine timestamp tick frequency.\n");
521 debug("Timestamp tick frequency: %ld MHz\n", tick_freq_mhz
);
524 static u64
arch_convert_raw_ts_entry(u64 ts
)
526 return ts
/ tick_freq_mhz
;
530 * Print an integer in 'normalized' form - with commas separating every three
533 static void print_norm(u64 v
)
536 /* print the higher order sections first */
537 print_norm(v
/ 1000);
538 printf(",%3.3u", (u32
)(v
% 1000));
540 printf("%u", (u32
)(v
% 1000));
544 static const char *timestamp_name(uint32_t id
)
546 for (size_t i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++) {
547 if (timestamp_ids
[i
].id
== id
)
548 return timestamp_ids
[i
].name
;
553 static uint64_t timestamp_print_parseable_entry(uint32_t id
, uint64_t stamp
,
559 name
= timestamp_name(id
);
561 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
563 /* ID<tab>absolute time<tab>relative time<tab>description */
565 printf("%llu\t", (long long)arch_convert_raw_ts_entry(stamp
));
566 printf("%llu\t", (long long)step_time
);
567 printf("%s\n", name
);
572 static uint64_t timestamp_print_entry(uint32_t id
, uint64_t stamp
, uint64_t prev_stamp
)
577 name
= timestamp_name(id
);
580 printf("%-50s", name
);
581 print_norm(arch_convert_raw_ts_entry(stamp
));
582 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
585 print_norm(step_time
);
593 static int compare_timestamp_entries(const void *a
, const void *b
)
595 const struct timestamp_entry
*tse_a
= (struct timestamp_entry
*)a
;
596 const struct timestamp_entry
*tse_b
= (struct timestamp_entry
*)b
;
598 if (tse_a
->entry_stamp
> tse_b
->entry_stamp
)
600 else if (tse_a
->entry_stamp
< tse_b
->entry_stamp
)
606 /* dump the timestamp table */
607 static void dump_timestamps(int mach_readable
)
609 const struct timestamp_table
*tst_p
;
610 struct timestamp_table
*sorted_tst_p
;
614 struct mapping timestamp_mapping
;
616 if (timestamps
.tag
!= LB_TAG_TIMESTAMPS
) {
617 fprintf(stderr
, "No timestamps found in coreboot table.\n");
621 size
= sizeof(*tst_p
);
622 tst_p
= map_memory(×tamp_mapping
, timestamps
.cbmem_addr
, size
);
624 die("Unable to map timestamp header\n");
626 timestamp_set_tick_freq(tst_p
->tick_freq_mhz
);
629 printf("%d entries total:\n\n", tst_p
->num_entries
);
630 size
+= tst_p
->num_entries
* sizeof(tst_p
->entries
[0]);
632 unmap_memory(×tamp_mapping
);
634 tst_p
= map_memory(×tamp_mapping
, timestamps
.cbmem_addr
, size
);
636 die("Unable to map full timestamp table\n");
638 /* Report the base time within the table. */
641 timestamp_print_parseable_entry(0, tst_p
->base_time
,
644 timestamp_print_entry(0, tst_p
->base_time
, prev_stamp
);
645 prev_stamp
= tst_p
->base_time
;
647 sorted_tst_p
= malloc(size
);
649 die("Failed to allocate memory");
650 aligned_memcpy(sorted_tst_p
, tst_p
, size
);
652 qsort(&sorted_tst_p
->entries
[0], sorted_tst_p
->num_entries
,
653 sizeof(struct timestamp_entry
), compare_timestamp_entries
);
656 for (uint32_t i
= 0; i
< sorted_tst_p
->num_entries
; i
++) {
658 const struct timestamp_entry
*tse
= &sorted_tst_p
->entries
[i
];
660 /* Make all timestamps absolute. */
661 stamp
= tse
->entry_stamp
+ sorted_tst_p
->base_time
;
664 timestamp_print_parseable_entry(tse
->entry_id
,
667 total_time
+= timestamp_print_entry(tse
->entry_id
,
672 if (!mach_readable
) {
673 printf("\nTotal Time: ");
674 print_norm(total_time
);
678 unmap_memory(×tamp_mapping
);
682 /* dump the tcpa log table */
683 static void dump_tcpa_log(void)
685 const struct tcpa_table
*tclt_p
;
687 struct mapping tcpa_mapping
;
689 if (tcpa_log
.tag
!= LB_TAG_TCPA_LOG
) {
690 fprintf(stderr
, "No tcpa log found in coreboot table.\n");
694 size
= sizeof(*tclt_p
);
695 tclt_p
= map_memory(&tcpa_mapping
, tcpa_log
.cbmem_addr
, size
);
697 die("Unable to map tcpa log header\n");
699 size
+= tclt_p
->num_entries
* sizeof(tclt_p
->entries
[0]);
701 unmap_memory(&tcpa_mapping
);
703 tclt_p
= map_memory(&tcpa_mapping
, tcpa_log
.cbmem_addr
, size
);
705 die("Unable to map full tcpa log table\n");
707 printf("coreboot TCPA log:\n\n");
709 for (uint16_t i
= 0; i
< tclt_p
->num_entries
; i
++) {
710 const struct tcpa_entry
*tce
= &tclt_p
->entries
[i
];
712 printf(" PCR-%u ", tce
->pcr
);
714 for (uint32_t j
= 0; j
< tce
->digest_length
; j
++)
715 printf("%02x", tce
->digest
[j
]);
717 printf(" %s [%s]\n", tce
->digest_type
, tce
->name
);
720 unmap_memory(&tcpa_mapping
);
723 struct cbmem_console
{
727 } __attribute__ ((__packed__
));
729 #define CBMC_CURSOR_MASK ((1 << 28) - 1)
730 #define CBMC_OVERFLOW (1 << 31)
732 /* dump the cbmem console */
733 static void dump_console(int one_boot_only
)
735 const struct cbmem_console
*console_p
;
738 struct mapping console_mapping
;
740 if (console
.tag
!= LB_TAG_CBMEM_CONSOLE
) {
741 fprintf(stderr
, "No console found in coreboot table.\n");
745 size
= sizeof(*console_p
);
746 console_p
= map_memory(&console_mapping
, console
.cbmem_addr
, size
);
748 die("Unable to map console object.\n");
750 cursor
= console_p
->cursor
& CBMC_CURSOR_MASK
;
751 if (!(console_p
->cursor
& CBMC_OVERFLOW
) && cursor
< console_p
->size
)
754 size
= console_p
->size
;
755 unmap_memory(&console_mapping
);
757 console_c
= malloc(size
+ 1);
759 fprintf(stderr
, "Not enough memory for console.\n");
762 console_c
[size
] = '\0';
764 console_p
= map_memory(&console_mapping
, console
.cbmem_addr
,
765 size
+ sizeof(*console_p
));
768 die("Unable to map full console object.\n");
770 if (console_p
->cursor
& CBMC_OVERFLOW
) {
771 if (cursor
>= size
) {
772 printf("cbmem: ERROR: CBMEM console struct is illegal, "
773 "output may be corrupt or out of order!\n\n");
776 aligned_memcpy(console_c
, console_p
->body
+ cursor
,
778 aligned_memcpy(console_c
+ size
- cursor
,
779 console_p
->body
, cursor
);
781 aligned_memcpy(console_c
, console_p
->body
, size
);
784 /* Slight memory corruption may occur between reboots and give us a few
785 unprintable characters like '\0'. Replace them with '?' on output. */
786 for (cursor
= 0; cursor
< size
; cursor
++)
787 if (!isprint(console_c
[cursor
]) && !isspace(console_c
[cursor
]))
788 console_c
[cursor
] = '?';
790 /* We detect the last boot by looking for a bootblock, romstage or
791 ramstage banner, in that order (to account for platforms without
792 CONFIG_BOOTBLOCK_CONSOLE and/or CONFIG_EARLY_CONSOLE). Once we find
793 a banner, store the last match for that stage in cursor and stop. */
796 #define BANNER_REGEX(stage) \
797 "\n\ncoreboot-[^\n]* " stage " starting.*\\.\\.\\.\n"
798 #define OVERFLOW_REGEX(stage) "\n\\*\\*\\* Pre-CBMEM " stage " console overflow"
799 const char *regex
[] = { BANNER_REGEX("bootblock"),
800 BANNER_REGEX("verstage"),
801 OVERFLOW_REGEX("romstage"),
802 BANNER_REGEX("romstage"),
803 OVERFLOW_REGEX("ramstage"),
804 BANNER_REGEX("ramstage") };
806 for (size_t i
= 0; !cursor
&& i
< ARRAY_SIZE(regex
); i
++) {
809 assert(!regcomp(&re
, regex
[i
], 0));
811 /* Keep looking for matches so we find the last one. */
812 while (!regexec(&re
, console_c
+ cursor
, 1, &match
, 0))
813 cursor
+= match
.rm_so
+ 1;
818 puts(console_c
+ cursor
);
820 unmap_memory(&console_mapping
);
823 static void hexdump(unsigned long memory
, int length
)
828 struct mapping hexdump_mapping
;
830 m
= map_memory(&hexdump_mapping
, memory
, length
);
832 die("Unable to map hexdump memory.\n");
834 for (i
= 0; i
< length
; i
+= 16) {
838 for (j
= 0; j
< 16; j
++) {
846 printf("%08lx:", memory
+ i
);
847 for (j
= 0; j
< 16; j
++)
848 printf(" %02x", m
[i
+j
]);
850 for (j
= 0; j
< 16; j
++)
851 printf("%c", isprint(m
[i
+j
]) ? m
[i
+j
] : '.');
853 } else if (all_zero
== 2) {
858 unmap_memory(&hexdump_mapping
);
861 static void dump_cbmem_hex(void)
863 if (cbmem
.type
!= LB_MEM_TABLE
) {
864 fprintf(stderr
, "No coreboot CBMEM area found!\n");
868 hexdump(unpack_lb64(cbmem
.start
), unpack_lb64(cbmem
.size
));
871 static void rawdump(uint64_t base
, uint64_t size
)
874 struct mapping dump_mapping
;
876 m
= map_memory(&dump_mapping
, base
, size
);
878 die("Unable to map rawdump memory\n");
880 for (uint64_t i
= 0 ; i
< size
; i
++)
883 unmap_memory(&dump_mapping
);
886 static void dump_cbmem_raw(unsigned int id
)
888 const uint8_t *table
;
893 table
= mapping_virt(&lbtable_mapping
);
900 while (offset
< mapping_size(&lbtable_mapping
)) {
901 const struct lb_record
*lbr
;
902 const struct lb_cbmem_entry
*lbe
;
904 lbr
= (const void *)(table
+ offset
);
907 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
910 lbe
= (const void *)lbr
;
912 debug("found id for raw dump %0x", lbe
->id
);
914 size
= lbe
->entry_size
;
920 fprintf(stderr
, "id %0x not found in cbtable\n", id
);
925 struct cbmem_id_to_name
{
929 static const struct cbmem_id_to_name cbmem_ids
[] = { CBMEM_ID_TO_NAME_TABLE
};
931 #define MAX_STAGEx 10
932 static void cbmem_print_entry(int n
, uint32_t id
, uint64_t base
, uint64_t size
)
938 for (size_t i
= 0; i
< ARRAY_SIZE(cbmem_ids
); i
++) {
939 if (cbmem_ids
[i
].id
== id
) {
940 name
= cbmem_ids
[i
].name
;
943 if (id
>= CBMEM_ID_STAGEx_META
&&
944 id
< CBMEM_ID_STAGEx_META
+ MAX_STAGEx
) {
945 snprintf(stage_x
, sizeof(stage_x
), "STAGE%d META",
946 (id
- CBMEM_ID_STAGEx_META
));
949 if (id
>= CBMEM_ID_STAGEx_CACHE
&&
950 id
< CBMEM_ID_STAGEx_CACHE
+ MAX_STAGEx
) {
951 snprintf(stage_x
, sizeof(stage_x
), "STAGE%d $ ",
952 (id
- CBMEM_ID_STAGEx_CACHE
));
959 printf("\t\t%08x", id
);
961 printf("%s\t%08x", name
, id
);
962 printf(" %08" PRIx64
" ", base
);
963 printf(" %08" PRIx64
"\n", size
);
966 static void dump_cbmem_toc(void)
969 const uint8_t *table
;
972 table
= mapping_virt(&lbtable_mapping
);
977 printf("CBMEM table of contents:\n");
978 printf(" NAME ID START LENGTH\n");
983 while (offset
< mapping_size(&lbtable_mapping
)) {
984 const struct lb_record
*lbr
;
985 const struct lb_cbmem_entry
*lbe
;
987 lbr
= (const void *)(table
+ offset
);
990 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
993 lbe
= (const void *)lbr
;
994 cbmem_print_entry(i
, lbe
->id
, lbe
->address
, lbe
->entry_size
);
999 #define COVERAGE_MAGIC 0x584d4153
1009 static int mkpath(char *path
, mode_t mode
)
1011 assert (path
&& *path
);
1013 for (p
= strchr(path
+1, '/'); p
; p
= strchr(p
+ 1, '/')) {
1015 if (mkdir(path
, mode
) == -1) {
1016 if (errno
!= EEXIST
) {
1026 static void dump_coverage(void)
1030 const void *coverage
;
1031 struct mapping coverage_mapping
;
1032 unsigned long phys_offset
;
1033 #define phys_to_virt(x) ((void *)(unsigned long)(x) + phys_offset)
1035 if (find_cbmem_entry(CBMEM_ID_COVERAGE
, &start
, &size
)) {
1036 fprintf(stderr
, "No coverage information found\n");
1040 /* Map coverage area */
1041 coverage
= map_memory(&coverage_mapping
, start
, size
);
1043 die("Unable to map coverage area.\n");
1044 phys_offset
= (unsigned long)coverage
- (unsigned long)start
;
1046 printf("Dumping coverage data...\n");
1048 struct file
*file
= (struct file
*)coverage
;
1049 while (file
&& file
->magic
== COVERAGE_MAGIC
) {
1053 debug(" -> %s\n", (char *)phys_to_virt(file
->filename
));
1054 filename
= strdup((char *)phys_to_virt(file
->filename
));
1055 if (mkpath(filename
, 0755) == -1) {
1056 perror("Directory for coverage data could "
1060 f
= fopen(filename
, "wb");
1062 printf("Could not open %s: %s\n",
1063 filename
, strerror(errno
));
1066 if (fwrite((void *)phys_to_virt(file
->data
),
1067 file
->len
, 1, f
) != 1) {
1068 printf("Could not write to %s: %s\n",
1069 filename
, strerror(errno
));
1076 file
= (struct file
*)phys_to_virt(file
->next
);
1080 unmap_memory(&coverage_mapping
);
1083 static void print_version(void)
1085 printf("cbmem v%s -- ", CBMEM_VERSION
);
1086 printf("Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.\n\n");
1088 "This program is free software: you can redistribute it and/or modify\n"
1089 "it under the terms of the GNU General Public License as published by\n"
1090 "the Free Software Foundation, version 2 of the License.\n\n"
1091 "This program is distributed in the hope that it will be useful,\n"
1092 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1093 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1094 "GNU General Public License for more details.\n\n");
1097 static void print_usage(const char *name
, int exit_code
)
1099 printf("usage: %s [-cCltTLxVvh?]\n", name
);
1101 " -c | --console: print cbmem console\n"
1102 " -1 | --oneboot: print cbmem console for last boot only\n"
1103 " -C | --coverage: dump coverage information\n"
1104 " -l | --list: print cbmem table of contents\n"
1105 " -x | --hexdump: print hexdump of cbmem area\n"
1106 " -r | --rawdump ID: print rawdump of specific ID (in hex) of cbtable\n"
1107 " -t | --timestamps: print timestamp information\n"
1108 " -T | --parseable-timestamps: print parseable timestamps\n"
1109 " -L | --tcpa-log print TCPA log\n"
1110 " -V | --verbose: verbose (debugging) output\n"
1111 " -v | --version: print the version\n"
1112 " -h | --help: print this help\n"
1117 #if defined(__arm__) || defined(__aarch64__)
1118 static void dt_update_cells(const char *name
, int *addr_cells_ptr
,
1119 int *size_cells_ptr
)
1121 if (*addr_cells_ptr
>= 0 && *size_cells_ptr
>= 0)
1125 size_t nlen
= strlen(name
);
1126 char *prop
= alloca(nlen
+ sizeof("/#address-cells"));
1129 if (*addr_cells_ptr
< 0) {
1130 strcpy(prop
+ nlen
, "/#address-cells");
1131 int fd
= open(prop
, O_RDONLY
);
1132 if (fd
< 0 && errno
!= ENOENT
) {
1134 } else if (fd
>= 0) {
1135 if (read(fd
, &buffer
, sizeof(int)) < 0)
1138 *addr_cells_ptr
= ntohl(buffer
);
1143 if (*size_cells_ptr
< 0) {
1144 strcpy(prop
+ nlen
, "/#size-cells");
1145 int fd
= open(prop
, O_RDONLY
);
1146 if (fd
< 0 && errno
!= ENOENT
) {
1148 } else if (fd
>= 0) {
1149 if (read(fd
, &buffer
, sizeof(int)) < 0)
1152 *size_cells_ptr
= ntohl(buffer
);
1158 static char *dt_find_compat(const char *parent
, const char *compat
,
1159 int *addr_cells_ptr
, int *size_cells_ptr
)
1162 struct dirent
*entry
;
1165 if (!(dir
= opendir(parent
))) {
1170 /* Loop through all files in the directory (DT node). */
1171 while ((entry
= readdir(dir
))) {
1172 /* We only care about compatible props or subnodes. */
1173 if (entry
->d_name
[0] == '.' || !((entry
->d_type
& DT_DIR
) ||
1174 !strcmp(entry
->d_name
, "compatible")))
1177 /* Assemble the file name (on the stack, for speed). */
1178 size_t plen
= strlen(parent
);
1179 char *name
= alloca(plen
+ strlen(entry
->d_name
) + 2);
1181 strcpy(name
, parent
);
1183 strcpy(name
+ plen
+ 1, entry
->d_name
);
1185 /* If it's a subnode, recurse. */
1186 if (entry
->d_type
& DT_DIR
) {
1187 ret
= dt_find_compat(name
, compat
, addr_cells_ptr
,
1190 /* There is only one matching node to find, abort. */
1192 /* Gather cells values on the way up. */
1193 dt_update_cells(parent
, addr_cells_ptr
,
1200 /* If it's a compatible string, see if it's the right one. */
1201 int fd
= open(name
, O_RDONLY
);
1202 int clen
= strlen(compat
);
1203 char *buffer
= alloca(clen
+ 1);
1210 if (read(fd
, buffer
, clen
+ 1) < 0) {
1217 if (!strcmp(compat
, buffer
)) {
1218 /* Initialize these to "unset" for the way up. */
1219 *addr_cells_ptr
= *size_cells_ptr
= -1;
1221 /* Can't leave string on the stack or we'll lose it! */
1222 ret
= strdup(parent
);
1230 #endif /* defined(__arm__) || defined(__aarch64__) */
1232 int main(int argc
, char** argv
)
1234 int print_defaults
= 1;
1235 int print_console
= 0;
1236 int print_coverage
= 0;
1238 int print_hexdump
= 0;
1239 int print_rawdump
= 0;
1240 int print_timestamps
= 0;
1241 int print_tcpa_log
= 0;
1242 int machine_readable_timestamps
= 0;
1243 int one_boot_only
= 0;
1244 unsigned int rawdump_id
= 0;
1246 int opt
, option_index
= 0;
1247 static struct option long_options
[] = {
1248 {"console", 0, 0, 'c'},
1249 {"oneboot", 0, 0, '1'},
1250 {"coverage", 0, 0, 'C'},
1251 {"list", 0, 0, 'l'},
1252 {"tcpa-log", 0, 0, 'L'},
1253 {"timestamps", 0, 0, 't'},
1254 {"parseable-timestamps", 0, 0, 'T'},
1255 {"hexdump", 0, 0, 'x'},
1256 {"rawdump", required_argument
, 0, 'r'},
1257 {"verbose", 0, 0, 'V'},
1258 {"version", 0, 0, 'v'},
1259 {"help", 0, 0, 'h'},
1262 while ((opt
= getopt_long(argc
, argv
, "c1CltTLxVvh?r:",
1263 long_options
, &option_index
)) != EOF
) {
1293 rawdump_id
= strtoul(optarg
, NULL
, 16);
1296 print_timestamps
= 1;
1300 print_timestamps
= 1;
1301 machine_readable_timestamps
= 1;
1312 print_usage(argv
[0], 0);
1316 print_usage(argv
[0], 1);
1321 if (optind
< argc
) {
1322 fprintf(stderr
, "Error: Extra parameter found.\n");
1323 print_usage(argv
[0], 1);
1326 mem_fd
= open("/dev/mem", O_RDONLY
, 0);
1328 fprintf(stderr
, "Failed to gain memory access: %s\n",
1333 #if defined(__arm__) || defined(__aarch64__)
1334 int addr_cells
, size_cells
;
1335 char *coreboot_node
= dt_find_compat("/proc/device-tree", "coreboot",
1336 &addr_cells
, &size_cells
);
1338 if (!coreboot_node
) {
1339 fprintf(stderr
, "Could not find 'coreboot' compatible node!\n");
1343 if (addr_cells
< 0) {
1344 fprintf(stderr
, "Warning: no #address-cells node in tree!\n");
1348 int nlen
= strlen(coreboot_node
);
1349 char *reg
= alloca(nlen
+ sizeof("/reg"));
1351 strcpy(reg
, coreboot_node
);
1352 strcpy(reg
+ nlen
, "/reg");
1353 free(coreboot_node
);
1355 int fd
= open(reg
, O_RDONLY
);
1362 size_t size_to_read
= addr_cells
* 4 + size_cells
* 4;
1363 u8
*dtbuffer
= alloca(size_to_read
);
1364 if (read(fd
, dtbuffer
, size_to_read
) < 0) {
1370 /* No variable-length byte swap function anywhere in C... how sad. */
1372 for (i
= 0; i
< addr_cells
* 4; i
++) {
1374 baseaddr
|= *dtbuffer
;
1377 u64 cb_table_size
= 0;
1378 for (i
= 0; i
< size_cells
* 4; i
++) {
1379 cb_table_size
<<= 8;
1380 cb_table_size
|= *dtbuffer
;
1384 parse_cbtable(baseaddr
, cb_table_size
);
1386 unsigned long long possible_base_addresses
[] = { 0, 0xf0000 };
1388 /* Find and parse coreboot table */
1389 for (size_t j
= 0; j
< ARRAY_SIZE(possible_base_addresses
); j
++) {
1390 if (!parse_cbtable(possible_base_addresses
[j
], 0))
1395 if (mapping_virt(&lbtable_mapping
) == NULL
)
1396 die("Table not found.\n");
1399 dump_console(one_boot_only
);
1411 dump_cbmem_raw(rawdump_id
);
1413 if (print_defaults
|| print_timestamps
)
1414 dump_timestamps(machine_readable_timestamps
);
1419 unmap_memory(&lbtable_mapping
);