blob: 9569dfa4efc6e181287423ed69511da0a0983771 [file] [log] [blame]
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001/*
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
Scott Duplichanf2c98372014-12-12 21:03:06 -060030#ifndef O_BINARY
31#define O_BINARY 0
32#endif
33
Chris Douglasse2718652014-02-28 08:54:41 -050034#define NUM_REGIONS 5
35
36static const struct region_name region_names[NUM_REGIONS] = {
Chris Douglass03ce0142014-02-26 13:30:13 -050037 { "Flash Descriptor", "fd" },
38 { "BIOS", "bios" },
39 { "Intel ME", "me" },
40 { "GbE", "gbe" },
41 { "Platform Data", "pd" }
42};
43
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070044static fdbar_t *find_fd(char *image, int size)
45{
46 int i, found = 0;
47
48 /* Scan for FD signature */
49 for (i = 0; i < (size - 4); i += 4) {
50 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
51 found = 1;
52 break; // signature found.
53 }
54 }
55
56 if (!found) {
57 printf("No Flash Descriptor found in this image\n");
58 return NULL;
59 }
60
61 printf("Found Flash Descriptor signature at 0x%08x\n", i);
62
63 return (fdbar_t *) (image + i);
64}
65
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070066static region_t get_region(frba_t *frba, int region_type)
67{
68 region_t region;
69 region.base = 0, region.limit = 0, region.size = 0;
70
71 switch (region_type) {
72 case 0:
73 region.base = (frba->flreg0 & 0x00000fff) << 12;
74 region.limit = ((frba->flreg0 & 0x0fff0000) >> 4) | 0xfff;
75 break;
76 case 1:
77 region.base = (frba->flreg1 & 0x00000fff) << 12;
78 region.limit = ((frba->flreg1 & 0x0fff0000) >> 4) | 0xfff;
79 break;
80 case 2:
81 region.base = (frba->flreg2 & 0x00000fff) << 12;
82 region.limit = ((frba->flreg2 & 0x0fff0000) >> 4) | 0xfff;
83 break;
84 case 3:
85 region.base = (frba->flreg3 & 0x00000fff) << 12;
86 region.limit = ((frba->flreg3 & 0x0fff0000) >> 4) | 0xfff;
87 break;
88 case 4:
89 region.base = (frba->flreg4 & 0x00000fff) << 12;
90 region.limit = ((frba->flreg4 & 0x0fff0000) >> 4) | 0xfff;
91 break;
92 default:
93 fprintf(stderr, "Invalid region type.\n");
94 exit (EXIT_FAILURE);
95 }
96
97 region.size = region.limit - region.base + 1;
Chris Douglass03ce0142014-02-26 13:30:13 -050098 if (region.size < 0)
99 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700100
101 return region;
102}
103
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500104static void set_region(frba_t *frba, int region_type, region_t region)
105{
106 switch (region_type) {
107 case 0:
108 frba->flreg0 = (((region.limit >> 12) & 0x7fff) << 16)
109 | ((region.base >> 12) & 0x7fff);
110 break;
111 case 1:
112 frba->flreg1 = (((region.limit >> 12) & 0x7fff) << 16)
113 | ((region.base >> 12) & 0x7fff);
114 break;
115 case 2:
116 frba->flreg2 = (((region.limit >> 12) & 0x7fff) << 16)
117 | ((region.base >> 12) & 0x7fff);
118 break;
119 case 3:
120 frba->flreg3 = (((region.limit >> 12) & 0x7fff) << 16)
121 | ((region.base >> 12) & 0x7fff);
122 break;
123 case 4:
124 frba->flreg4 = (((region.limit >> 12) & 0x7fff) << 16)
125 | ((region.base >> 12) & 0x7fff);
126 break;
127 default:
128 fprintf(stderr, "Invalid region type.\n");
129 exit (EXIT_FAILURE);
130 }
131}
132
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700133static const char *region_name(int region_type)
134{
Chris Douglasse2718652014-02-28 08:54:41 -0500135 if (region_type < 0 || region_type >= NUM_REGIONS) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700136 fprintf(stderr, "Invalid region type.\n");
137 exit (EXIT_FAILURE);
138 }
139
Chris Douglass03ce0142014-02-26 13:30:13 -0500140 return region_names[region_type].pretty;
141}
142
143static const char *region_name_short(int region_type)
144{
Chris Douglasse2718652014-02-28 08:54:41 -0500145 if (region_type < 0 || region_type >= NUM_REGIONS) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500146 fprintf(stderr, "Invalid region type.\n");
147 exit (EXIT_FAILURE);
148 }
149
150 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700151}
152
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500153static int region_num(const char *name)
154{
155 int i;
156
Chris Douglasse2718652014-02-28 08:54:41 -0500157 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500158 if (strcasecmp(name, region_names[i].pretty) == 0)
159 return i;
160 if (strcasecmp(name, region_names[i].terse) == 0)
161 return i;
162 }
163
164 return -1;
165}
166
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700167static const char *region_filename(int region_type)
168{
Chris Douglasse2718652014-02-28 08:54:41 -0500169 static const char *region_filenames[NUM_REGIONS] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700170 "flashregion_0_flashdescriptor.bin",
171 "flashregion_1_bios.bin",
172 "flashregion_2_intel_me.bin",
173 "flashregion_3_gbe.bin",
174 "flashregion_4_platform_data.bin"
175 };
176
Chris Douglasse2718652014-02-28 08:54:41 -0500177 if (region_type < 0 || region_type >= NUM_REGIONS) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700178 fprintf(stderr, "Invalid region type.\n");
179 exit (EXIT_FAILURE);
180 }
181
182 return region_filenames[region_type];
183}
184
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700185static void dump_region(int num, frba_t *frba)
186{
187 region_t region = get_region(frba, num);
188 printf(" Flash Region %d (%s): %08x - %08x %s\n",
189 num, region_name(num), region.base, region.limit,
190 region.size < 1 ? "(unused)" : "");
191}
192
Chris Douglass03ce0142014-02-26 13:30:13 -0500193static void dump_region_layout(char *buf, size_t bufsize, int num, frba_t *frba)
194{
195 region_t region = get_region(frba, num);
196 snprintf(buf, bufsize, "%08x:%08x %s\n",
197 region.base, region.limit, region_name_short(num));
198}
199
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700200static void dump_frba(frba_t * frba)
201{
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700202 printf("Found Region Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700203 printf("FLREG0: 0x%08x\n", frba->flreg0);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700204 dump_region(0, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700205 printf("FLREG1: 0x%08x\n", frba->flreg1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700206 dump_region(1, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700207 printf("FLREG2: 0x%08x\n", frba->flreg2);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700208 dump_region(2, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700209 printf("FLREG3: 0x%08x\n", frba->flreg3);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700210 dump_region(3, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700211 printf("FLREG4: 0x%08x\n", frba->flreg4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700212 dump_region(4, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700213}
214
Chris Douglass03ce0142014-02-26 13:30:13 -0500215static void dump_frba_layout(frba_t * frba, char *layout_fname)
216{
217 char buf[LAYOUT_LINELEN];
218 size_t bufsize = LAYOUT_LINELEN;
219 int i;
220
221 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
222 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
223 if (layout_fd == -1) {
224 perror("Could not open file");
225 exit(EXIT_FAILURE);
226 }
227
Chris Douglasse2718652014-02-28 08:54:41 -0500228 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500229 dump_region_layout(buf, bufsize, i, frba);
230 if (write(layout_fd, buf, strlen(buf)) < 0) {
231 perror("Could not write to file");
232 exit(EXIT_FAILURE);
233 }
234 }
235 close(layout_fd);
236 printf("Wrote layout to %s\n", layout_fname);
237}
238
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700239static void decode_spi_frequency(unsigned int freq)
240{
241 switch (freq) {
242 case SPI_FREQUENCY_20MHZ:
243 printf("20MHz");
244 break;
245 case SPI_FREQUENCY_33MHZ:
246 printf("33MHz");
247 break;
248 case SPI_FREQUENCY_50MHZ:
249 printf("50MHz");
250 break;
251 default:
252 printf("unknown<%x>MHz", freq);
253 }
254}
255
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700256static void decode_component_density(unsigned int density)
257{
258 switch (density) {
259 case COMPONENT_DENSITY_512KB:
260 printf("512KB");
261 break;
262 case COMPONENT_DENSITY_1MB:
263 printf("1MB");
264 break;
265 case COMPONENT_DENSITY_2MB:
266 printf("2MB");
267 break;
268 case COMPONENT_DENSITY_4MB:
269 printf("4MB");
270 break;
271 case COMPONENT_DENSITY_8MB:
272 printf("8MB");
273 break;
274 case COMPONENT_DENSITY_16MB:
275 printf("16MB");
276 break;
277 default:
278 printf("unknown<%x>MB", density);
279 }
280}
281
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700282static void dump_fcba(fcba_t * fcba)
283{
284 printf("\nFound Component Section\n");
285 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700286 printf(" Dual Output Fast Read Support: %ssupported\n",
287 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700288 printf(" Read ID/Read Status Clock Frequency: ");
289 decode_spi_frequency((fcba->flcomp >> 27) & 7);
290 printf("\n Write/Erase Clock Frequency: ");
291 decode_spi_frequency((fcba->flcomp >> 24) & 7);
292 printf("\n Fast Read Clock Frequency: ");
293 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700294 printf("\n Fast Read Support: %ssupported",
295 (fcba->flcomp & (1 << 20))?"":"not ");
296 printf("\n Read Clock Frequency: ");
297 decode_spi_frequency((fcba->flcomp >> 17) & 7);
298 printf("\n Component 2 Density: ");
299 decode_component_density((fcba->flcomp >> 3) & 7);
300 printf("\n Component 1 Density: ");
301 decode_component_density(fcba->flcomp & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700302 printf("\n");
303 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700304 printf(" Invalid Instruction 3: 0x%02x\n",
305 (fcba->flill >> 24) & 0xff);
306 printf(" Invalid Instruction 2: 0x%02x\n",
307 (fcba->flill >> 16) & 0xff);
308 printf(" Invalid Instruction 1: 0x%02x\n",
309 (fcba->flill >> 8) & 0xff);
310 printf(" Invalid Instruction 0: 0x%02x\n",
311 fcba->flill & 0xff);
312 printf("FLPB 0x%08x\n", fcba->flpb);
313 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
314 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700315}
316
317static void dump_fpsba(fpsba_t * fpsba)
318{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700319 printf("Found PCH Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700320 printf("PCHSTRP0: 0x%08x\n", fpsba->pchstrp0);
321 printf("PCHSTRP1: 0x%08x\n", fpsba->pchstrp1);
322 printf("PCHSTRP2: 0x%08x\n", fpsba->pchstrp2);
323 printf("PCHSTRP3: 0x%08x\n", fpsba->pchstrp3);
324 printf("PCHSTRP4: 0x%08x\n", fpsba->pchstrp4);
325 printf("PCHSTRP5: 0x%08x\n", fpsba->pchstrp5);
326 printf("PCHSTRP6: 0x%08x\n", fpsba->pchstrp6);
327 printf("PCHSTRP7: 0x%08x\n", fpsba->pchstrp7);
328 printf("PCHSTRP8: 0x%08x\n", fpsba->pchstrp8);
329 printf("PCHSTRP9: 0x%08x\n", fpsba->pchstrp9);
330 printf("PCHSTRP10: 0x%08x\n", fpsba->pchstrp10);
331 printf("PCHSTRP11: 0x%08x\n", fpsba->pchstrp11);
332 printf("PCHSTRP12: 0x%08x\n", fpsba->pchstrp12);
333 printf("PCHSTRP13: 0x%08x\n", fpsba->pchstrp13);
334 printf("PCHSTRP14: 0x%08x\n", fpsba->pchstrp14);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700335 printf("PCHSTRP15: 0x%08x\n", fpsba->pchstrp15);
336 printf("PCHSTRP16: 0x%08x\n", fpsba->pchstrp16);
337 printf("PCHSTRP17: 0x%08x\n\n", fpsba->pchstrp17);
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700338}
339
340static void decode_flmstr(uint32_t flmstr)
341{
342 printf(" Platform Data Region Write Access: %s\n",
343 (flmstr & (1 << 28)) ? "enabled" : "disabled");
344 printf(" GbE Region Write Access: %s\n",
345 (flmstr & (1 << 27)) ? "enabled" : "disabled");
346 printf(" Intel ME Region Write Access: %s\n",
347 (flmstr & (1 << 26)) ? "enabled" : "disabled");
348 printf(" Host CPU/BIOS Region Write Access: %s\n",
349 (flmstr & (1 << 25)) ? "enabled" : "disabled");
350 printf(" Flash Descriptor Write Access: %s\n",
351 (flmstr & (1 << 24)) ? "enabled" : "disabled");
352
353 printf(" Platform Data Region Read Access: %s\n",
354 (flmstr & (1 << 20)) ? "enabled" : "disabled");
355 printf(" GbE Region Read Access: %s\n",
356 (flmstr & (1 << 19)) ? "enabled" : "disabled");
357 printf(" Intel ME Region Read Access: %s\n",
358 (flmstr & (1 << 18)) ? "enabled" : "disabled");
359 printf(" Host CPU/BIOS Region Read Access: %s\n",
360 (flmstr & (1 << 17)) ? "enabled" : "disabled");
361 printf(" Flash Descriptor Read Access: %s\n",
362 (flmstr & (1 << 16)) ? "enabled" : "disabled");
363
364 printf(" Requester ID: 0x%04x\n\n",
365 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700366}
367
368static void dump_fmba(fmba_t * fmba)
369{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700370 printf("Found Master Section\n");
371 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
372 decode_flmstr(fmba->flmstr1);
373 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
374 decode_flmstr(fmba->flmstr2);
375 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
376 decode_flmstr(fmba->flmstr3);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700377}
378
379static void dump_fmsba(fmsba_t * fmsba)
380{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700381 printf("Found Processor Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700382 printf("????: 0x%08x\n", fmsba->data[0]);
383 printf("????: 0x%08x\n", fmsba->data[1]);
384 printf("????: 0x%08x\n", fmsba->data[2]);
385 printf("????: 0x%08x\n", fmsba->data[3]);
386}
387
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700388static void dump_jid(uint32_t jid)
389{
390 printf(" SPI Componend Device ID 1: 0x%02x\n",
391 (jid >> 16) & 0xff);
392 printf(" SPI Componend Device ID 0: 0x%02x\n",
393 (jid >> 8) & 0xff);
394 printf(" SPI Componend Vendor ID: 0x%02x\n",
395 jid & 0xff);
396}
397
398static void dump_vscc(uint32_t vscc)
399{
400 printf(" Lower Erase Opcode: 0x%02x\n",
401 vscc >> 24);
402 printf(" Lower Write Enable on Write Status: 0x%02x\n",
403 vscc & (1 << 20) ? 0x06 : 0x50);
404 printf(" Lower Write Status Required: %s\n",
405 vscc & (1 << 19) ? "Yes" : "No");
406 printf(" Lower Write Granularity: %d bytes\n",
407 vscc & (1 << 18) ? 64 : 1);
408 printf(" Lower Block / Sector Erase Size: ");
409 switch ((vscc >> 16) & 0x3) {
410 case 0:
411 printf("256 Byte\n");
412 break;
413 case 1:
414 printf("4KB\n");
415 break;
416 case 2:
417 printf("8KB\n");
418 break;
419 case 3:
420 printf("64KB\n");
421 break;
422 }
423
424 printf(" Upper Erase Opcode: 0x%02x\n",
425 (vscc >> 8) & 0xff);
426 printf(" Upper Write Enable on Write Status: 0x%02x\n",
427 vscc & (1 << 4) ? 0x06 : 0x50);
428 printf(" Upper Write Status Required: %s\n",
429 vscc & (1 << 3) ? "Yes" : "No");
430 printf(" Upper Write Granularity: %d bytes\n",
431 vscc & (1 << 2) ? 64 : 1);
432 printf(" Upper Block / Sector Erase Size: ");
433 switch (vscc & 0x3) {
434 case 0:
435 printf("256 Byte\n");
436 break;
437 case 1:
438 printf("4KB\n");
439 break;
440 case 2:
441 printf("8KB\n");
442 break;
443 case 3:
444 printf("64KB\n");
445 break;
446 }
447}
448
449static void dump_vtba(vtba_t *vtba, int vtl)
450{
451 int i;
452 int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
453
454 printf("ME VSCC table:\n");
455 for (i = 0; i < num; i++) {
456 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
457 dump_jid(vtba->entry[i].jid);
458 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
459 dump_vscc(vtba->entry[i].vscc);
460 }
461 printf("\n");
462}
463
464static void dump_oem(uint8_t *oem)
465{
466 int i, j;
467 printf("OEM Section:\n");
468 for (i = 0; i < 4; i++) {
469 printf("%02x:", i << 4);
470 for (j = 0; j < 16; j++)
471 printf(" %02x", oem[(i<<4)+j]);
472 printf ("\n");
473 }
474 printf ("\n");
475}
476
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700477static void dump_fd(char *image, int size)
478{
479 fdbar_t *fdb = find_fd(image, size);
480 if (!fdb)
481 exit(EXIT_FAILURE);
482
483 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
484 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
485 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
486 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
487 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
488
489 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
490 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
491 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
492 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
493 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
494
495 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
496 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
497 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
498
499 printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700500 printf(" Intel ME VSCC Table Length (VTL): %d\n",
501 (fdb->flumap1 >> 8) & 0xff);
502 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
503 (fdb->flumap1 & 0xff) << 4);
504 dump_vtba((vtba_t *)
505 (image + ((fdb->flumap1 & 0xff) << 4)),
506 (fdb->flumap1 >> 8) & 0xff);
507 dump_oem((uint8_t *)image + 0xf00);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700508 dump_frba((frba_t *)
509 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)));
510 dump_fcba((fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4)));
511 dump_fpsba((fpsba_t *)
512 (image + (((fdb->flmap1 >> 16) & 0xff) << 4)));
513 dump_fmba((fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4)));
514 dump_fmsba((fmsba_t *) (image + (((fdb->flmap2) & 0xff) << 4)));
515}
516
Chris Douglass03ce0142014-02-26 13:30:13 -0500517static void dump_layout(char *image, int size, char *layout_fname)
518{
519 fdbar_t *fdb = find_fd(image, size);
520 if (!fdb)
521 exit(EXIT_FAILURE);
522
523 dump_frba_layout((frba_t *)
524 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)),
525 layout_fname);
526}
527
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700528static void write_regions(char *image, int size)
529{
530 int i;
531
532 fdbar_t *fdb = find_fd(image, size);
533 if (!fdb)
534 exit(EXIT_FAILURE);
535
536 frba_t *frba =
537 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
538
Chris Douglasse2718652014-02-28 08:54:41 -0500539 for (i = 0; i < NUM_REGIONS; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700540 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700541 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700542 if (region.size > 0) {
543 int region_fd;
544 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600545 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700546 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200547 if (region_fd < 0) {
548 perror("Error while trying to open file");
549 exit(EXIT_FAILURE);
550 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700551 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700552 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700553 close(region_fd);
554 }
555 }
556}
557
558static void write_image(char *filename, char *image, int size)
559{
560 char new_filename[FILENAME_MAX]; // allow long file names
561 int new_fd;
562
Patrick Georgi440daf72014-08-03 12:14:25 +0200563 // - 5: leave room for ".new\0"
564 strncpy(new_filename, filename, FILENAME_MAX - 5);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700565 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
566
567 printf("Writing new image to %s\n", new_filename);
568
569 // Now write out new image
570 new_fd = open(new_filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600571 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700572 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200573 if (new_fd < 0) {
574 perror("Error while trying to open file");
575 exit(EXIT_FAILURE);
576 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700577 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700578 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700579 close(new_fd);
580}
581
582static void set_spi_frequency(char *filename, char *image, int size,
583 enum spi_frequency freq)
584{
585 fdbar_t *fdb = find_fd(image, size);
586 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
587
588 /* clear bits 21-29 */
589 fcba->flcomp &= ~0x3fe00000;
590 /* Read ID and Read Status Clock Frequency */
591 fcba->flcomp |= freq << 27;
592 /* Write and Erase Clock Frequency */
593 fcba->flcomp |= freq << 24;
594 /* Fast Read Clock Frequency */
595 fcba->flcomp |= freq << 21;
596
597 write_image(filename, image, size);
598}
599
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700600static void set_em100_mode(char *filename, char *image, int size)
601{
602 fdbar_t *fdb = find_fd(image, size);
603 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
604
605 fcba->flcomp &= ~(1 << 30);
606 set_spi_frequency(filename, image, size, SPI_FREQUENCY_20MHZ);
607}
608
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700609static void lock_descriptor(char *filename, char *image, int size)
610{
611 fdbar_t *fdb = find_fd(image, size);
612 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
613 /* TODO: Dynamically take Platform Data Region and GbE Region
614 * into regard.
615 */
616 fmba->flmstr1 = 0x0a0b0000;
617 fmba->flmstr2 = 0x0c0d0000;
618 fmba->flmstr3 = 0x08080118;
619
620 write_image(filename, image, size);
621}
622
623static void unlock_descriptor(char *filename, char *image, int size)
624{
625 fdbar_t *fdb = find_fd(image, size);
626 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
627 fmba->flmstr1 = 0xffff0000;
628 fmba->flmstr2 = 0xffff0000;
629 fmba->flmstr3 = 0x08080118;
630
631 write_image(filename, image, size);
632}
633
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700634void inject_region(char *filename, char *image, int size, int region_type,
635 char *region_fname)
636{
637 fdbar_t *fdb = find_fd(image, size);
638 if (!fdb)
639 exit(EXIT_FAILURE);
640 frba_t *frba =
641 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700642
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700643 region_t region = get_region(frba, region_type);
644 if (region.size <= 0xfff) {
645 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
646 region_name(region_type));
647 exit(EXIT_FAILURE);
648 }
649
Scott Duplichanf2c98372014-12-12 21:03:06 -0600650 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700651 if (region_fd == -1) {
652 perror("Could not open file");
653 exit(EXIT_FAILURE);
654 }
655 struct stat buf;
656 if (fstat(region_fd, &buf) == -1) {
657 perror("Could not stat file");
658 exit(EXIT_FAILURE);
659 }
660 int region_size = buf.st_size;
661
662 printf("File %s is %d bytes\n", region_fname, region_size);
663
664 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -0800665 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700666 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
667 " bytes. Not injecting.\n",
668 region_name(region_type), region.size,
669 region.size, region_size, region_size);
670 exit(EXIT_FAILURE);
671 }
672
673 int offset = 0;
674 if ((region_type == 1) && (region_size < region.size)) {
675 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
676 " bytes. Padding before injecting.\n",
677 region_name(region_type), region.size,
678 region.size, region_size, region_size);
679 offset = region.size - region_size;
680 memset(image + region.base, 0xff, offset);
681 }
682
Stefan Reinauer5e93b372012-09-25 13:30:48 -0700683 if (size < region.base + offset + region_size) {
684 fprintf(stderr, "Output file is too small. (%d < %d)\n",
685 size, region.base + offset + region_size);
686 exit(EXIT_FAILURE);
687 }
688
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700689 if (read(region_fd, image + region.base + offset, region_size)
690 != region_size) {
691 perror("Could not read file");
692 exit(EXIT_FAILURE);
693 }
694
695 close(region_fd);
696
697 printf("Adding %s as the %s section of %s\n",
698 region_fname, region_name(region_type), filename);
699 write_image(filename, image, size);
700}
701
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500702unsigned int next_pow2(unsigned int x)
703{
704 unsigned int y = 1;
705 if (x == 0)
706 return 0;
707 while (y <= x)
708 y = y << 1;
709
710 return y;
711}
712
713/**
714 * Determine if two memory regions overlap.
715 *
716 * @param r1, r2 Memory regions to compare.
717 * @return 0 if the two regions are seperate
718 * @return 1 if the two regions overlap
719 */
720static int regions_collide(region_t r1, region_t r2)
721{
722 if ((r1.size == 0) || (r2.size == 0))
723 return 0;
724
725 if ( ((r1.base >= r2.base) && (r1.base <= r2.limit)) ||
726 ((r1.limit >= r2.base) && (r1.limit <= r2.limit)) )
727 return 1;
728
729 return 0;
730}
731
732void new_layout(char *filename, char *image, int size, char *layout_fname)
733{
734 FILE *romlayout;
735 char tempstr[256];
736 char layout_region_name[256];
737 int i, j;
738 int region_number;
Chris Douglasse2718652014-02-28 08:54:41 -0500739 region_t current_regions[NUM_REGIONS];
740 region_t new_regions[NUM_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500741 int new_extent = 0;
742 char *new_image;
743
744 /* load current descriptor map and regions */
745 fdbar_t *fdb = find_fd(image, size);
746 if (!fdb)
747 exit(EXIT_FAILURE);
748
749 frba_t *frba =
750 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
751
Chris Douglasse2718652014-02-28 08:54:41 -0500752 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500753 current_regions[i] = get_region(frba, i);
754 new_regions[i] = get_region(frba, i);
755 }
756
757 /* read new layout */
758 romlayout = fopen(layout_fname, "r");
759
760 if (!romlayout) {
761 perror("Could not read layout file.\n");
762 exit(EXIT_FAILURE);
763 }
764
765 while (!feof(romlayout)) {
766 char *tstr1, *tstr2;
767
Patrick Georgi802ad522014-08-09 17:12:23 +0200768 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500769 layout_region_name))
770 continue;
771
772 region_number = region_num(layout_region_name);
773 if (region_number < 0)
774 continue;
775
776 tstr1 = strtok(tempstr, ":");
777 tstr2 = strtok(NULL, ":");
778 if (!tstr1 || !tstr2) {
779 fprintf(stderr, "Could not parse layout file.\n");
780 exit(EXIT_FAILURE);
781 }
782 new_regions[region_number].base = strtol(tstr1,
783 (char **)NULL, 16);
784 new_regions[region_number].limit = strtol(tstr2,
785 (char **)NULL, 16);
786 new_regions[region_number].size =
787 new_regions[region_number].limit -
788 new_regions[region_number].base + 1;
789
790 if (new_regions[region_number].size < 0)
791 new_regions[region_number].size = 0;
792 }
793 fclose(romlayout);
794
795 /* check new layout */
Chris Douglasse2718652014-02-28 08:54:41 -0500796 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500797 if (new_regions[i].size == 0)
798 continue;
799
800 if (new_regions[i].size < current_regions[i].size) {
801 printf("DANGER: Region %s is shrinking.\n",
802 region_name(i));
803 printf(" The region will be truncated to fit.\n");
804 printf(" This may result in an unusable image.\n");
805 }
806
Chris Douglasse2718652014-02-28 08:54:41 -0500807 for (j = i + 1; j < NUM_REGIONS; j++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500808 if (regions_collide(new_regions[i], new_regions[j])) {
809 fprintf(stderr, "Regions would overlap.\n");
810 exit(EXIT_FAILURE);
811 }
812 }
813
814 /* detect if the image size should grow */
815 if (new_extent < new_regions[i].limit)
816 new_extent = new_regions[i].limit;
817 }
818
819 new_extent = next_pow2(new_extent - 1);
820 if (new_extent != size) {
821 printf("The image has changed in size.\n");
822 printf("The old image is %d bytes.\n", size);
823 printf("The new image is %d bytes.\n", new_extent);
824 }
825
826 /* copy regions to a new image */
827 new_image = malloc(new_extent);
828 memset(new_image, 0xff, new_extent);
Chris Douglasse2718652014-02-28 08:54:41 -0500829 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500830 int copy_size = new_regions[i].size;
831 int offset_current = 0, offset_new = 0;
832 region_t current = current_regions[i];
833 region_t new = new_regions[i];
834
835 if (new.size == 0)
836 continue;
837
838 if (new.size > current.size) {
839 /* copy from the end of the current region */
840 copy_size = current.size;
841 offset_new = new.size - current.size;
842 }
843
844 if (new.size < current.size) {
845 /* copy to the end of the new region */
846 offset_current = current.size - new.size;
847 }
848
849 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
850 region_name(i), copy_size);
851 printf(" from %08x+%08x:%08x (%10d)\n", current.base,
852 offset_current, current.limit, current.size);
853 printf(" to %08x+%08x:%08x (%10d)\n", new.base,
854 offset_new, new.limit, new.size);
855
856 memcpy(new_image + new.base + offset_new,
857 image + current.base + offset_current,
858 copy_size);
859 }
860
861 /* update new descriptor regions */
862 fdb = find_fd(new_image, new_extent);
863 if (!fdb)
864 exit(EXIT_FAILURE);
865
866 frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Chris Douglasse2718652014-02-28 08:54:41 -0500867 for (i = 1; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500868 set_region(frba, i, new_regions[i]);
869 }
870
871 write_image(filename, new_image, new_extent);
872 free(new_image);
873}
874
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700875static void print_version(void)
876{
877 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
878 printf("Copyright (C) 2011 Google Inc.\n\n");
879 printf
880 ("This program is free software: you can redistribute it and/or modify\n"
881 "it under the terms of the GNU General Public License as published by\n"
882 "the Free Software Foundation, version 2 of the License.\n\n"
883 "This program is distributed in the hope that it will be useful,\n"
884 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
885 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
886 "GNU General Public License for more details.\n\n"
887 "You should have received a copy of the GNU General Public License\n"
888 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n");
889}
890
891static void print_usage(const char *name)
892{
893 printf("usage: %s [-vhdix?] <filename>\n", name);
894 printf("\n"
895 " -d | --dump: dump intel firmware descriptor\n"
Chris Douglass03ce0142014-02-26 13:30:13 -0500896 " -f | --layout <filename> dump regions into a flashrom layout file\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700897 " -x | --extract: extract intel fd modules\n"
898 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500899 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700900 " -s | --spifreq <20|33|50> set the SPI frequency\n"
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700901 " -e | --em100 set SPI frequency to 20MHz and disable\n"
902 " Dual Output Fast Read Support\n"
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700903 " -l | --lock Lock firmware descriptor and ME region\n"
904 " -u | --unlock Unlock firmware descriptor and ME region\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700905 " -v | --version: print the version\n"
906 " -h | --help: print this help\n\n"
907 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
908 "\n");
909}
910
911int main(int argc, char *argv[])
912{
913 int opt, option_index = 0;
914 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700915 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500916 int mode_layout = 0, mode_newlayout = 0;
Chris Douglass03ce0142014-02-26 13:30:13 -0500917 char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700918 int region_type = -1, inputfreq = 0;
919 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
920
921 static struct option long_options[] = {
922 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -0500923 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700924 {"extract", 0, NULL, 'x'},
925 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500926 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700927 {"spifreq", 1, NULL, 's'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700928 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700929 {"lock", 0, NULL, 'l'},
930 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700931 {"version", 0, NULL, 'v'},
932 {"help", 0, NULL, 'h'},
933 {0, 0, 0, 0}
934 };
935
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500936 while ((opt = getopt_long(argc, argv, "df:xi:n:s:eluvh?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700937 long_options, &option_index)) != EOF) {
938 switch (opt) {
939 case 'd':
940 mode_dump = 1;
941 break;
Chris Douglass03ce0142014-02-26 13:30:13 -0500942 case 'f':
943 mode_layout = 1;
944 layout_fname = strdup(optarg);
945 if (!layout_fname) {
946 fprintf(stderr, "No layout file specified\n");
947 print_usage(argv[0]);
948 exit(EXIT_FAILURE);
949 }
950 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700951 case 'x':
952 mode_extract = 1;
953 break;
954 case 'i':
955 // separate type and file name
956 region_type_string = strdup(optarg);
957 region_fname = strchr(region_type_string, ':');
958 if (!region_fname) {
959 print_usage(argv[0]);
960 exit(EXIT_FAILURE);
961 }
962 region_fname[0] = '\0';
963 region_fname++;
964 // Descriptor, BIOS, ME, GbE, Platform
965 // valid type?
966 if (!strcasecmp("Descriptor", region_type_string))
967 region_type = 0;
968 else if (!strcasecmp("BIOS", region_type_string))
969 region_type = 1;
970 else if (!strcasecmp("ME", region_type_string))
971 region_type = 2;
972 else if (!strcasecmp("GbE", region_type_string))
973 region_type = 3;
974 else if (!strcasecmp("Platform", region_type_string))
975 region_type = 4;
976 if (region_type == -1) {
977 fprintf(stderr, "No such region type: '%s'\n\n",
978 region_type_string);
979 print_usage(argv[0]);
980 exit(EXIT_FAILURE);
981 }
982 mode_inject = 1;
983 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500984 case 'n':
985 mode_newlayout = 1;
986 layout_fname = strdup(optarg);
987 if (!layout_fname) {
988 fprintf(stderr, "No layout file specified\n");
989 print_usage(argv[0]);
990 exit(EXIT_FAILURE);
991 }
992 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700993 case 's':
994 // Parse the requested SPI frequency
995 inputfreq = strtol(optarg, NULL, 0);
996 switch (inputfreq) {
997 case 20:
998 spifreq = SPI_FREQUENCY_20MHZ;
999 break;
1000 case 33:
1001 spifreq = SPI_FREQUENCY_33MHZ;
1002 break;
1003 case 50:
1004 spifreq = SPI_FREQUENCY_50MHZ;
1005 break;
1006 default:
1007 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1008 inputfreq);
1009 print_usage(argv[0]);
1010 exit(EXIT_FAILURE);
1011 }
1012 mode_spifreq = 1;
1013 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001014 case 'e':
1015 mode_em100 = 1;
1016 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001017 case 'l':
1018 mode_locked = 1;
1019 if (mode_unlocked == 1) {
1020 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1021 exit(EXIT_FAILURE);
1022 }
1023 break;
1024 case 'u':
1025 mode_unlocked = 1;
1026 if (mode_locked == 1) {
1027 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1028 exit(EXIT_FAILURE);
1029 }
1030 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001031 case 'v':
1032 print_version();
1033 exit(EXIT_SUCCESS);
1034 break;
1035 case 'h':
1036 case '?':
1037 default:
1038 print_usage(argv[0]);
1039 exit(EXIT_SUCCESS);
1040 break;
1041 }
1042 }
1043
Chris Douglass03ce0142014-02-26 13:30:13 -05001044 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001045 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001046 mode_locked)) > 1) {
1047 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001048 print_usage(argv[0]);
1049 exit(EXIT_FAILURE);
1050 }
1051
Chris Douglass03ce0142014-02-26 13:30:13 -05001052 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001053 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Chris Douglass03ce0142014-02-26 13:30:13 -05001054 mode_unlocked) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001055 fprintf(stderr, "You need to specify a mode.\n\n");
1056 print_usage(argv[0]);
1057 exit(EXIT_FAILURE);
1058 }
1059
1060 if (optind + 1 != argc) {
1061 fprintf(stderr, "You need to specify a file.\n\n");
1062 print_usage(argv[0]);
1063 exit(EXIT_FAILURE);
1064 }
1065
1066 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001067 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001068 if (bios_fd == -1) {
1069 perror("Could not open file");
1070 exit(EXIT_FAILURE);
1071 }
1072 struct stat buf;
1073 if (fstat(bios_fd, &buf) == -1) {
1074 perror("Could not stat file");
1075 exit(EXIT_FAILURE);
1076 }
1077 int size = buf.st_size;
1078
1079 printf("File %s is %d bytes\n", filename, size);
1080
1081 char *image = malloc(size);
1082 if (!image) {
1083 printf("Out of memory.\n");
1084 exit(EXIT_FAILURE);
1085 }
1086
1087 if (read(bios_fd, image, size) != size) {
1088 perror("Could not read file");
1089 exit(EXIT_FAILURE);
1090 }
1091
1092 close(bios_fd);
1093
1094 if (mode_dump)
1095 dump_fd(image, size);
1096
Chris Douglass03ce0142014-02-26 13:30:13 -05001097 if (mode_layout)
1098 dump_layout(image, size, layout_fname);
1099
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001100 if (mode_extract)
1101 write_regions(image, size);
1102
1103 if (mode_inject)
1104 inject_region(filename, image, size, region_type,
1105 region_fname);
1106
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001107 if (mode_newlayout)
1108 new_layout(filename, image, size, layout_fname);
1109
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001110 if (mode_spifreq)
1111 set_spi_frequency(filename, image, size, spifreq);
1112
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001113 if (mode_em100)
1114 set_em100_mode(filename, image, size);
1115
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001116 if(mode_locked)
1117 lock_descriptor(filename, image, size);
1118
1119 if (mode_unlocked)
1120 unlock_descriptor(filename, image, size);
1121
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001122 free(image);
1123
1124 return 0;
1125}