blob: 2f2ff93cb35b918d251d2f5b09b629e408f35755 [file] [log] [blame]
Bill Richardson60bcbe32010-09-09 14:53:56 -07001/*
Bill Richardson9429f882012-07-26 13:10:59 -07002 * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Bill Richardson60bcbe32010-09-09 14:53:56 -07003 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6#include <errno.h>
7#include <fcntl.h>
8#include <inttypes.h>
9#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/mman.h>
14#include <sys/stat.h>
15#include <sys/types.h>
16#include <unistd.h>
17
Che-Liang Chiou305e9e52011-02-17 17:56:16 +080018#include "fmap.h"
19
Bill Richardson9429f882012-07-26 13:10:59 -070020enum { FMT_NORMAL, FMT_PRETTY, FMT_FLASHROM, FMT_HUMAN };
Bill Richardson77c02432011-07-29 13:05:58 -070021
Bill Richardson60bcbe32010-09-09 14:53:56 -070022/* global variables */
23static int opt_extract = 0;
Bill Richardson77c02432011-07-29 13:05:58 -070024static int opt_format = FMT_NORMAL;
Bill Richardson9429f882012-07-26 13:10:59 -070025static char *progname;
26static void *base_of_rom;
Bill Richardson60bcbe32010-09-09 14:53:56 -070027
28
29/* Return 0 if successful */
Bill Richardson9429f882012-07-26 13:10:59 -070030static int dump_fmap(const void *ptr, int argc, char *argv[])
31{
Bill Richardsonf4729192012-05-02 23:30:16 -070032 int i, retval = 0;
Bill Richardson60bcbe32010-09-09 14:53:56 -070033 char buf[80]; // DWR: magic number
Bill Richardson9429f882012-07-26 13:10:59 -070034 const FmapHeader *fmh = (const FmapHeader*)ptr;
35 const FmapAreaHeader *ah = (const FmapAreaHeader*)(ptr + sizeof(FmapHeader));
Bill Richardson60bcbe32010-09-09 14:53:56 -070036
Bill Richardson77c02432011-07-29 13:05:58 -070037 if (FMT_NORMAL == opt_format) {
Bill Richardson9a2c3b22011-06-13 12:45:24 -070038 snprintf(buf, FMAP_SIGNATURE_SIZE+1, "%s", fmh->fmap_signature);
39 printf("fmap_signature %s\n", buf);
40 printf("fmap_version: %d.%d\n",
41 fmh->fmap_ver_major, fmh->fmap_ver_minor);
42 printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base);
43 printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size, fmh->fmap_size);
44 snprintf(buf, FMAP_NAMELEN+1, "%s", fmh->fmap_name);
45 printf("fmap_name: %s\n", buf);
46 printf("fmap_nareas: %d\n", fmh->fmap_nareas);
47 }
Bill Richardson60bcbe32010-09-09 14:53:56 -070048
Bill Richardson9429f882012-07-26 13:10:59 -070049 for (i = 0; i < fmh->fmap_nareas; i++, ah++) {
Bill Richardson77c02432011-07-29 13:05:58 -070050 snprintf(buf, FMAP_NAMELEN+1, "%s", ah->area_name);
Bill Richardsone7e8ecd2012-03-01 11:05:29 -080051
52 if (argc) {
53 int j, found=0;
Bill Richardson9429f882012-07-26 13:10:59 -070054 for (j = 0; j < argc; j++)
Bill Richardsone7e8ecd2012-03-01 11:05:29 -080055 if (!strcmp(argv[j], buf)) {
Bill Richardson9429f882012-07-26 13:10:59 -070056 found = 1;
57 break;
58 }
Bill Richardsone7e8ecd2012-03-01 11:05:29 -080059 if (!found) {
60 continue;
61 }
62 }
63
Bill Richardson9429f882012-07-26 13:10:59 -070064 switch (opt_format) {
Bill Richardson77c02432011-07-29 13:05:58 -070065 case FMT_PRETTY:
Bill Richardson9a2c3b22011-06-13 12:45:24 -070066 printf("%s %d %d\n", buf, ah->area_offset, ah->area_size);
Bill Richardson77c02432011-07-29 13:05:58 -070067 break;
68 case FMT_FLASHROM:
69 if (ah->area_size)
Louis Yung-Chieh Lo9462e3e2011-08-24 12:53:43 +080070 printf("0x%08x:0x%08x %s\n", ah->area_offset,
Bill Richardson9429f882012-07-26 13:10:59 -070071 ah->area_offset + ah->area_size - 1, buf);
Bill Richardson77c02432011-07-29 13:05:58 -070072 break;
73 default:
Bill Richardson9a2c3b22011-06-13 12:45:24 -070074 printf("area: %d\n", i+1);
75 printf("area_offset: 0x%08x\n", ah->area_offset);
76 printf("area_size: 0x%08x (%d)\n", ah->area_size, ah->area_size);
77 printf("area_name: %s\n", buf);
78 }
Bill Richardson60bcbe32010-09-09 14:53:56 -070079
80 if (opt_extract) {
Bill Richardson9429f882012-07-26 13:10:59 -070081 char *s;
82 for (s = buf; *s; s++)
Bill Richardson60bcbe32010-09-09 14:53:56 -070083 if (*s == ' ')
Bill Richardson9a2c3b22011-06-13 12:45:24 -070084 *s = '_';
Bill Richardson9429f882012-07-26 13:10:59 -070085 FILE *fp = fopen(buf,"wb");
Bill Richardson60bcbe32010-09-09 14:53:56 -070086 if (!fp) {
87 fprintf(stderr, "%s: can't open %s: %s\n",
88 progname, buf, strerror(errno));
89 retval = 1;
90 } else {
Bill Richardsonccdaa472011-03-03 18:08:18 -080091 if (ah->area_size &&
92 1 != fwrite(base_of_rom + ah->area_offset, ah->area_size, 1, fp)) {
Bill Richardson60bcbe32010-09-09 14:53:56 -070093 fprintf(stderr, "%s: can't write %s: %s\n",
94 progname, buf, strerror(errno));
95 retval = 1;
96 } else {
Bill Richardson77c02432011-07-29 13:05:58 -070097 if (FMT_NORMAL == opt_format)
Bill Richardson9a2c3b22011-06-13 12:45:24 -070098 printf("saved as \"%s\"\n", buf);
Bill Richardson60bcbe32010-09-09 14:53:56 -070099 }
100 fclose(fp);
101 }
102 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700103 }
104
105 return retval;
106}
107
108
Bill Richardson9429f882012-07-26 13:10:59 -0700109/* Sort by start, then size, then name */
110static int by_start(FmapAreaHeader *a, FmapAreaHeader *b)
111{
112 if (a->area_offset == b->area_offset) {
113
114 if (a->area_size == b->area_size )
115 return strncmp(a->area_name, b->area_name, FMAP_NAMELEN) < 0;
116
117 return a->area_size < b->area_size;
118 }
119
120 return a->area_offset > b->area_offset;
121}
122
123
124
125static void isort(FmapAreaHeader *ary, int num,
126 int (*lessthan)(FmapAreaHeader *a, FmapAreaHeader *b))
127{
128 int i, j;
129 FmapAreaHeader tmp;
130
131 for (i = 1; i < num; i++) {
132 tmp = ary[i];
133 for (j = i; j && lessthan(ary+j-1, &tmp); j--)
134 ary[j] = ary[j-1];
135 ary[j] = tmp;
136 }
137}
138
139/* Return 0 if successful */
140static int human_fmap(void *ptr)
141{
142 int i, j;
143 uint32_t end_i;
144 FmapHeader *fmh = (FmapHeader *)ptr;
145 FmapAreaHeader *ah = (FmapAreaHeader *)(fmh + 1);
146 FmapAreaHeader tmp;
147
148 /* We're using mmap() with MAP_PRIVATE, so we can freely fiddle with the fmap
149 * data. We'll sort the areas, reusing the flags field for indentation. */
150 for (i = 0; i < fmh->fmap_nareas; i++)
151 ah[i].area_flags = 0;
152
153 /* First, sort by start and size. */
154 isort(ah, fmh->fmap_nareas, by_start);
155
156 /* Now figure out indentation. */
157 for (i = 0; i < fmh->fmap_nareas - 1; i++) {
158 end_i = ah[i].area_offset + ah[i].area_size;
159 for (j = i+1; (j < fmh->fmap_nareas &&
160 ah[j].area_offset + ah[j].area_size <= end_i &&
161 /* Don't double-indent identical blocks. */
162 !(ah[i].area_offset == ah[j].area_offset &&
163 ah[i].area_size == ah[j].area_size)); j++)
164 ah[j].area_flags++;
165 }
166
167 /* Rearrange nested blocks */
168 for (i = 0; i < fmh->fmap_nareas - 1; i++) {
169 tmp = ah[i];
170 for (j = i+1; (j < fmh->fmap_nareas &&
171 tmp.area_flags < ah[j].area_flags); j++)
172 ah[j-1] = ah[j];
173 ah[j-1] = tmp;
174 }
175
176 /* Print the results. */
177 printf("%-20s %8s %8s %6s\n", "# name", "start", "end", "size");
178 for (i = fmh->fmap_nareas - 1; i>= 0; i--) {
179 for (j = 0; j < ah[i].area_flags; j++)
180 printf(" ");
181 printf("%-*s", 20 - ah[i].area_flags * 2, ah[i].area_name);
182 printf(" %*s%0*x", ah[i].area_flags, "",
183 8 - ah[i].area_flags, ah[i].area_offset);
184 printf(" %*s%0*x", ah[i].area_flags, "",
185 8 - ah[i].area_flags, ah[i].area_offset + ah[i].area_size);
186 printf(" %6x\n", ah[i].area_size);
187 }
188
189 return 0;
190}
191
192
193int main(int argc, char *argv[])
194{
Bill Richardson60bcbe32010-09-09 14:53:56 -0700195 int c;
196 int errorcnt = 0;
197 struct stat sb;
198 int fd;
Bill Richardson9429f882012-07-26 13:10:59 -0700199 const char *fmap;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700200 int retval = 1;
201
202 progname = strrchr(argv[0], '/');
203 if (progname)
204 progname++;
205 else
206 progname = argv[0];
207
Bill Richardson9429f882012-07-26 13:10:59 -0700208 opterr = 0; /* quiet, you */
209 while ((c = getopt(argc, argv, ":xpfh")) != -1) {
210 switch (c) {
Bill Richardson60bcbe32010-09-09 14:53:56 -0700211 case 'x':
212 opt_extract = 1;
213 break;
Bill Richardson9a2c3b22011-06-13 12:45:24 -0700214 case 'p':
Bill Richardson77c02432011-07-29 13:05:58 -0700215 opt_format = FMT_PRETTY;
216 break;
217 case 'f':
218 opt_format = FMT_FLASHROM;
Bill Richardson9a2c3b22011-06-13 12:45:24 -0700219 break;
Bill Richardson9429f882012-07-26 13:10:59 -0700220 case 'h':
221 opt_format = FMT_HUMAN;
222 break;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700223 case '?':
224 fprintf(stderr, "%s: unrecognized switch: -%c\n",
225 progname, optopt);
226 errorcnt++;
227 break;
228 case ':':
229 fprintf(stderr, "%s: missing argument to -%c\n",
230 progname, optopt);
231 errorcnt++;
232 break;
233 default:
234 errorcnt++;
235 break;
236 }
237 }
238
239 if (errorcnt || optind >= argc) {
240 fprintf(stderr,
Bill Richardson9429f882012-07-26 13:10:59 -0700241 "\nUsage: %s [-x] [-p|-f|-h] FLASHIMAGE [NAME...]\n\n"
Bill Richardson9a2c3b22011-06-13 12:45:24 -0700242 "Display (and extract with -x) the FMAP components from a BIOS image.\n"
243 "The -p option makes the output easier to parse by scripts.\n"
Bill Richardsone7e8ecd2012-03-01 11:05:29 -0800244 "The -f option emits the FMAP in the format used by flashrom.\n"
245 "\n"
246 "Specify one or more NAMEs to only print sections that exactly match.\n"
Bill Richardson9429f882012-07-26 13:10:59 -0700247 "\n"
248 "The -h option shows the whole FMAP in human-readable form.\n"
Bill Richardson9a2c3b22011-06-13 12:45:24 -0700249 "\n",
250 progname);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700251 return 1;
252 }
253
254 if (0 != stat(argv[optind], &sb)) {
255 fprintf(stderr, "%s: can't stat %s: %s\n",
256 progname,
257 argv[optind],
258 strerror(errno));
259 return 1;
260 }
261
262 fd = open(argv[optind], O_RDONLY);
263 if (fd < 0) {
264 fprintf(stderr, "%s: can't open %s: %s\n",
265 progname,
266 argv[optind],
267 strerror(errno));
268 return 1;
269 }
Bill Richardson77c02432011-07-29 13:05:58 -0700270 if (FMT_NORMAL == opt_format)
Bill Richardson9a2c3b22011-06-13 12:45:24 -0700271 printf("opened %s\n", argv[optind]);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700272
Bill Richardson9429f882012-07-26 13:10:59 -0700273 base_of_rom = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
Che-Liang Chiou305e9e52011-02-17 17:56:16 +0800274 if (base_of_rom == (char*)-1) {
Bill Richardson60bcbe32010-09-09 14:53:56 -0700275 fprintf(stderr, "%s: can't mmap %s: %s\n",
276 progname,
277 argv[optind],
278 strerror(errno));
279 close(fd);
280 return 1;
281 }
282 close(fd); /* done with this now */
283
Che-Liang Chiou305e9e52011-02-17 17:56:16 +0800284 fmap = FmapFind((char*) base_of_rom, sb.st_size);
285 if (fmap) {
Bill Richardson9429f882012-07-26 13:10:59 -0700286 switch (opt_format) {
287 case FMT_HUMAN:
288 retval = human_fmap((void *)fmap);
289 break;
290 case FMT_NORMAL:
Bill Richardson9a2c3b22011-06-13 12:45:24 -0700291 printf("hit at 0x%08x\n", (uint32_t) (fmap - (char*) base_of_rom));
Bill Richardson9429f882012-07-26 13:10:59 -0700292 /* fallthrough */
293 default:
294 retval = dump_fmap(fmap, argc-optind-1, argv+optind+1);
295 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700296 }
297
298 if (0 != munmap(base_of_rom, sb.st_size)) {
299 fprintf(stderr, "%s: can't munmap %s: %s\n",
300 progname,
301 argv[optind],
302 strerror(errno));
303 return 1;
304 }
305
306 return retval;
307}