Allow components smaller than declared size.
[coreboot.git] / util / ifdtool / ifdtool.c
1 /*
2  * ifdtool - dump Intel Firmware Descriptor information
3  *
4  * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
5  *
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.
9  *
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.
14  *
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
18  */
19
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <getopt.h>
25 #include <fcntl.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include "ifdtool.h"
29
30 static fdbar_t *find_fd(char *image, int size)
31 {
32         int i, found = 0;
33
34         /* Scan for FD signature */
35         for (i = 0; i < (size - 4); i += 4) {
36                 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
37                         found = 1;
38                         break;  // signature found.
39                 }
40         }
41
42         if (!found) {
43                 printf("No Flash Descriptor found in this image\n");
44                 return NULL;
45         }
46
47         printf("Found Flash Descriptor signature at 0x%08x\n", i);
48
49         return (fdbar_t *) (image + i);
50 }
51
52 typedef struct {
53         int base, limit, size;
54 } region_t;
55
56 static region_t get_region(frba_t *frba, int region_type)
57 {
58         region_t region;
59         region.base = 0, region.limit = 0, region.size = 0;
60
61         switch (region_type) {
62         case 0:
63                 region.base = (frba->flreg0 & 0x00000fff) << 12;
64                 region.limit = ((frba->flreg0 & 0x0fff0000) >> 4) | 0xfff;
65                 break;
66         case 1:
67                 region.base = (frba->flreg1 & 0x00000fff) << 12;
68                 region.limit = ((frba->flreg1 & 0x0fff0000) >> 4) | 0xfff;
69                 break;
70         case 2:
71                 region.base = (frba->flreg2 & 0x00000fff) << 12;
72                 region.limit = ((frba->flreg2 & 0x0fff0000) >> 4) | 0xfff;
73                 break;
74         case 3:
75                 region.base = (frba->flreg3 & 0x00000fff) << 12;
76                 region.limit = ((frba->flreg3 & 0x0fff0000) >> 4) | 0xfff;
77                 break;
78         case 4:
79                 region.base = (frba->flreg4 & 0x00000fff) << 12;
80                 region.limit = ((frba->flreg4 & 0x0fff0000) >> 4) | 0xfff;
81                 break;
82         default:
83                 fprintf(stderr, "Invalid region type.\n");
84                 exit (EXIT_FAILURE);
85         }
86
87         region.size = region.limit - region.base + 1;
88
89         return region;
90 }
91
92 static const char *region_name(int region_type)
93 {
94         static const char *regions[5] = {
95                 "Flash Descriptor",
96                 "BIOS",
97                 "Intel ME",
98                 "GbE",
99                 "Platform Data"
100         };
101
102         if (region_type < 0 || region_type > 4) {
103                 fprintf(stderr, "Invalid region type.\n");
104                 exit (EXIT_FAILURE);
105         }
106
107         return regions[region_type];
108 }
109
110 static const char *region_filename(int region_type)
111 {
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"
118         };
119
120         if (region_type < 0 || region_type > 4) {
121                 fprintf(stderr, "Invalid region type.\n");
122                 exit (EXIT_FAILURE);
123         }
124
125         return region_filenames[region_type];
126 }
127
128 static void dump_frba(frba_t * frba)
129 {
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);
136 }
137
138 static void decode_spi_frequency(unsigned int freq)
139 {
140         switch (freq) {
141         case SPI_FREQUENCY_20MHZ:
142                 printf("20MHz");
143                 break;
144         case SPI_FREQUENCY_33MHZ:
145                 printf("33MHz");
146                 break;
147         case SPI_FREQUENCY_50MHZ:
148                 printf("50MHz");
149                 break;
150         default:
151                 printf("unknown<%x>MHz", freq);
152         }
153 }
154
155 static void dump_fcba(fcba_t * fcba)
156 {
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);
165         printf("\n");
166         printf("FLILL      0x%08x\n", fcba->flill);
167         printf("FLPB       0x%08x\n", fcba->flpb);
168 }
169
170 static void dump_fpsba(fpsba_t * fpsba)
171 {
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);
189 }
190
191 static void dump_fmba(fmba_t * fmba)
192 {
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);
197 }
198
199 static void dump_fmsba(fmsba_t * fmsba)
200 {
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]);
206 }
207
208 static void dump_fd(char *image, int size)
209 {
210         fdbar_t *fdb = find_fd(image, size);
211         if (!fdb)
212                 exit(EXIT_FAILURE);
213
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);
219
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);
225
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);
229
230         printf("FLUMAP1:   0x%08x\n", fdb->flumap1);
231
232         dump_frba((frba_t *)
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)));
239 }
240
241 static void write_regions(char *image, int size)
242 {
243         int i;
244
245         fdbar_t *fdb = find_fd(image, size);
246         if (!fdb)
247                 exit(EXIT_FAILURE);
248
249         frba_t *frba =
250             (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
251
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) {
258                         int region_fd;
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.");
264                         close(region_fd);
265                 }
266         }
267 }
268
269 static void write_image(char *filename, char *image, int size)
270 {
271         char new_filename[FILENAME_MAX]; // allow long file names
272         int new_fd;
273
274         strncpy(new_filename, filename, FILENAME_MAX);
275         strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
276
277         printf("Writing new image to %s\n", new_filename);
278
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.");
285         close(new_fd);
286 }
287
288 static void set_spi_frequency(char *filename, char *image, int size,
289                               enum spi_frequency freq)
290 {
291         fdbar_t *fdb = find_fd(image, size);
292         fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
293
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;
302
303         write_image(filename, image, size);
304 }
305
306 void inject_region(char *filename, char *image, int size, int region_type,
307                    char *region_fname)
308 {
309         fdbar_t *fdb = find_fd(image, size);
310         if (!fdb)
311                 exit(EXIT_FAILURE);
312         frba_t *frba =
313             (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
314
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));
319                 exit(EXIT_FAILURE);
320         }
321
322         int region_fd = open(region_fname, O_RDONLY);
323         if (region_fd == -1) {
324                 perror("Could not open file");
325                 exit(EXIT_FAILURE);
326         }
327         struct stat buf;
328         if (fstat(region_fd, &buf) == -1) {
329                 perror("Could not stat file");
330                 exit(EXIT_FAILURE);
331         }
332         int region_size = buf.st_size;
333
334         printf("File %s is %d bytes\n", region_fname, region_size);
335
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);
342                 exit(EXIT_FAILURE);
343         }
344
345         int offset = 0;
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);
353         }
354
355         if (read(region_fd, image + region.base + offset, region_size)
356                                                         != region_size) {
357                 perror("Could not read file");
358                 exit(EXIT_FAILURE);
359         }
360
361         close(region_fd);
362
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);
366 }
367
368 static void print_version(void)
369 {
370         printf("ifdtool v%s -- ", IFDTOOL_VERSION);
371         printf("Copyright (C) 2011 Google Inc.\n\n");
372         printf
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");
382 }
383
384 static void print_usage(const char *name)
385 {
386         printf("usage: %s [-vhdix?] <filename>\n", name);
387         printf("\n"
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"
395                "\n");
396 }
397
398 int main(int argc, char *argv[])
399 {
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;
405
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'},
413                 {0, 0, 0, 0}
414         };
415
416         while ((opt = getopt_long(argc, argv, "dxi:s:vh?",
417                                   long_options, &option_index)) != EOF) {
418                 switch (opt) {
419                 case 'd':
420                         mode_dump = 1;
421                         break;
422                 case 'x':
423                         mode_extract = 1;
424                         break;
425                 case 'i':
426                         // separate type and file name
427                         region_type_string = strdup(optarg);
428                         region_fname = strchr(region_type_string, ':');
429                         if (!region_fname) {
430                                 print_usage(argv[0]);
431                                 exit(EXIT_FAILURE);
432                         }
433                         region_fname[0] = '\0';
434                         region_fname++;
435                         // Descriptor, BIOS, ME, GbE, Platform
436                         // valid type?
437                         if (!strcasecmp("Descriptor", region_type_string))
438                                 region_type = 0;
439                         else if (!strcasecmp("BIOS", region_type_string))
440                                 region_type = 1;
441                         else if (!strcasecmp("ME", region_type_string))
442                                 region_type = 2;
443                         else if (!strcasecmp("GbE", region_type_string))
444                                 region_type = 3;
445                         else if (!strcasecmp("Platform", region_type_string))
446                                 region_type = 4;
447                         if (region_type == -1) {
448                                 fprintf(stderr, "No such region type: '%s'\n\n",
449                                         region_type_string);
450                                 print_usage(argv[0]);
451                                 exit(EXIT_FAILURE);
452                         }
453                         mode_inject = 1;
454                         break;
455                 case 's':
456                         // Parse the requested SPI frequency
457                         inputfreq = strtol(optarg, NULL, 0);
458                         switch (inputfreq) {
459                         case 20:
460                                 spifreq = SPI_FREQUENCY_20MHZ;
461                                 break;
462                         case 33:
463                                 spifreq = SPI_FREQUENCY_33MHZ;
464                                 break;
465                         case 50:
466                                 spifreq = SPI_FREQUENCY_50MHZ;
467                                 break;
468                         default:
469                                 fprintf(stderr, "Invalid SPI Frequency: %d\n",
470                                         inputfreq);
471                                 print_usage(argv[0]);
472                                 exit(EXIT_FAILURE);
473                         }
474                         mode_spifreq = 1;
475                         break;
476                 case 'v':
477                         print_version();
478                         exit(EXIT_SUCCESS);
479                         break;
480                 case 'h':
481                 case '?':
482                 default:
483                         print_usage(argv[0]);
484                         exit(EXIT_SUCCESS);
485                         break;
486                 }
487         }
488
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]);
492                 exit(EXIT_FAILURE);
493         }
494
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]);
498                 exit(EXIT_FAILURE);
499         }
500
501         if (optind + 1 != argc) {
502                 fprintf(stderr, "You need to specify a file.\n\n");
503                 print_usage(argv[0]);
504                 exit(EXIT_FAILURE);
505         }
506
507         char *filename = argv[optind];
508         int bios_fd = open(filename, O_RDONLY);
509         if (bios_fd == -1) {
510                 perror("Could not open file");
511                 exit(EXIT_FAILURE);
512         }
513         struct stat buf;
514         if (fstat(bios_fd, &buf) == -1) {
515                 perror("Could not stat file");
516                 exit(EXIT_FAILURE);
517         }
518         int size = buf.st_size;
519
520         printf("File %s is %d bytes\n", filename, size);
521
522         char *image = malloc(size);
523         if (!image) {
524                 printf("Out of memory.\n");
525                 exit(EXIT_FAILURE);
526         }
527
528         if (read(bios_fd, image, size) != size) {
529                 perror("Could not read file");
530                 exit(EXIT_FAILURE);
531         }
532
533         close(bios_fd);
534
535         if (mode_dump)
536                 dump_fd(image, size);
537
538         if (mode_extract)
539                 write_regions(image, size);
540
541         if (mode_inject)
542                 inject_region(filename, image, size, region_type,
543                                 region_fname);
544
545         if (mode_spifreq)
546                 set_spi_frequency(filename, image, size, spifreq);
547
548         free(image);
549
550         return 0;
551 }