2 * ifdtool - dump Intel Firmware Descriptor information
4 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
26 #include <sys/types.h>
30 static fdbar_t *find_fd(char *image, int size)
34 /* Scan for FD signature */
35 for (i = 0; i < (size - 4); i += 4) {
36 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
38 break; // signature found.
43 printf("No Flash Descriptor found in this image\n");
47 printf("Found Flash Descriptor signature at 0x%08x\n", i);
49 return (fdbar_t *) (image + i);
53 int base, limit, size;
56 static region_t get_region(frba_t *frba, int region_type)
59 region.base = 0, region.limit = 0, region.size = 0;
61 switch (region_type) {
63 region.base = (frba->flreg0 & 0x00000fff) << 12;
64 region.limit = ((frba->flreg0 & 0x0fff0000) >> 4) | 0xfff;
67 region.base = (frba->flreg1 & 0x00000fff) << 12;
68 region.limit = ((frba->flreg1 & 0x0fff0000) >> 4) | 0xfff;
71 region.base = (frba->flreg2 & 0x00000fff) << 12;
72 region.limit = ((frba->flreg2 & 0x0fff0000) >> 4) | 0xfff;
75 region.base = (frba->flreg3 & 0x00000fff) << 12;
76 region.limit = ((frba->flreg3 & 0x0fff0000) >> 4) | 0xfff;
79 region.base = (frba->flreg4 & 0x00000fff) << 12;
80 region.limit = ((frba->flreg4 & 0x0fff0000) >> 4) | 0xfff;
83 fprintf(stderr, "Invalid region type.\n");
87 region.size = region.limit - region.base + 1;
92 static const char *region_name(int region_type)
94 static const char *regions[5] = {
102 if (region_type < 0 || region_type > 4) {
103 fprintf(stderr, "Invalid region type.\n");
107 return regions[region_type];
110 static const char *region_filename(int region_type)
112 static const char *region_filenames[5] = {
113 "flashregion_0_flashdescriptor.bin",
114 "flashregion_1_bios.bin",
115 "flashregion_2_intel_me.bin",
116 "flashregion_3_gbe.bin",
117 "flashregion_4_platform_data.bin"
120 if (region_type < 0 || region_type > 4) {
121 fprintf(stderr, "Invalid region type.\n");
125 return region_filenames[region_type];
128 static void dump_frba(frba_t * frba)
130 printf("\nFound Region Section\n");
131 printf("FLREG0: 0x%08x\n", frba->flreg0);
132 printf("FLREG1: 0x%08x\n", frba->flreg1);
133 printf("FLREG2: 0x%08x\n", frba->flreg2);
134 printf("FLREG3: 0x%08x\n", frba->flreg3);
135 printf("FLREG4: 0x%08x\n", frba->flreg4);
138 static void decode_spi_frequency(unsigned int freq)
141 case SPI_FREQUENCY_20MHZ:
144 case SPI_FREQUENCY_33MHZ:
147 case SPI_FREQUENCY_50MHZ:
151 printf("unknown<%x>MHz", freq);
155 static void dump_fcba(fcba_t * fcba)
157 printf("\nFound Component Section\n");
158 printf("FLCOMP 0x%08x\n", fcba->flcomp);
159 printf(" Read ID/Read Status Clock Frequency: ");
160 decode_spi_frequency((fcba->flcomp >> 27) & 7);
161 printf("\n Write/Erase Clock Frequency: ");
162 decode_spi_frequency((fcba->flcomp >> 24) & 7);
163 printf("\n Fast Read Clock Frequency: ");
164 decode_spi_frequency((fcba->flcomp >> 21) & 7);
166 printf("FLILL 0x%08x\n", fcba->flill);
167 printf("FLPB 0x%08x\n", fcba->flpb);
170 static void dump_fpsba(fpsba_t * fpsba)
172 printf("\nFound PCH Strap Section\n");
173 printf("PCHSTRP0: 0x%08x\n", fpsba->pchstrp0);
174 printf("PCHSTRP1: 0x%08x\n", fpsba->pchstrp1);
175 printf("PCHSTRP2: 0x%08x\n", fpsba->pchstrp2);
176 printf("PCHSTRP3: 0x%08x\n", fpsba->pchstrp3);
177 printf("PCHSTRP4: 0x%08x\n", fpsba->pchstrp4);
178 printf("PCHSTRP5: 0x%08x\n", fpsba->pchstrp5);
179 printf("PCHSTRP6: 0x%08x\n", fpsba->pchstrp6);
180 printf("PCHSTRP7: 0x%08x\n", fpsba->pchstrp7);
181 printf("PCHSTRP8: 0x%08x\n", fpsba->pchstrp8);
182 printf("PCHSTRP9: 0x%08x\n", fpsba->pchstrp9);
183 printf("PCHSTRP10: 0x%08x\n", fpsba->pchstrp10);
184 printf("PCHSTRP11: 0x%08x\n", fpsba->pchstrp11);
185 printf("PCHSTRP12: 0x%08x\n", fpsba->pchstrp12);
186 printf("PCHSTRP13: 0x%08x\n", fpsba->pchstrp13);
187 printf("PCHSTRP14: 0x%08x\n", fpsba->pchstrp14);
188 printf("PCHSTRP15: 0x%08x\n", fpsba->pchstrp15);
191 static void dump_fmba(fmba_t * fmba)
193 printf("\nFound Master Section\n");
194 printf("FLMSTR1: 0x%08x\n", fmba->flmstr1);
195 printf("FLMSTR2: 0x%08x\n", fmba->flmstr2);
196 printf("FLMSTR3: 0x%08x\n", fmba->flmstr3);
199 static void dump_fmsba(fmsba_t * fmsba)
201 printf("\nFound Processor Strap Section\n");
202 printf("????: 0x%08x\n", fmsba->data[0]);
203 printf("????: 0x%08x\n", fmsba->data[1]);
204 printf("????: 0x%08x\n", fmsba->data[2]);
205 printf("????: 0x%08x\n", fmsba->data[3]);
208 static void dump_fd(char *image, int size)
210 fdbar_t *fdb = find_fd(image, size);
214 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
215 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
216 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
217 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
218 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
220 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
221 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
222 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
223 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
224 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
226 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
227 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
228 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
230 printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
233 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)));
234 dump_fcba((fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4)));
235 dump_fpsba((fpsba_t *)
236 (image + (((fdb->flmap1 >> 16) & 0xff) << 4)));
237 dump_fmba((fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4)));
238 dump_fmsba((fmsba_t *) (image + (((fdb->flmap2) & 0xff) << 4)));
241 static void write_regions(char *image, int size)
245 fdbar_t *fdb = find_fd(image, size);
250 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
252 for (i = 0; i<5; i++) {
253 region_t region = get_region(frba, i);
254 printf("Flash Region %d (%s): %08x - %08x %s\n",
255 i, region_name(i), region.base, region.limit,
256 region.size < 1 ? "(unused)" : "");
257 if (region.size > 0) {
259 region_fd = open(region_filename(i),
260 O_WRONLY | O_CREAT | O_TRUNC,
261 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
262 if (write(region_fd, image + region.base, region.size) != region.size)
263 printf("Error while writing.");
269 static void write_image(char *filename, char *image, int size)
271 char new_filename[FILENAME_MAX]; // allow long file names
274 strncpy(new_filename, filename, FILENAME_MAX);
275 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
277 printf("Writing new image to %s\n", new_filename);
279 // Now write out new image
280 new_fd = open(new_filename,
281 O_WRONLY | O_CREAT | O_TRUNC,
282 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
283 if (write(new_fd, image, size) != size)
284 printf("Error while writing.");
288 static void set_spi_frequency(char *filename, char *image, int size,
289 enum spi_frequency freq)
291 fdbar_t *fdb = find_fd(image, size);
292 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
294 /* clear bits 21-29 */
295 fcba->flcomp &= ~0x3fe00000;
296 /* Read ID and Read Status Clock Frequency */
297 fcba->flcomp |= freq << 27;
298 /* Write and Erase Clock Frequency */
299 fcba->flcomp |= freq << 24;
300 /* Fast Read Clock Frequency */
301 fcba->flcomp |= freq << 21;
303 write_image(filename, image, size);
306 void inject_region(char *filename, char *image, int size, int region_type,
309 fdbar_t *fdb = find_fd(image, size);
313 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
315 region_t region = get_region(frba, region_type);
316 if (region.size <= 0xfff) {
317 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
318 region_name(region_type));
322 int region_fd = open(region_fname, O_RDONLY);
323 if (region_fd == -1) {
324 perror("Could not open file");
328 if (fstat(region_fd, &buf) == -1) {
329 perror("Could not stat file");
332 int region_size = buf.st_size;
334 printf("File %s is %d bytes\n", region_fname, region_size);
336 if ( (region_size > region.size) || ((region_type != 1) &&
337 (region_size != region.size))) {
338 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
339 " bytes. Not injecting.\n",
340 region_name(region_type), region.size,
341 region.size, region_size, region_size);
346 if ((region_type == 1) && (region_size < region.size)) {
347 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
348 " bytes. Padding before injecting.\n",
349 region_name(region_type), region.size,
350 region.size, region_size, region_size);
351 offset = region.size - region_size;
352 memset(image + region.base, 0xff, offset);
355 if (read(region_fd, image + region.base + offset, region_size)
357 perror("Could not read file");
363 printf("Adding %s as the %s section of %s\n",
364 region_fname, region_name(region_type), filename);
365 write_image(filename, image, size);
368 static void print_version(void)
370 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
371 printf("Copyright (C) 2011 Google Inc.\n\n");
373 ("This program is free software: you can redistribute it and/or modify\n"
374 "it under the terms of the GNU General Public License as published by\n"
375 "the Free Software Foundation, version 2 of the License.\n\n"
376 "This program is distributed in the hope that it will be useful,\n"
377 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
378 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
379 "GNU General Public License for more details.\n\n"
380 "You should have received a copy of the GNU General Public License\n"
381 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n");
384 static void print_usage(const char *name)
386 printf("usage: %s [-vhdix?] <filename>\n", name);
388 " -d | --dump: dump intel firmware descriptor\n"
389 " -x | --extract: extract intel fd modules\n"
390 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
391 " -s | --spifreq <20|33|50> set the SPI frequency\n"
392 " -v | --version: print the version\n"
393 " -h | --help: print this help\n\n"
394 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
398 int main(int argc, char *argv[])
400 int opt, option_index = 0;
401 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
402 char *region_type_string = NULL, *region_fname = NULL;
403 int region_type = -1, inputfreq = 0;
404 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
406 static struct option long_options[] = {
407 {"dump", 0, NULL, 'd'},
408 {"extract", 0, NULL, 'x'},
409 {"inject", 1, NULL, 'i'},
410 {"spifreq", 1, NULL, 's'},
411 {"version", 0, NULL, 'v'},
412 {"help", 0, NULL, 'h'},
416 while ((opt = getopt_long(argc, argv, "dxi:s:vh?",
417 long_options, &option_index)) != EOF) {
426 // separate type and file name
427 region_type_string = strdup(optarg);
428 region_fname = strchr(region_type_string, ':');
430 print_usage(argv[0]);
433 region_fname[0] = '\0';
435 // Descriptor, BIOS, ME, GbE, Platform
437 if (!strcasecmp("Descriptor", region_type_string))
439 else if (!strcasecmp("BIOS", region_type_string))
441 else if (!strcasecmp("ME", region_type_string))
443 else if (!strcasecmp("GbE", region_type_string))
445 else if (!strcasecmp("Platform", region_type_string))
447 if (region_type == -1) {
448 fprintf(stderr, "No such region type: '%s'\n\n",
450 print_usage(argv[0]);
456 // Parse the requested SPI frequency
457 inputfreq = strtol(optarg, NULL, 0);
460 spifreq = SPI_FREQUENCY_20MHZ;
463 spifreq = SPI_FREQUENCY_33MHZ;
466 spifreq = SPI_FREQUENCY_50MHZ;
469 fprintf(stderr, "Invalid SPI Frequency: %d\n",
471 print_usage(argv[0]);
483 print_usage(argv[0]);
489 if ((mode_dump + mode_extract + mode_inject + mode_spifreq) > 1) {
490 fprintf(stderr, "Only one mode allowed.\n\n");
491 print_usage(argv[0]);
495 if ((mode_dump + mode_extract + mode_inject + mode_spifreq) == 0) {
496 fprintf(stderr, "You need to specify a mode.\n\n");
497 print_usage(argv[0]);
501 if (optind + 1 != argc) {
502 fprintf(stderr, "You need to specify a file.\n\n");
503 print_usage(argv[0]);
507 char *filename = argv[optind];
508 int bios_fd = open(filename, O_RDONLY);
510 perror("Could not open file");
514 if (fstat(bios_fd, &buf) == -1) {
515 perror("Could not stat file");
518 int size = buf.st_size;
520 printf("File %s is %d bytes\n", filename, size);
522 char *image = malloc(size);
524 printf("Out of memory.\n");
528 if (read(bios_fd, image, size) != size) {
529 perror("Could not read file");
536 dump_fd(image, size);
539 write_regions(image, size);
542 inject_region(filename, image, size, region_type,
546 set_spi_frequency(filename, image, size, spifreq);