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.
28 #include <arpa/inet.h>
29 #include <sys/types.h>
34 #include <commonlib/cbmem_id.h>
35 #include <commonlib/timestamp_serialized.h>
36 #include <commonlib/coreboot_tables.h>
39 #include <sys/param.h>
40 #include <sys/sysctl.h>
43 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
44 #define MAP_BYTES (1024*1024)
51 #define CBMEM_VERSION "1.1"
54 static int verbose
= 0;
55 #define debug(x...) if(verbose) printf(x)
57 /* File handle used to access /dev/mem */
60 static uint64_t lbtable_address
;
61 static size_t lbtable_size
;
64 * calculate ip checksum (16 bit quantities) on a passed in buffer. In case
65 * the buffer length is odd last byte is excluded from the calculation
67 static u16
ipchcksum(const void *addr
, unsigned size
)
70 unsigned i
, n
= size
/ 2; /* don't expect odd sized blocks */
73 for (i
= 0; i
< n
; i
++)
76 sum
= (sum
>> 16) + (sum
& 0xffff);
83 * Functions to map / unmap physical memory into virtual address space. These
84 * functions always maps 1MB at a time and can only map one area at once.
86 static void *mapped_virtual
;
87 static size_t mapped_size
;
89 static inline size_t size_to_mib(size_t sz
)
94 static void unmap_memory(void)
96 if (mapped_virtual
== NULL
) {
97 fprintf(stderr
, "Error unmapping memory\n");
100 if (size_to_mib(mapped_size
) == 0) {
101 debug("Unmapping %zuMB of virtual memory at %p.\n",
102 size_to_mib(mapped_size
), mapped_virtual
);
104 debug("Unmapping %zuMB of virtual memory at %p.\n",
105 size_to_mib(mapped_size
), mapped_virtual
);
107 munmap(mapped_virtual
, mapped_size
);
108 mapped_virtual
= NULL
;
112 static void *map_memory_size(u64 physical
, size_t size
, uint8_t abort_on_failure
)
116 u64 page
= getpagesize();
119 if (mapped_virtual
!= NULL
)
122 /* Mapped memory must be aligned to page size */
123 p
= physical
& ~(page
- 1);
124 padding
= physical
& (page
-1);
127 if (size_to_mib(size
) == 0) {
128 debug("Mapping %zuB of physical memory at 0x%jx (requested 0x%jx).\n",
129 size
, (intmax_t)p
, (intmax_t)physical
);
131 debug("Mapping %zuMB of physical memory at 0x%jx (requested 0x%jx).\n",
132 size_to_mib(size
), (intmax_t)p
, (intmax_t)physical
);
135 v
= mmap(NULL
, size
, PROT_READ
, MAP_SHARED
, mem_fd
, p
);
137 if (v
== MAP_FAILED
) {
138 /* The mapped area may have overrun the upper cbmem boundary when trying to
139 * align to the page size. Try growing down instead of up...
144 size
= size
+ (page
- 1);
145 v
= mmap(NULL
, size
, PROT_READ
, MAP_SHARED
, mem_fd
, p
);
146 debug(" ... failed. Mapping %zuB of physical memory at 0x%jx.\n",
150 if (v
== MAP_FAILED
) {
151 if (abort_on_failure
) {
152 fprintf(stderr
, "Failed to mmap /dev/mem: %s\n",
160 /* Remember what we actually mapped ... */
164 /* ... but return address to the physical memory that was requested */
166 debug(" ... padding virtual address with 0x%zx bytes.\n",
173 static void *map_lbtable(void)
175 if (lbtable_address
== 0 || lbtable_size
== 0) {
176 fprintf(stderr
, "No coreboot table area found!\n");
180 return map_memory_size(lbtable_address
, lbtable_size
, 1);
183 static void unmap_lbtable(void)
188 /* Find the first cbmem entry filling in the details. */
189 static int find_cbmem_entry(uint32_t id
, uint64_t *addr
, size_t *size
)
195 table
= map_lbtable();
202 while (offset
< lbtable_size
) {
203 struct lb_record
*lbr
;
204 struct lb_cbmem_entry
*lbe
;
206 lbr
= (void *)(table
+ offset
);
209 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
216 *addr
= lbe
->address
;
217 *size
= lbe
->entry_size
;
227 * Try finding the timestamp table and coreboot cbmem console starting from the
228 * passed in memory offset. Could be called recursively in case a forwarding
231 * Returns pointer to a memory buffer containg the timestamp table or zero if
235 static struct lb_cbmem_ref timestamps
;
236 static struct lb_cbmem_ref console
;
237 static struct lb_memory_range cbmem
;
239 /* This is a work-around for a nasty problem introduced by initially having
240 * pointer sized entries in the lb_cbmem_ref structures. This caused problems
241 * on 64bit x86 systems because coreboot is 32bit on those systems.
242 * When the problem was found, it was corrected, but there are a lot of
243 * systems out there with a firmware that does not produce the right
244 * lb_cbmem_ref structure. Hence we try to autocorrect this issue here.
246 static struct lb_cbmem_ref
parse_cbmem_ref(struct lb_cbmem_ref
*cbmem_ref
)
248 struct lb_cbmem_ref ret
;
252 if (cbmem_ref
->size
< sizeof(*cbmem_ref
))
253 ret
.cbmem_addr
= (uint32_t)ret
.cbmem_addr
;
255 debug(" cbmem_addr = %" PRIx64
"\n", ret
.cbmem_addr
);
260 static int parse_cbtable(u64 address
, size_t table_size
, uint8_t abort_on_failure
)
262 int i
, found
, ret
= 0;
265 debug("Looking for coreboot table at %" PRIx64
" %zd bytes.\n",
266 address
, table_size
);
267 buf
= map_memory_size(address
, table_size
, abort_on_failure
);
271 /* look at every 16 bytes within 4K of the base */
273 for (i
= 0; i
< 0x1000; i
+= 0x10) {
274 struct lb_header
*lbh
;
275 struct lb_record
* lbr_p
;
279 lbh
= (struct lb_header
*)(buf
+ i
);
280 if (memcmp(lbh
->signature
, "LBIO", sizeof(lbh
->signature
)) ||
281 !lbh
->header_bytes
||
282 ipchcksum(lbh
, sizeof(*lbh
))) {
285 lbtable
= buf
+ i
+ lbh
->header_bytes
;
287 if (ipchcksum(lbtable
, lbh
->table_bytes
) !=
288 lbh
->table_checksum
) {
289 debug("Signature found, but wrong checksum.\n");
296 /* Keep reference to lbtable. */
297 lbtable_address
= address
;
298 lbtable_address
+= ((uint8_t *)lbtable
- (uint8_t *)lbh
);
299 lbtable_size
= lbh
->table_bytes
;
301 for (j
= 0; j
< lbh
->table_bytes
; j
+= lbr_p
->size
) {
302 lbr_p
= (struct lb_record
*) ((char *)lbtable
+ j
);
303 debug(" coreboot table entry 0x%02x\n", lbr_p
->tag
);
304 switch (lbr_p
->tag
) {
305 case LB_TAG_MEMORY
: {
307 debug(" Found memory map.\n");
308 struct lb_memory
*memory
=
309 (struct lb_memory
*)lbr_p
;
310 while ((char *)&memory
->map
[i
] < ((char *)lbr_p
312 if (memory
->map
[i
].type
== LB_MEM_TABLE
) {
313 debug(" LB_MEM_TABLE found.\n");
314 /* The last one found is CBMEM */
315 cbmem
= memory
->map
[i
];
321 case LB_TAG_TIMESTAMPS
: {
322 debug(" Found timestamp table.\n");
323 timestamps
= parse_cbmem_ref((struct lb_cbmem_ref
*) lbr_p
);
326 case LB_TAG_CBMEM_CONSOLE
: {
327 debug(" Found cbmem console.\n");
328 console
= parse_cbmem_ref((struct lb_cbmem_ref
*) lbr_p
);
331 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 *(struct lb_forward
*) lbr_p
;
338 debug(" Found forwarding entry.\n");
340 ret
= parse_cbtable(lbf_p
.forward
, table_size
, 0);
342 /* try again with a smaller memory mapping request */
343 ret
= parse_cbtable(lbf_p
.forward
, table_size
/ 2, 1);
363 #if defined(linux) && (defined(__i386__) || defined(__x86_64__))
365 * read CPU frequency from a sysfs file, return an frequency in Kilohertz as
366 * an int or exit on any error.
368 static unsigned long arch_tick_frequency(void)
376 const char* freq_file
=
377 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
379 cpuf
= fopen(freq_file
, "r");
381 fprintf(stderr
, "Could not open %s: %s\n",
382 freq_file
, strerror(errno
));
386 memset(freqs
, 0, sizeof(freqs
));
387 size
= fread(freqs
, 1, sizeof(freqs
), cpuf
);
388 if (!size
|| (size
== sizeof(freqs
))) {
389 fprintf(stderr
, "Wrong number of bytes(%d) read from %s\n",
394 rv
= strtoull(freqs
, &endp
, 10);
396 if (*endp
== '\0' || *endp
== '\n')
398 fprintf(stderr
, "Wrong formatted value ^%s^ read from %s\n",
402 #elif defined(__OpenBSD__) && (defined(__i386__) || defined(__x86_64__))
403 static unsigned long arch_tick_frequency(void)
405 int mib
[2] = { CTL_HW
, HW_CPUSPEED
};
406 static int value
= 0;
407 size_t value_len
= sizeof(value
);
409 /* Return 1 MHz when sysctl fails. */
410 if ((value
== 0) && (sysctl(mib
, 2, &value
, &value_len
, NULL
, 0) == -1))
416 static unsigned long arch_tick_frequency(void)
423 static unsigned long tick_freq_mhz
;
425 static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz
)
427 tick_freq_mhz
= table_tick_freq_mhz
;
429 /* Honor table frequency. */
433 tick_freq_mhz
= arch_tick_frequency();
435 if (!tick_freq_mhz
) {
436 fprintf(stderr
, "Cannot determine timestamp tick frequency.\n");
441 u64
arch_convert_raw_ts_entry(u64 ts
)
443 return ts
/ tick_freq_mhz
;
447 * Print an integer in 'normalized' form - with commas separating every three
450 static void print_norm(u64 v
)
453 /* print the higher order sections first */
454 print_norm(v
/ 1000);
455 printf(",%3.3u", (u32
)(v
% 1000));
457 printf("%u", (u32
)(v
% 1000));
461 enum additional_timestamp_id
{
462 // Depthcharge entry IDs start at 1000.
465 TS_RO_PARAMS_INIT
= 1001,
466 TS_RO_VB_INIT
= 1002,
467 TS_RO_VB_SELECT_FIRMWARE
= 1003,
468 TS_RO_VB_SELECT_AND_LOAD_KERNEL
= 1004,
470 TS_RW_VB_SELECT_AND_LOAD_KERNEL
= 1010,
472 TS_VB_SELECT_AND_LOAD_KERNEL
= 1020,
474 TS_VB_EC_VBOOT_DONE
= 1030,
476 TS_CROSSYSTEM_DATA
= 1100,
477 TS_START_KERNEL
= 1101
480 static const struct timestamp_id_to_name
{
483 } timestamp_ids
[] = {
484 /* Marker to report base_time. */
485 { 0, "1st timestamp" },
486 { TS_START_ROMSTAGE
, "start of rom stage" },
487 { TS_BEFORE_INITRAM
, "before ram initialization" },
488 { TS_AFTER_INITRAM
, "after ram initialization" },
489 { TS_END_ROMSTAGE
, "end of romstage" },
490 { TS_START_VBOOT
, "start of verified boot" },
491 { TS_END_VBOOT
, "end of verified boot" },
492 { TS_START_COPYRAM
, "starting to load ramstage" },
493 { TS_END_COPYRAM
, "finished loading ramstage" },
494 { TS_START_RAMSTAGE
, "start of ramstage" },
495 { TS_START_BOOTBLOCK
, "start of bootblock" },
496 { TS_END_BOOTBLOCK
, "end of bootblock" },
497 { TS_START_COPYROM
, "starting to load romstage" },
498 { TS_END_COPYROM
, "finished loading romstage" },
499 { TS_START_ULZMA
, "starting LZMA decompress (ignore for x86)" },
500 { TS_END_ULZMA
, "finished LZMA decompress (ignore for x86)" },
501 { TS_DEVICE_ENUMERATE
, "device enumeration" },
502 { TS_DEVICE_CONFIGURE
, "device configuration" },
503 { TS_DEVICE_ENABLE
, "device enable" },
504 { TS_DEVICE_INITIALIZE
, "device initialization" },
505 { TS_DEVICE_DONE
, "device setup done" },
506 { TS_CBMEM_POST
, "cbmem post" },
507 { TS_WRITE_TABLES
, "write tables" },
508 { TS_LOAD_PAYLOAD
, "load payload" },
509 { TS_ACPI_WAKE_JUMP
, "ACPI wake jump" },
510 { TS_SELFBOOT_JUMP
, "selfboot jump" },
512 { TS_START_COPYVER
, "starting to load verstage" },
513 { TS_END_COPYVER
, "finished loading verstage" },
514 { TS_START_TPMINIT
, "starting to initialize TPM" },
515 { TS_END_TPMINIT
, "finished TPM initialization" },
516 { TS_START_VERIFY_SLOT
, "starting to verify keyblock/preamble (RSA)" },
517 { TS_END_VERIFY_SLOT
, "finished verifying keyblock/preamble (RSA)" },
518 { TS_START_HASH_BODY
, "starting to verify body (load+SHA2+RSA) " },
519 { TS_DONE_LOADING
, "finished loading body (ignore for x86)" },
520 { TS_DONE_HASHING
, "finished calculating body hash (SHA2)" },
521 { TS_END_HASH_BODY
, "finished verifying body signature (RSA)" },
523 { TS_DC_START
, "depthcharge start" },
524 { TS_RO_PARAMS_INIT
, "RO parameter init" },
525 { TS_RO_VB_INIT
, "RO vboot init" },
526 { TS_RO_VB_SELECT_FIRMWARE
, "RO vboot select firmware" },
527 { TS_RO_VB_SELECT_AND_LOAD_KERNEL
, "RO vboot select&load kernel" },
528 { TS_RW_VB_SELECT_AND_LOAD_KERNEL
, "RW vboot select&load kernel" },
529 { TS_VB_SELECT_AND_LOAD_KERNEL
, "vboot select&load kernel" },
530 { TS_VB_EC_VBOOT_DONE
, "finished EC verification" },
531 { TS_CROSSYSTEM_DATA
, "crossystem data" },
532 { TS_START_KERNEL
, "start kernel" },
534 /* FSP related timestamps */
535 { TS_FSP_MEMORY_INIT_START
, "calling FspMemoryInit" },
536 { TS_FSP_MEMORY_INIT_END
, "returning from FspMemoryInit" },
537 { TS_FSP_TEMP_RAM_EXIT_START
, "calling FspTempRamExit" },
538 { TS_FSP_TEMP_RAM_EXIT_END
, "returning from FspTempRamExit" },
539 { TS_FSP_SILICON_INIT_START
, "calling FspSiliconInit" },
540 { TS_FSP_SILICON_INIT_END
, "returning from FspSiliconInit" },
541 { TS_FSP_BEFORE_ENUMERATE
, "calling FspNotify(AfterPciEnumeration)" },
542 { TS_FSP_AFTER_ENUMERATE
,
543 "returning from FspNotify(AfterPciEnumeration)" },
544 { TS_FSP_BEFORE_FINALIZE
, "calling FspNotify(ReadyToBoot)" },
545 { TS_FSP_AFTER_FINALIZE
, "returning from FspNotify(ReadyToBoot)" }
548 static const char *timestamp_name(uint32_t id
)
552 for (i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++) {
553 if (timestamp_ids
[i
].id
== id
)
554 return timestamp_ids
[i
].name
;
559 static uint64_t timestamp_print_parseable_entry(uint32_t id
, uint64_t stamp
,
565 name
= timestamp_name(id
);
567 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
569 /* ID<tab>absolute time<tab>relative time<tab>description */
571 printf("%llu\t", (long long)arch_convert_raw_ts_entry(stamp
));
572 printf("%llu\t", (long long)step_time
);
573 printf("%s\n", name
);
578 uint64_t timestamp_print_entry(uint32_t id
, uint64_t stamp
, uint64_t prev_stamp
)
583 name
= timestamp_name(id
);
586 printf("%-50s", name
);
587 print_norm(arch_convert_raw_ts_entry(stamp
));
588 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
591 print_norm(step_time
);
599 /* dump the timestamp table */
600 static void dump_timestamps(int mach_readable
)
603 struct timestamp_table
*tst_p
;
608 if (timestamps
.tag
!= LB_TAG_TIMESTAMPS
) {
609 fprintf(stderr
, "No timestamps found in coreboot table.\n");
613 size
= sizeof(*tst_p
);
614 tst_p
= map_memory_size((unsigned long)timestamps
.cbmem_addr
, size
, 1);
616 timestamp_set_tick_freq(tst_p
->tick_freq_mhz
);
619 printf("%d entries total:\n\n", tst_p
->num_entries
);
620 size
+= tst_p
->num_entries
* sizeof(tst_p
->entries
[0]);
623 tst_p
= map_memory_size((unsigned long)timestamps
.cbmem_addr
, size
, 1);
625 /* Report the base time within the table. */
628 timestamp_print_parseable_entry(0, tst_p
->base_time
,
631 timestamp_print_entry(0, tst_p
->base_time
, prev_stamp
);
632 prev_stamp
= tst_p
->base_time
;
635 for (i
= 0; i
< tst_p
->num_entries
; i
++) {
637 const struct timestamp_entry
*tse
= &tst_p
->entries
[i
];
639 /* Make all timestamps absolute. */
640 stamp
= tse
->entry_stamp
+ tst_p
->base_time
;
643 timestamp_print_parseable_entry(tse
->entry_id
,
646 total_time
+= timestamp_print_entry(tse
->entry_id
,
651 if (!mach_readable
) {
652 printf("\nTotal Time: ");
653 print_norm(total_time
);
660 /* dump the cbmem console */
661 static void dump_console(void)
668 if (console
.tag
!= LB_TAG_CBMEM_CONSOLE
) {
669 fprintf(stderr
, "No console found in coreboot table.\n");
673 console_p
= map_memory_size((unsigned long)console
.cbmem_addr
,
674 2 * sizeof(uint32_t), 1);
675 /* The in-memory format of the console area is:
679 * Hence we have to add 8 to get to the actual console string.
681 size
= ((uint32_t *)console_p
)[0];
682 cursor
= ((uint32_t *)console_p
)[1];
683 /* Cursor continues to go on even after no more data fits in
684 * the buffer but the data is dropped in this case.
688 console_c
= calloc(1, size
+ 1);
691 fprintf(stderr
, "Not enough memory for console.\n");
695 console_p
= map_memory_size((unsigned long)console
.cbmem_addr
,
696 size
+ sizeof(size
) + sizeof(cursor
), 1);
697 memcpy(console_c
, console_p
+ 8, size
);
699 printf("%s\n", console_c
);
701 printf("%d %s lost\n", cursor
- size
,
702 (cursor
- size
) == 1 ? "byte":"bytes");
709 static void hexdump(unsigned long memory
, int length
)
715 m
= map_memory_size((intptr_t)memory
, length
, 1);
717 if (length
> MAP_BYTES
) {
718 printf("Truncating hex dump from %d to %d bytes\n\n",
723 for (i
= 0; i
< length
; i
+= 16) {
727 for (j
= 0; j
< 16; j
++) {
735 printf("%08lx:", memory
+ i
);
736 for (j
= 0; j
< 16; j
++)
737 printf(" %02x", m
[i
+j
]);
739 for (j
= 0; j
< 16; j
++)
740 printf("%c", isprint(m
[i
+j
]) ? m
[i
+j
] : '.');
742 } else if (all_zero
== 2) {
750 static void dump_cbmem_hex(void)
752 if (cbmem
.type
!= LB_MEM_TABLE
) {
753 fprintf(stderr
, "No coreboot CBMEM area found!\n");
757 hexdump(unpack_lb64(cbmem
.start
), unpack_lb64(cbmem
.size
));
760 void rawdump(uint64_t base
, uint64_t size
)
765 m
= map_memory_size((intptr_t)base
, size
, 1);
767 fprintf(stderr
, "Failed to map memory");
771 for (i
= 0 ; i
< size
; i
++)
776 static void dump_cbmem_raw(unsigned int id
)
783 table
= map_lbtable();
790 while (offset
< lbtable_size
) {
791 struct lb_record
*lbr
;
792 struct lb_cbmem_entry
*lbe
;
794 lbr
= (void *)(table
+ offset
);
797 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
802 debug("found id for raw dump %0x", lbe
->id
);
804 size
= lbe
->entry_size
;
812 fprintf(stderr
, "id %0x not found in cbtable\n", id
);
817 struct cbmem_id_to_name
{
821 static const struct cbmem_id_to_name cbmem_ids
[] = { CBMEM_ID_TO_NAME_TABLE
};
823 void cbmem_print_entry(int n
, uint32_t id
, uint64_t base
, uint64_t size
)
829 for (i
= 0; i
< ARRAY_SIZE(cbmem_ids
); i
++) {
830 if (cbmem_ids
[i
].id
== id
) {
831 name
= cbmem_ids
[i
].name
;
840 printf("%s\t%08x", name
, id
);
841 printf(" %08" PRIx64
" ", base
);
842 printf(" %08" PRIx64
"\n", size
);
845 static void dump_cbmem_toc(void)
851 table
= map_lbtable();
856 printf("CBMEM table of contents:\n");
857 printf(" NAME ID START LENGTH\n");
862 while (offset
< lbtable_size
) {
863 struct lb_record
*lbr
;
864 struct lb_cbmem_entry
*lbe
;
866 lbr
= (void *)(table
+ offset
);
869 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
873 cbmem_print_entry(i
, lbe
->id
, lbe
->address
, lbe
->entry_size
);
880 #define COVERAGE_MAGIC 0x584d4153
890 static int mkpath(char *path
, mode_t mode
)
892 assert (path
&& *path
);
894 for (p
= strchr(path
+1, '/'); p
; p
= strchr(p
+ 1, '/')) {
896 if (mkdir(path
, mode
) == -1) {
897 if (errno
!= EEXIST
) {
907 static void dump_coverage(void)
912 unsigned long phys_offset
;
913 #define phys_to_virt(x) ((void *)(unsigned long)(x) + phys_offset)
915 if (find_cbmem_entry(CBMEM_ID_COVERAGE
, &start
, &size
)) {
916 fprintf(stderr
, "No coverage information found\n");
920 /* Map coverage area */
921 coverage
= map_memory_size(start
, size
, 1);
922 phys_offset
= (unsigned long)coverage
- (unsigned long)start
;
924 printf("Dumping coverage data...\n");
926 struct file
*file
= (struct file
*)coverage
;
927 while (file
&& file
->magic
== COVERAGE_MAGIC
) {
931 debug(" -> %s\n", (char *)phys_to_virt(file
->filename
));
932 filename
= strdup((char *)phys_to_virt(file
->filename
));
933 if (mkpath(filename
, 0755) == -1) {
934 perror("Directory for coverage data could "
938 f
= fopen(filename
, "wb");
940 printf("Could not open %s: %s\n",
941 filename
, strerror(errno
));
944 if (fwrite((void *)phys_to_virt(file
->data
),
945 file
->len
, 1, f
) != 1) {
946 printf("Could not write to %s: %s\n",
947 filename
, strerror(errno
));
954 file
= (struct file
*)phys_to_virt(file
->next
);
961 static void print_version(void)
963 printf("cbmem v%s -- ", CBMEM_VERSION
);
964 printf("Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.\n\n");
966 "This program is free software: you can redistribute it and/or modify\n"
967 "it under the terms of the GNU General Public License as published by\n"
968 "the Free Software Foundation, version 2 of the License.\n\n"
969 "This program is distributed in the hope that it will be useful,\n"
970 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
971 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
972 "GNU General Public License for more details.\n\n"
973 "You should have received a copy of the GNU General Public License\n"
974 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n");
977 static void print_usage(const char *name
)
979 printf("usage: %s [-cCltTxVvh?]\n", name
);
981 " -c | --console: print cbmem console\n"
982 " -C | --coverage: dump coverage information\n"
983 " -l | --list: print cbmem table of contents\n"
984 " -x | --hexdump: print hexdump of cbmem area\n"
985 " -r | --rawdump ID: print rawdump of specific ID (in hex) of cbtable\n"
986 " -t | --timestamps: print timestamp information\n"
987 " -T | --parseable-timestamps: print parseable timestamps\n"
988 " -V | --verbose: verbose (debugging) output\n"
989 " -v | --version: print the version\n"
990 " -h | --help: print this help\n"
996 static void dt_update_cells(const char *name
, int *addr_cells_ptr
,
999 if (*addr_cells_ptr
>= 0 && *size_cells_ptr
>= 0)
1003 size_t nlen
= strlen(name
);
1004 char *prop
= alloca(nlen
+ sizeof("/#address-cells"));
1007 if (*addr_cells_ptr
< 0) {
1008 strcpy(prop
+ nlen
, "/#address-cells");
1009 int fd
= open(prop
, O_RDONLY
);
1010 if (fd
< 0 && errno
!= ENOENT
) {
1012 } else if (fd
>= 0) {
1013 if (read(fd
, &buffer
, sizeof(int)) < 0)
1016 *addr_cells_ptr
= ntohl(buffer
);
1021 if (*size_cells_ptr
< 0) {
1022 strcpy(prop
+ nlen
, "/#size-cells");
1023 int fd
= open(prop
, O_RDONLY
);
1024 if (fd
< 0 && errno
!= ENOENT
) {
1026 } else if (fd
>= 0) {
1027 if (read(fd
, &buffer
, sizeof(int)) < 0)
1030 *size_cells_ptr
= ntohl(buffer
);
1036 static char *dt_find_compat(const char *parent
, const char *compat
,
1037 int *addr_cells_ptr
, int *size_cells_ptr
)
1040 struct dirent
*entry
;
1043 if (!(dir
= opendir(parent
))) {
1048 /* Loop through all files in the directory (DT node). */
1049 while ((entry
= readdir(dir
))) {
1050 /* We only care about compatible props or subnodes. */
1051 if (entry
->d_name
[0] == '.' || !((entry
->d_type
& DT_DIR
) ||
1052 !strcmp(entry
->d_name
, "compatible")))
1055 /* Assemble the file name (on the stack, for speed). */
1056 size_t plen
= strlen(parent
);
1057 char *name
= alloca(plen
+ strlen(entry
->d_name
) + 2);
1059 strcpy(name
, parent
);
1061 strcpy(name
+ plen
+ 1, entry
->d_name
);
1063 /* If it's a subnode, recurse. */
1064 if (entry
->d_type
& DT_DIR
) {
1065 ret
= dt_find_compat(name
, compat
, addr_cells_ptr
,
1068 /* There is only one matching node to find, abort. */
1070 /* Gather cells values on the way up. */
1071 dt_update_cells(parent
, addr_cells_ptr
,
1078 /* If it's a compatible string, see if it's the right one. */
1079 int fd
= open(name
, O_RDONLY
);
1080 int clen
= strlen(compat
);
1081 char *buffer
= alloca(clen
+ 1);
1088 if (read(fd
, buffer
, clen
+ 1) < 0) {
1095 if (!strcmp(compat
, buffer
)) {
1096 /* Initialize these to "unset" for the way up. */
1097 *addr_cells_ptr
= *size_cells_ptr
= -1;
1099 /* Can't leave string on the stack or we'll lose it! */
1100 ret
= strdup(parent
);
1108 #endif /* __arm__ */
1110 int main(int argc
, char** argv
)
1112 int print_defaults
= 1;
1113 int print_console
= 0;
1114 int print_coverage
= 0;
1116 int print_hexdump
= 0;
1117 int print_rawdump
= 0;
1118 int print_timestamps
= 0;
1119 int machine_readable_timestamps
= 0;
1120 unsigned int rawdump_id
= 0;
1122 int opt
, option_index
= 0;
1123 static struct option long_options
[] = {
1124 {"console", 0, 0, 'c'},
1125 {"coverage", 0, 0, 'C'},
1126 {"list", 0, 0, 'l'},
1127 {"timestamps", 0, 0, 't'},
1128 {"parseable-timestamps", 0, 0, 'T'},
1129 {"hexdump", 0, 0, 'x'},
1130 {"rawdump", required_argument
, 0, 'r'},
1131 {"verbose", 0, 0, 'V'},
1132 {"version", 0, 0, 'v'},
1133 {"help", 0, 0, 'h'},
1136 while ((opt
= getopt_long(argc
, argv
, "cCltTxVvh?r:",
1137 long_options
, &option_index
)) != EOF
) {
1158 rawdump_id
= strtoul(optarg
, NULL
, 16);
1161 print_timestamps
= 1;
1165 print_timestamps
= 1;
1166 machine_readable_timestamps
= 1;
1179 print_usage(argv
[0]);
1185 mem_fd
= open("/dev/mem", O_RDONLY
, 0);
1187 fprintf(stderr
, "Failed to gain memory access: %s\n",
1193 int addr_cells
, size_cells
;
1194 char *coreboot_node
= dt_find_compat("/proc/device-tree", "coreboot",
1195 &addr_cells
, &size_cells
);
1197 if (!coreboot_node
) {
1198 fprintf(stderr
, "Could not find 'coreboot' compatible node!\n");
1202 if (addr_cells
< 0) {
1203 fprintf(stderr
, "Warning: no #address-cells node in tree!\n");
1207 int nlen
= strlen(coreboot_node
);
1208 char *reg
= alloca(nlen
+ sizeof("/reg"));
1210 strcpy(reg
, coreboot_node
);
1211 strcpy(reg
+ nlen
, "/reg");
1212 free(coreboot_node
);
1214 int fd
= open(reg
, O_RDONLY
);
1221 size_t size_to_read
= addr_cells
* 4 + size_cells
* 4;
1222 u8
*dtbuffer
= alloca(size_to_read
);
1223 if (read(fd
, dtbuffer
, size_to_read
) < 0) {
1229 /* No variable-length byte swap function anywhere in C... how sad. */
1231 for (i
= 0; i
< addr_cells
* 4; i
++) {
1233 baseaddr
|= *dtbuffer
;
1236 u64 cb_table_size
= 0;
1237 for (i
= 0; i
< size_cells
* 4; i
++) {
1238 cb_table_size
<<= 8;
1239 cb_table_size
|= *dtbuffer
;
1243 parse_cbtable(baseaddr
, cb_table_size
, 1);
1246 static const int possible_base_addresses
[] = { 0, 0xf0000 };
1248 /* Find and parse coreboot table */
1249 for (j
= 0; j
< ARRAY_SIZE(possible_base_addresses
); j
++) {
1250 if (parse_cbtable(possible_base_addresses
[j
], MAP_BYTES
, 1))
1268 dump_cbmem_raw(rawdump_id
);
1270 if (print_defaults
|| print_timestamps
)
1271 dump_timestamps(machine_readable_timestamps
);