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>
35 #include <commonlib/cbmem_id.h>
36 #include <commonlib/timestamp_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]))
45 #define MAP_BYTES (1024*1024)
52 #define CBMEM_VERSION "1.1"
55 static int verbose
= 0;
56 #define debug(x...) if(verbose) printf(x)
58 /* File handle used to access /dev/mem */
61 static uint64_t lbtable_address
;
62 static size_t lbtable_size
;
65 * Some architectures map /dev/mem memory in a way that doesn't support
66 * unaligned accesses. Most normal libc memcpy()s aren't safe to use in this
67 * case, so build our own which makes sure to never do unaligned accesses on
68 * *src (*dest is fine since we never map /dev/mem for writing).
70 static void *aligned_memcpy(void *dest
, const void *src
, size_t n
)
73 const volatile u8
*s
= src
; /* volatile to prevent optimization */
75 while ((uintptr_t)s
& (sizeof(size_t) - 1)) {
81 while (n
>= sizeof(size_t)) {
82 *(size_t *)d
= *(const volatile size_t *)s
;
95 * calculate ip checksum (16 bit quantities) on a passed in buffer. In case
96 * the buffer length is odd last byte is excluded from the calculation
98 static u16
ipchcksum(const void *addr
, unsigned size
)
101 unsigned i
, n
= size
/ 2; /* don't expect odd sized blocks */
104 for (i
= 0; i
< n
; i
++)
107 sum
= (sum
>> 16) + (sum
& 0xffff);
114 * Functions to map / unmap physical memory into virtual address space. These
115 * functions always maps 1MB at a time and can only map one area at once.
117 static void *mapped_virtual
;
118 static size_t mapped_size
;
120 static inline size_t size_to_mib(size_t sz
)
125 static void unmap_memory(void)
127 if (mapped_virtual
== NULL
) {
128 fprintf(stderr
, "Error unmapping memory\n");
131 if (size_to_mib(mapped_size
) == 0) {
132 debug("Unmapping %zuMB of virtual memory at %p.\n",
133 size_to_mib(mapped_size
), mapped_virtual
);
135 debug("Unmapping %zuMB of virtual memory at %p.\n",
136 size_to_mib(mapped_size
), mapped_virtual
);
138 munmap(mapped_virtual
, mapped_size
);
139 mapped_virtual
= NULL
;
143 static void *map_memory_size(u64 physical
, size_t size
, uint8_t abort_on_failure
)
147 u64 page
= getpagesize();
150 if (mapped_virtual
!= NULL
)
153 /* Mapped memory must be aligned to page size */
154 p
= physical
& ~(page
- 1);
155 padding
= physical
& (page
-1);
158 if (size_to_mib(size
) == 0) {
159 debug("Mapping %zuB of physical memory at 0x%jx (requested 0x%jx).\n",
160 size
, (intmax_t)p
, (intmax_t)physical
);
162 debug("Mapping %zuMB of physical memory at 0x%jx (requested 0x%jx).\n",
163 size_to_mib(size
), (intmax_t)p
, (intmax_t)physical
);
166 v
= mmap(NULL
, size
, PROT_READ
, MAP_SHARED
, mem_fd
, p
);
168 /* Only try growing down when address exceeds page size so that
169 one doesn't underflow the offset request. */
170 if (v
== MAP_FAILED
&& p
>= page
) {
171 /* The mapped area may have overrun the upper cbmem boundary when trying to
172 * align to the page size. Try growing down instead of up...
177 size
= size
+ (page
- 1);
178 v
= mmap(NULL
, size
, PROT_READ
, MAP_SHARED
, mem_fd
, p
);
179 debug(" ... failed. Mapping %zuB of physical memory at 0x%jx.\n",
183 if (v
== MAP_FAILED
) {
184 if (abort_on_failure
) {
185 fprintf(stderr
, "Failed to mmap /dev/mem: %s\n",
193 /* Remember what we actually mapped ... */
197 /* ... but return address to the physical memory that was requested */
199 debug(" ... padding virtual address with 0x%zx bytes.\n",
206 static void *map_lbtable(void)
208 if (lbtable_address
== 0 || lbtable_size
== 0) {
209 fprintf(stderr
, "No coreboot table area found!\n");
213 return map_memory_size(lbtable_address
, lbtable_size
, 1);
216 static void unmap_lbtable(void)
221 /* Find the first cbmem entry filling in the details. */
222 static int find_cbmem_entry(uint32_t id
, uint64_t *addr
, size_t *size
)
228 table
= map_lbtable();
235 while (offset
< lbtable_size
) {
236 struct lb_record
*lbr
;
237 struct lb_cbmem_entry
*lbe
;
239 lbr
= (void *)(table
+ offset
);
242 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
249 *addr
= lbe
->address
;
250 *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 containg the timestamp table or zero if
268 static struct lb_cbmem_ref timestamps
;
269 static struct lb_cbmem_ref console
;
270 static struct lb_memory_range cbmem
;
272 /* This is a work-around for a nasty problem introduced by initially having
273 * pointer sized entries in the lb_cbmem_ref structures. This caused problems
274 * on 64bit x86 systems because coreboot is 32bit on those systems.
275 * When the problem was found, it was corrected, but there are a lot of
276 * systems out there with a firmware that does not produce the right
277 * lb_cbmem_ref structure. Hence we try to autocorrect this issue here.
279 static struct lb_cbmem_ref
parse_cbmem_ref(struct lb_cbmem_ref
*cbmem_ref
)
281 struct lb_cbmem_ref ret
;
285 if (cbmem_ref
->size
< sizeof(*cbmem_ref
))
286 ret
.cbmem_addr
= (uint32_t)ret
.cbmem_addr
;
288 debug(" cbmem_addr = %" PRIx64
"\n", ret
.cbmem_addr
);
293 static int parse_cbtable(u64 address
, size_t table_size
, uint8_t abort_on_failure
)
295 int i
, found
= 0, ret
= 0;
298 debug("Looking for coreboot table at %" PRIx64
" %zd bytes.\n",
299 address
, table_size
);
300 buf
= map_memory_size(address
, table_size
, abort_on_failure
);
304 /* look at every 16 bytes within 4K of the base */
306 for (i
= 0; i
< 0x1000; i
+= 0x10) {
307 struct lb_header
*lbh
;
308 struct lb_record
* lbr_p
;
312 lbh
= (struct lb_header
*)(buf
+ i
);
313 if (memcmp(lbh
->signature
, "LBIO", sizeof(lbh
->signature
)) ||
314 !lbh
->header_bytes
||
315 ipchcksum(lbh
, sizeof(*lbh
))) {
318 lbtable
= buf
+ i
+ lbh
->header_bytes
;
320 if (ipchcksum(lbtable
, lbh
->table_bytes
) !=
321 lbh
->table_checksum
) {
322 debug("Signature found, but wrong checksum.\n");
329 /* Keep reference to lbtable. */
330 lbtable_address
= address
;
331 lbtable_address
+= ((uint8_t *)lbtable
- (uint8_t *)lbh
);
332 lbtable_size
= lbh
->table_bytes
;
334 for (j
= 0; j
< lbh
->table_bytes
; j
+= lbr_p
->size
) {
335 lbr_p
= (struct lb_record
*) ((char *)lbtable
+ j
);
336 debug(" coreboot table entry 0x%02x\n", lbr_p
->tag
);
337 switch (lbr_p
->tag
) {
338 case LB_TAG_MEMORY
: {
340 debug(" Found memory map.\n");
341 struct lb_memory
*memory
=
342 (struct lb_memory
*)lbr_p
;
343 while ((char *)&memory
->map
[i
] < ((char *)lbr_p
345 if (memory
->map
[i
].type
== LB_MEM_TABLE
) {
346 debug(" LB_MEM_TABLE found.\n");
347 /* The last one found is CBMEM */
348 cbmem
= memory
->map
[i
];
354 case LB_TAG_TIMESTAMPS
: {
355 debug(" Found timestamp table.\n");
356 timestamps
= parse_cbmem_ref((struct lb_cbmem_ref
*) lbr_p
);
359 case LB_TAG_CBMEM_CONSOLE
: {
360 debug(" Found cbmem console.\n");
361 console
= parse_cbmem_ref((struct lb_cbmem_ref
*) lbr_p
);
364 case LB_TAG_FORWARD
: {
366 * This is a forwarding entry - repeat the
367 * search at the new address.
369 struct lb_forward lbf_p
=
370 *(struct lb_forward
*) lbr_p
;
371 debug(" Found forwarding entry.\n");
373 ret
= parse_cbtable(lbf_p
.forward
, table_size
, 0);
375 /* try again with a smaller memory mapping request */
376 ret
= parse_cbtable(lbf_p
.forward
, table_size
/ 2, 1);
396 #if defined(linux) && (defined(__i386__) || defined(__x86_64__))
398 * read CPU frequency from a sysfs file, return an frequency in Megahertz as
399 * an int or exit on any error.
401 static unsigned long arch_tick_frequency(void)
409 const char* freq_file
=
410 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
412 cpuf
= fopen(freq_file
, "r");
414 fprintf(stderr
, "Could not open %s: %s\n",
415 freq_file
, strerror(errno
));
419 memset(freqs
, 0, sizeof(freqs
));
420 size
= fread(freqs
, 1, sizeof(freqs
), cpuf
);
421 if (!size
|| (size
== sizeof(freqs
))) {
422 fprintf(stderr
, "Wrong number of bytes(%d) read from %s\n",
427 rv
= strtoull(freqs
, &endp
, 10);
429 if (*endp
== '\0' || *endp
== '\n')
430 /* cpuinfo_max_freq is in kHz. Convert it to MHz. */
432 fprintf(stderr
, "Wrong formatted value ^%s^ read from %s\n",
436 #elif defined(__OpenBSD__) && (defined(__i386__) || defined(__x86_64__))
437 static unsigned long arch_tick_frequency(void)
439 int mib
[2] = { CTL_HW
, HW_CPUSPEED
};
440 static int value
= 0;
441 size_t value_len
= sizeof(value
);
443 /* Return 1 MHz when sysctl fails. */
444 if ((value
== 0) && (sysctl(mib
, 2, &value
, &value_len
, NULL
, 0) == -1))
450 static unsigned long arch_tick_frequency(void)
457 static unsigned long tick_freq_mhz
;
459 static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz
)
461 tick_freq_mhz
= table_tick_freq_mhz
;
463 /* Honor table frequency. */
467 tick_freq_mhz
= arch_tick_frequency();
469 if (!tick_freq_mhz
) {
470 fprintf(stderr
, "Cannot determine timestamp tick frequency.\n");
475 u64
arch_convert_raw_ts_entry(u64 ts
)
477 return ts
/ tick_freq_mhz
;
481 * Print an integer in 'normalized' form - with commas separating every three
484 static void print_norm(u64 v
)
487 /* print the higher order sections first */
488 print_norm(v
/ 1000);
489 printf(",%3.3u", (u32
)(v
% 1000));
491 printf("%u", (u32
)(v
% 1000));
495 static const char *timestamp_name(uint32_t id
)
499 for (i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++) {
500 if (timestamp_ids
[i
].id
== id
)
501 return timestamp_ids
[i
].name
;
506 static uint64_t timestamp_print_parseable_entry(uint32_t id
, uint64_t stamp
,
512 name
= timestamp_name(id
);
514 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
516 /* ID<tab>absolute time<tab>relative time<tab>description */
518 printf("%llu\t", (long long)arch_convert_raw_ts_entry(stamp
));
519 printf("%llu\t", (long long)step_time
);
520 printf("%s\n", name
);
525 uint64_t timestamp_print_entry(uint32_t id
, uint64_t stamp
, uint64_t prev_stamp
)
530 name
= timestamp_name(id
);
533 printf("%-50s", name
);
534 print_norm(arch_convert_raw_ts_entry(stamp
));
535 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
538 print_norm(step_time
);
546 /* dump the timestamp table */
547 static void dump_timestamps(int mach_readable
)
550 struct timestamp_table
*tst_p
;
555 if (timestamps
.tag
!= LB_TAG_TIMESTAMPS
) {
556 fprintf(stderr
, "No timestamps found in coreboot table.\n");
560 size
= sizeof(*tst_p
);
561 tst_p
= map_memory_size((unsigned long)timestamps
.cbmem_addr
, size
, 1);
563 timestamp_set_tick_freq(tst_p
->tick_freq_mhz
);
566 printf("%d entries total:\n\n", tst_p
->num_entries
);
567 size
+= tst_p
->num_entries
* sizeof(tst_p
->entries
[0]);
570 tst_p
= map_memory_size((unsigned long)timestamps
.cbmem_addr
, size
, 1);
572 /* Report the base time within the table. */
575 timestamp_print_parseable_entry(0, tst_p
->base_time
,
578 timestamp_print_entry(0, tst_p
->base_time
, prev_stamp
);
579 prev_stamp
= tst_p
->base_time
;
582 for (i
= 0; i
< tst_p
->num_entries
; i
++) {
584 const struct timestamp_entry
*tse
= &tst_p
->entries
[i
];
586 /* Make all timestamps absolute. */
587 stamp
= tse
->entry_stamp
+ tst_p
->base_time
;
590 timestamp_print_parseable_entry(tse
->entry_id
,
593 total_time
+= timestamp_print_entry(tse
->entry_id
,
598 if (!mach_readable
) {
599 printf("\nTotal Time: ");
600 print_norm(total_time
);
607 struct cbmem_console
{
611 } __attribute__ ((__packed__
));
613 #define CBMC_CURSOR_MASK ((1 << 28) - 1)
614 #define CBMC_OVERFLOW (1 << 31)
616 /* dump the cbmem console */
617 static void dump_console(int one_boot_only
)
619 struct cbmem_console
*console_p
;
623 if (console
.tag
!= LB_TAG_CBMEM_CONSOLE
) {
624 fprintf(stderr
, "No console found in coreboot table.\n");
628 size
= sizeof(*console_p
);
629 console_p
= map_memory_size((unsigned long)console
.cbmem_addr
, size
, 1);
630 cursor
= console_p
->cursor
& CBMC_CURSOR_MASK
;
631 if (!(console_p
->cursor
& CBMC_OVERFLOW
) && cursor
< console_p
->size
)
634 size
= console_p
->size
;
637 console_c
= malloc(size
+ 1);
639 fprintf(stderr
, "Not enough memory for console.\n");
642 console_c
[size
] = '\0';
644 console_p
= map_memory_size((unsigned long)console
.cbmem_addr
,
645 size
+ sizeof(*console_p
), 1);
646 if (console_p
->cursor
& CBMC_OVERFLOW
) {
647 if (cursor
>= size
) {
648 printf("cbmem: ERROR: CBMEM console struct is illegal, "
649 "output may be corrupt or out of order!\n\n");
652 aligned_memcpy(console_c
, console_p
->body
+ cursor
,
654 aligned_memcpy(console_c
+ size
- cursor
,
655 console_p
->body
, cursor
);
657 aligned_memcpy(console_c
, console_p
->body
, size
);
660 /* Slight memory corruption may occur between reboots and give us a few
661 unprintable characters like '\0'. Replace them with '?' on output. */
662 for (cursor
= 0; cursor
< size
; cursor
++)
663 if (!isprint(console_c
[cursor
]) && !isspace(console_c
[cursor
]))
664 console_c
[cursor
] = '?';
666 /* We detect the last boot by looking for a bootblock, romstage or
667 ramstage banner, in that order (to account for platforms without
668 CONFIG_BOOTBLOCK_CONSOLE and/or CONFIG_EARLY_CONSOLE). Once we find
669 a banner, store the last match for that stage in cursor and stop. */
672 #define BANNER_REGEX(stage) "\n\ncoreboot-[^\n]* " stage " starting\\.\\.\\.\n"
673 #define OVERFLOW_REGEX(stage) "\n*** Pre-CBMEM " stage " console overflowed"
674 const char *regex
[] = { BANNER_REGEX("bootblock"),
675 BANNER_REGEX("romstage"),
676 OVERFLOW_REGEX("romstage"),
677 BANNER_REGEX("ramstage"),
678 OVERFLOW_REGEX("ramstage") };
681 for (i
= 0; !cursor
&& i
< ARRAY_SIZE(regex
); i
++) {
684 assert(!regcomp(&re
, regex
[i
], 0));
686 /* Keep looking for matches so we find the last one. */
687 while (!regexec(&re
, console_c
+ cursor
, 1, &match
, 0))
688 cursor
+= match
.rm_so
+ 1;
693 puts(console_c
+ cursor
);
698 static void hexdump(unsigned long memory
, int length
)
704 m
= map_memory_size((intptr_t)memory
, length
, 1);
706 if (length
> MAP_BYTES
) {
707 printf("Truncating hex dump from %d to %d bytes\n\n",
712 for (i
= 0; i
< length
; i
+= 16) {
716 for (j
= 0; j
< 16; j
++) {
724 printf("%08lx:", memory
+ i
);
725 for (j
= 0; j
< 16; j
++)
726 printf(" %02x", m
[i
+j
]);
728 for (j
= 0; j
< 16; j
++)
729 printf("%c", isprint(m
[i
+j
]) ? m
[i
+j
] : '.');
731 } else if (all_zero
== 2) {
739 static void dump_cbmem_hex(void)
741 if (cbmem
.type
!= LB_MEM_TABLE
) {
742 fprintf(stderr
, "No coreboot CBMEM area found!\n");
746 hexdump(unpack_lb64(cbmem
.start
), unpack_lb64(cbmem
.size
));
749 void rawdump(uint64_t base
, uint64_t size
)
754 m
= map_memory_size((intptr_t)base
, size
, 1);
756 fprintf(stderr
, "Failed to map memory");
760 for (i
= 0 ; i
< size
; i
++)
765 static void dump_cbmem_raw(unsigned int id
)
772 table
= map_lbtable();
779 while (offset
< lbtable_size
) {
780 struct lb_record
*lbr
;
781 struct lb_cbmem_entry
*lbe
;
783 lbr
= (void *)(table
+ offset
);
786 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
791 debug("found id for raw dump %0x", lbe
->id
);
793 size
= lbe
->entry_size
;
801 fprintf(stderr
, "id %0x not found in cbtable\n", id
);
806 struct cbmem_id_to_name
{
810 static const struct cbmem_id_to_name cbmem_ids
[] = { CBMEM_ID_TO_NAME_TABLE
};
812 void cbmem_print_entry(int n
, uint32_t id
, uint64_t base
, uint64_t size
)
818 for (i
= 0; i
< ARRAY_SIZE(cbmem_ids
); i
++) {
819 if (cbmem_ids
[i
].id
== id
) {
820 name
= cbmem_ids
[i
].name
;
829 printf("%s\t%08x", name
, id
);
830 printf(" %08" PRIx64
" ", base
);
831 printf(" %08" PRIx64
"\n", size
);
834 static void dump_cbmem_toc(void)
840 table
= map_lbtable();
845 printf("CBMEM table of contents:\n");
846 printf(" NAME ID START LENGTH\n");
851 while (offset
< lbtable_size
) {
852 struct lb_record
*lbr
;
853 struct lb_cbmem_entry
*lbe
;
855 lbr
= (void *)(table
+ offset
);
858 if (lbr
->tag
!= LB_TAG_CBMEM_ENTRY
)
862 cbmem_print_entry(i
, lbe
->id
, lbe
->address
, lbe
->entry_size
);
869 #define COVERAGE_MAGIC 0x584d4153
879 static int mkpath(char *path
, mode_t mode
)
881 assert (path
&& *path
);
883 for (p
= strchr(path
+1, '/'); p
; p
= strchr(p
+ 1, '/')) {
885 if (mkdir(path
, mode
) == -1) {
886 if (errno
!= EEXIST
) {
896 static void dump_coverage(void)
901 unsigned long phys_offset
;
902 #define phys_to_virt(x) ((void *)(unsigned long)(x) + phys_offset)
904 if (find_cbmem_entry(CBMEM_ID_COVERAGE
, &start
, &size
)) {
905 fprintf(stderr
, "No coverage information found\n");
909 /* Map coverage area */
910 coverage
= map_memory_size(start
, size
, 1);
911 phys_offset
= (unsigned long)coverage
- (unsigned long)start
;
913 printf("Dumping coverage data...\n");
915 struct file
*file
= (struct file
*)coverage
;
916 while (file
&& file
->magic
== COVERAGE_MAGIC
) {
920 debug(" -> %s\n", (char *)phys_to_virt(file
->filename
));
921 filename
= strdup((char *)phys_to_virt(file
->filename
));
922 if (mkpath(filename
, 0755) == -1) {
923 perror("Directory for coverage data could "
927 f
= fopen(filename
, "wb");
929 printf("Could not open %s: %s\n",
930 filename
, strerror(errno
));
933 if (fwrite((void *)phys_to_virt(file
->data
),
934 file
->len
, 1, f
) != 1) {
935 printf("Could not write to %s: %s\n",
936 filename
, strerror(errno
));
943 file
= (struct file
*)phys_to_virt(file
->next
);
950 static void print_version(void)
952 printf("cbmem v%s -- ", CBMEM_VERSION
);
953 printf("Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.\n\n");
955 "This program is free software: you can redistribute it and/or modify\n"
956 "it under the terms of the GNU General Public License as published by\n"
957 "the Free Software Foundation, version 2 of the License.\n\n"
958 "This program is distributed in the hope that it will be useful,\n"
959 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
960 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
961 "GNU General Public License for more details.\n\n");
964 static void print_usage(const char *name
, int exit_code
)
966 printf("usage: %s [-cCltTxVvh?]\n", name
);
968 " -c | --console: print cbmem console\n"
969 " -1 | --oneboot: print cbmem console for last boot only\n"
970 " -C | --coverage: dump coverage information\n"
971 " -l | --list: print cbmem table of contents\n"
972 " -x | --hexdump: print hexdump of cbmem area\n"
973 " -r | --rawdump ID: print rawdump of specific ID (in hex) of cbtable\n"
974 " -t | --timestamps: print timestamp information\n"
975 " -T | --parseable-timestamps: print parseable timestamps\n"
976 " -V | --verbose: verbose (debugging) output\n"
977 " -v | --version: print the version\n"
978 " -h | --help: print this help\n"
984 static void dt_update_cells(const char *name
, int *addr_cells_ptr
,
987 if (*addr_cells_ptr
>= 0 && *size_cells_ptr
>= 0)
991 size_t nlen
= strlen(name
);
992 char *prop
= alloca(nlen
+ sizeof("/#address-cells"));
995 if (*addr_cells_ptr
< 0) {
996 strcpy(prop
+ nlen
, "/#address-cells");
997 int fd
= open(prop
, O_RDONLY
);
998 if (fd
< 0 && errno
!= ENOENT
) {
1000 } else if (fd
>= 0) {
1001 if (read(fd
, &buffer
, sizeof(int)) < 0)
1004 *addr_cells_ptr
= ntohl(buffer
);
1009 if (*size_cells_ptr
< 0) {
1010 strcpy(prop
+ nlen
, "/#size-cells");
1011 int fd
= open(prop
, O_RDONLY
);
1012 if (fd
< 0 && errno
!= ENOENT
) {
1014 } else if (fd
>= 0) {
1015 if (read(fd
, &buffer
, sizeof(int)) < 0)
1018 *size_cells_ptr
= ntohl(buffer
);
1024 static char *dt_find_compat(const char *parent
, const char *compat
,
1025 int *addr_cells_ptr
, int *size_cells_ptr
)
1028 struct dirent
*entry
;
1031 if (!(dir
= opendir(parent
))) {
1036 /* Loop through all files in the directory (DT node). */
1037 while ((entry
= readdir(dir
))) {
1038 /* We only care about compatible props or subnodes. */
1039 if (entry
->d_name
[0] == '.' || !((entry
->d_type
& DT_DIR
) ||
1040 !strcmp(entry
->d_name
, "compatible")))
1043 /* Assemble the file name (on the stack, for speed). */
1044 size_t plen
= strlen(parent
);
1045 char *name
= alloca(plen
+ strlen(entry
->d_name
) + 2);
1047 strcpy(name
, parent
);
1049 strcpy(name
+ plen
+ 1, entry
->d_name
);
1051 /* If it's a subnode, recurse. */
1052 if (entry
->d_type
& DT_DIR
) {
1053 ret
= dt_find_compat(name
, compat
, addr_cells_ptr
,
1056 /* There is only one matching node to find, abort. */
1058 /* Gather cells values on the way up. */
1059 dt_update_cells(parent
, addr_cells_ptr
,
1066 /* If it's a compatible string, see if it's the right one. */
1067 int fd
= open(name
, O_RDONLY
);
1068 int clen
= strlen(compat
);
1069 char *buffer
= alloca(clen
+ 1);
1076 if (read(fd
, buffer
, clen
+ 1) < 0) {
1083 if (!strcmp(compat
, buffer
)) {
1084 /* Initialize these to "unset" for the way up. */
1085 *addr_cells_ptr
= *size_cells_ptr
= -1;
1087 /* Can't leave string on the stack or we'll lose it! */
1088 ret
= strdup(parent
);
1096 #endif /* __arm__ */
1098 int main(int argc
, char** argv
)
1100 int print_defaults
= 1;
1101 int print_console
= 0;
1102 int print_coverage
= 0;
1104 int print_hexdump
= 0;
1105 int print_rawdump
= 0;
1106 int print_timestamps
= 0;
1107 int machine_readable_timestamps
= 0;
1108 int one_boot_only
= 0;
1109 unsigned int rawdump_id
= 0;
1111 int opt
, option_index
= 0;
1112 static struct option long_options
[] = {
1113 {"console", 0, 0, 'c'},
1114 {"oneboot", 0, 0, '1'},
1115 {"coverage", 0, 0, 'C'},
1116 {"list", 0, 0, 'l'},
1117 {"timestamps", 0, 0, 't'},
1118 {"parseable-timestamps", 0, 0, 'T'},
1119 {"hexdump", 0, 0, 'x'},
1120 {"rawdump", required_argument
, 0, 'r'},
1121 {"verbose", 0, 0, 'V'},
1122 {"version", 0, 0, 'v'},
1123 {"help", 0, 0, 'h'},
1126 while ((opt
= getopt_long(argc
, argv
, "c1CltTxVvh?r:",
1127 long_options
, &option_index
)) != EOF
) {
1153 rawdump_id
= strtoul(optarg
, NULL
, 16);
1156 print_timestamps
= 1;
1160 print_timestamps
= 1;
1161 machine_readable_timestamps
= 1;
1172 print_usage(argv
[0], 0);
1176 print_usage(argv
[0], 1);
1181 mem_fd
= open("/dev/mem", O_RDONLY
, 0);
1183 fprintf(stderr
, "Failed to gain memory access: %s\n",
1189 int addr_cells
, size_cells
;
1190 char *coreboot_node
= dt_find_compat("/proc/device-tree", "coreboot",
1191 &addr_cells
, &size_cells
);
1193 if (!coreboot_node
) {
1194 fprintf(stderr
, "Could not find 'coreboot' compatible node!\n");
1198 if (addr_cells
< 0) {
1199 fprintf(stderr
, "Warning: no #address-cells node in tree!\n");
1203 int nlen
= strlen(coreboot_node
);
1204 char *reg
= alloca(nlen
+ sizeof("/reg"));
1206 strcpy(reg
, coreboot_node
);
1207 strcpy(reg
+ nlen
, "/reg");
1208 free(coreboot_node
);
1210 int fd
= open(reg
, O_RDONLY
);
1217 size_t size_to_read
= addr_cells
* 4 + size_cells
* 4;
1218 u8
*dtbuffer
= alloca(size_to_read
);
1219 if (read(fd
, dtbuffer
, size_to_read
) < 0) {
1225 /* No variable-length byte swap function anywhere in C... how sad. */
1227 for (i
= 0; i
< addr_cells
* 4; i
++) {
1229 baseaddr
|= *dtbuffer
;
1232 u64 cb_table_size
= 0;
1233 for (i
= 0; i
< size_cells
* 4; i
++) {
1234 cb_table_size
<<= 8;
1235 cb_table_size
|= *dtbuffer
;
1239 parse_cbtable(baseaddr
, cb_table_size
, 1);
1242 static const int possible_base_addresses
[] = { 0, 0xf0000 };
1244 /* Find and parse coreboot table */
1245 for (j
= 0; j
< ARRAY_SIZE(possible_base_addresses
); j
++) {
1246 if (parse_cbtable(possible_base_addresses
[j
], MAP_BYTES
, 1))
1252 dump_console(one_boot_only
);
1264 dump_cbmem_raw(rawdump_id
);
1266 if (print_defaults
|| print_timestamps
)
1267 dump_timestamps(machine_readable_timestamps
);