blob: 0425b1cd49792c5d2ff2eff9471b61e0bc141e26 [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
Chris Douglasse2718652014-02-28 08:54:41 -050030#define NUM_REGIONS 5
31
32static const struct region_name region_names[NUM_REGIONS] = {
Chris Douglass03ce0142014-02-26 13:30:13 -050033 { "Flash Descriptor", "fd" },
34 { "BIOS", "bios" },
35 { "Intel ME", "me" },
36 { "GbE", "gbe" },
37 { "Platform Data", "pd" }
38};
39
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070040static fdbar_t *find_fd(char *image, int size)
41{
42 int i, found = 0;
43
44 /* Scan for FD signature */
45 for (i = 0; i < (size - 4); i += 4) {
46 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
47 found = 1;
48 break; // signature found.
49 }
50 }
51
52 if (!found) {
53 printf("No Flash Descriptor found in this image\n");
54 return NULL;
55 }
56
57 printf("Found Flash Descriptor signature at 0x%08x\n", i);
58
59 return (fdbar_t *) (image + i);
60}
61
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070062static region_t get_region(frba_t *frba, int region_type)
63{
64 region_t region;
65 region.base = 0, region.limit = 0, region.size = 0;
66
67 switch (region_type) {
68 case 0:
69 region.base = (frba->flreg0 & 0x00000fff) << 12;
70 region.limit = ((frba->flreg0 & 0x0fff0000) >> 4) | 0xfff;
71 break;
72 case 1:
73 region.base = (frba->flreg1 & 0x00000fff) << 12;
74 region.limit = ((frba->flreg1 & 0x0fff0000) >> 4) | 0xfff;
75 break;
76 case 2:
77 region.base = (frba->flreg2 & 0x00000fff) << 12;
78 region.limit = ((frba->flreg2 & 0x0fff0000) >> 4) | 0xfff;
79 break;
80 case 3:
81 region.base = (frba->flreg3 & 0x00000fff) << 12;
82 region.limit = ((frba->flreg3 & 0x0fff0000) >> 4) | 0xfff;
83 break;
84 case 4:
85 region.base = (frba->flreg4 & 0x00000fff) << 12;
86 region.limit = ((frba->flreg4 & 0x0fff0000) >> 4) | 0xfff;
87 break;
88 default:
89 fprintf(stderr, "Invalid region type.\n");
90 exit (EXIT_FAILURE);
91 }
92
93 region.size = region.limit - region.base + 1;
Chris Douglass03ce0142014-02-26 13:30:13 -050094 if (region.size < 0)
95 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070096
97 return region;
98}
99
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500100static void set_region(frba_t *frba, int region_type, region_t region)
101{
102 switch (region_type) {
103 case 0:
104 frba->flreg0 = (((region.limit >> 12) & 0x7fff) << 16)
105 | ((region.base >> 12) & 0x7fff);
106 break;
107 case 1:
108 frba->flreg1 = (((region.limit >> 12) & 0x7fff) << 16)
109 | ((region.base >> 12) & 0x7fff);
110 break;
111 case 2:
112 frba->flreg2 = (((region.limit >> 12) & 0x7fff) << 16)
113 | ((region.base >> 12) & 0x7fff);
114 break;
115 case 3:
116 frba->flreg3 = (((region.limit >> 12) & 0x7fff) << 16)
117 | ((region.base >> 12) & 0x7fff);
118 break;
119 case 4:
120 frba->flreg4 = (((region.limit >> 12) & 0x7fff) << 16)
121 | ((region.base >> 12) & 0x7fff);
122 break;
123 default:
124 fprintf(stderr, "Invalid region type.\n");
125 exit (EXIT_FAILURE);
126 }
127}
128
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700129static const char *region_name(int region_type)
130{
Chris Douglasse2718652014-02-28 08:54:41 -0500131 if (region_type < 0 || region_type >= NUM_REGIONS) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700132 fprintf(stderr, "Invalid region type.\n");
133 exit (EXIT_FAILURE);
134 }
135
Chris Douglass03ce0142014-02-26 13:30:13 -0500136 return region_names[region_type].pretty;
137}
138
139static const char *region_name_short(int region_type)
140{
Chris Douglasse2718652014-02-28 08:54:41 -0500141 if (region_type < 0 || region_type >= NUM_REGIONS) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500142 fprintf(stderr, "Invalid region type.\n");
143 exit (EXIT_FAILURE);
144 }
145
146 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700147}
148
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500149static int region_num(const char *name)
150{
151 int i;
152
Chris Douglasse2718652014-02-28 08:54:41 -0500153 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500154 if (strcasecmp(name, region_names[i].pretty) == 0)
155 return i;
156 if (strcasecmp(name, region_names[i].terse) == 0)
157 return i;
158 }
159
160 return -1;
161}
162
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700163static const char *region_filename(int region_type)
164{
Chris Douglasse2718652014-02-28 08:54:41 -0500165 static const char *region_filenames[NUM_REGIONS] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700166 "flashregion_0_flashdescriptor.bin",
167 "flashregion_1_bios.bin",
168 "flashregion_2_intel_me.bin",
169 "flashregion_3_gbe.bin",
170 "flashregion_4_platform_data.bin"
171 };
172
Chris Douglasse2718652014-02-28 08:54:41 -0500173 if (region_type < 0 || region_type >= NUM_REGIONS) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700174 fprintf(stderr, "Invalid region type.\n");
175 exit (EXIT_FAILURE);
176 }
177
178 return region_filenames[region_type];
179}
180
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700181static void dump_region(int num, frba_t *frba)
182{
183 region_t region = get_region(frba, num);
184 printf(" Flash Region %d (%s): %08x - %08x %s\n",
185 num, region_name(num), region.base, region.limit,
186 region.size < 1 ? "(unused)" : "");
187}
188
Chris Douglass03ce0142014-02-26 13:30:13 -0500189static void dump_region_layout(char *buf, size_t bufsize, int num, frba_t *frba)
190{
191 region_t region = get_region(frba, num);
192 snprintf(buf, bufsize, "%08x:%08x %s\n",
193 region.base, region.limit, region_name_short(num));
194}
195
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700196static void dump_frba(frba_t * frba)
197{
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700198 printf("Found Region Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700199 printf("FLREG0: 0x%08x\n", frba->flreg0);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700200 dump_region(0, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700201 printf("FLREG1: 0x%08x\n", frba->flreg1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700202 dump_region(1, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700203 printf("FLREG2: 0x%08x\n", frba->flreg2);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700204 dump_region(2, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700205 printf("FLREG3: 0x%08x\n", frba->flreg3);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700206 dump_region(3, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700207 printf("FLREG4: 0x%08x\n", frba->flreg4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700208 dump_region(4, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700209}
210
Chris Douglass03ce0142014-02-26 13:30:13 -0500211static void dump_frba_layout(frba_t * frba, char *layout_fname)
212{
213 char buf[LAYOUT_LINELEN];
214 size_t bufsize = LAYOUT_LINELEN;
215 int i;
216
217 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
218 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
219 if (layout_fd == -1) {
220 perror("Could not open file");
221 exit(EXIT_FAILURE);
222 }
223
Chris Douglasse2718652014-02-28 08:54:41 -0500224 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500225 dump_region_layout(buf, bufsize, i, frba);
226 if (write(layout_fd, buf, strlen(buf)) < 0) {
227 perror("Could not write to file");
228 exit(EXIT_FAILURE);
229 }
230 }
231 close(layout_fd);
232 printf("Wrote layout to %s\n", layout_fname);
233}
234
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700235static void decode_spi_frequency(unsigned int freq)
236{
237 switch (freq) {
238 case SPI_FREQUENCY_20MHZ:
239 printf("20MHz");
240 break;
241 case SPI_FREQUENCY_33MHZ:
242 printf("33MHz");
243 break;
244 case SPI_FREQUENCY_50MHZ:
245 printf("50MHz");
246 break;
247 default:
248 printf("unknown<%x>MHz", freq);
249 }
250}
251
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700252static void decode_component_density(unsigned int density)
253{
254 switch (density) {
255 case COMPONENT_DENSITY_512KB:
256 printf("512KB");
257 break;
258 case COMPONENT_DENSITY_1MB:
259 printf("1MB");
260 break;
261 case COMPONENT_DENSITY_2MB:
262 printf("2MB");
263 break;
264 case COMPONENT_DENSITY_4MB:
265 printf("4MB");
266 break;
267 case COMPONENT_DENSITY_8MB:
268 printf("8MB");
269 break;
270 case COMPONENT_DENSITY_16MB:
271 printf("16MB");
272 break;
273 default:
274 printf("unknown<%x>MB", density);
275 }
276}
277
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700278static void dump_fcba(fcba_t * fcba)
279{
280 printf("\nFound Component Section\n");
281 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700282 printf(" Dual Output Fast Read Support: %ssupported\n",
283 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700284 printf(" Read ID/Read Status Clock Frequency: ");
285 decode_spi_frequency((fcba->flcomp >> 27) & 7);
286 printf("\n Write/Erase Clock Frequency: ");
287 decode_spi_frequency((fcba->flcomp >> 24) & 7);
288 printf("\n Fast Read Clock Frequency: ");
289 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700290 printf("\n Fast Read Support: %ssupported",
291 (fcba->flcomp & (1 << 20))?"":"not ");
292 printf("\n Read Clock Frequency: ");
293 decode_spi_frequency((fcba->flcomp >> 17) & 7);
294 printf("\n Component 2 Density: ");
295 decode_component_density((fcba->flcomp >> 3) & 7);
296 printf("\n Component 1 Density: ");
297 decode_component_density(fcba->flcomp & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700298 printf("\n");
299 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700300 printf(" Invalid Instruction 3: 0x%02x\n",
301 (fcba->flill >> 24) & 0xff);
302 printf(" Invalid Instruction 2: 0x%02x\n",
303 (fcba->flill >> 16) & 0xff);
304 printf(" Invalid Instruction 1: 0x%02x\n",
305 (fcba->flill >> 8) & 0xff);
306 printf(" Invalid Instruction 0: 0x%02x\n",
307 fcba->flill & 0xff);
308 printf("FLPB 0x%08x\n", fcba->flpb);
309 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
310 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700311}
312
313static void dump_fpsba(fpsba_t * fpsba)
314{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700315 printf("Found PCH Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316 printf("PCHSTRP0: 0x%08x\n", fpsba->pchstrp0);
317 printf("PCHSTRP1: 0x%08x\n", fpsba->pchstrp1);
318 printf("PCHSTRP2: 0x%08x\n", fpsba->pchstrp2);
319 printf("PCHSTRP3: 0x%08x\n", fpsba->pchstrp3);
320 printf("PCHSTRP4: 0x%08x\n", fpsba->pchstrp4);
321 printf("PCHSTRP5: 0x%08x\n", fpsba->pchstrp5);
322 printf("PCHSTRP6: 0x%08x\n", fpsba->pchstrp6);
323 printf("PCHSTRP7: 0x%08x\n", fpsba->pchstrp7);
324 printf("PCHSTRP8: 0x%08x\n", fpsba->pchstrp8);
325 printf("PCHSTRP9: 0x%08x\n", fpsba->pchstrp9);
326 printf("PCHSTRP10: 0x%08x\n", fpsba->pchstrp10);
327 printf("PCHSTRP11: 0x%08x\n", fpsba->pchstrp11);
328 printf("PCHSTRP12: 0x%08x\n", fpsba->pchstrp12);
329 printf("PCHSTRP13: 0x%08x\n", fpsba->pchstrp13);
330 printf("PCHSTRP14: 0x%08x\n", fpsba->pchstrp14);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700331 printf("PCHSTRP15: 0x%08x\n", fpsba->pchstrp15);
332 printf("PCHSTRP16: 0x%08x\n", fpsba->pchstrp16);
333 printf("PCHSTRP17: 0x%08x\n\n", fpsba->pchstrp17);
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700334}
335
336static void decode_flmstr(uint32_t flmstr)
337{
338 printf(" Platform Data Region Write Access: %s\n",
339 (flmstr & (1 << 28)) ? "enabled" : "disabled");
340 printf(" GbE Region Write Access: %s\n",
341 (flmstr & (1 << 27)) ? "enabled" : "disabled");
342 printf(" Intel ME Region Write Access: %s\n",
343 (flmstr & (1 << 26)) ? "enabled" : "disabled");
344 printf(" Host CPU/BIOS Region Write Access: %s\n",
345 (flmstr & (1 << 25)) ? "enabled" : "disabled");
346 printf(" Flash Descriptor Write Access: %s\n",
347 (flmstr & (1 << 24)) ? "enabled" : "disabled");
348
349 printf(" Platform Data Region Read Access: %s\n",
350 (flmstr & (1 << 20)) ? "enabled" : "disabled");
351 printf(" GbE Region Read Access: %s\n",
352 (flmstr & (1 << 19)) ? "enabled" : "disabled");
353 printf(" Intel ME Region Read Access: %s\n",
354 (flmstr & (1 << 18)) ? "enabled" : "disabled");
355 printf(" Host CPU/BIOS Region Read Access: %s\n",
356 (flmstr & (1 << 17)) ? "enabled" : "disabled");
357 printf(" Flash Descriptor Read Access: %s\n",
358 (flmstr & (1 << 16)) ? "enabled" : "disabled");
359
360 printf(" Requester ID: 0x%04x\n\n",
361 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700362}
363
364static void dump_fmba(fmba_t * fmba)
365{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700366 printf("Found Master Section\n");
367 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
368 decode_flmstr(fmba->flmstr1);
369 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
370 decode_flmstr(fmba->flmstr2);
371 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
372 decode_flmstr(fmba->flmstr3);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700373}
374
375static void dump_fmsba(fmsba_t * fmsba)
376{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700377 printf("Found Processor Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700378 printf("????: 0x%08x\n", fmsba->data[0]);
379 printf("????: 0x%08x\n", fmsba->data[1]);
380 printf("????: 0x%08x\n", fmsba->data[2]);
381 printf("????: 0x%08x\n", fmsba->data[3]);
382}
383
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700384static void dump_jid(uint32_t jid)
385{
386 printf(" SPI Componend Device ID 1: 0x%02x\n",
387 (jid >> 16) & 0xff);
388 printf(" SPI Componend Device ID 0: 0x%02x\n",
389 (jid >> 8) & 0xff);
390 printf(" SPI Componend Vendor ID: 0x%02x\n",
391 jid & 0xff);
392}
393
394static void dump_vscc(uint32_t vscc)
395{
396 printf(" Lower Erase Opcode: 0x%02x\n",
397 vscc >> 24);
398 printf(" Lower Write Enable on Write Status: 0x%02x\n",
399 vscc & (1 << 20) ? 0x06 : 0x50);
400 printf(" Lower Write Status Required: %s\n",
401 vscc & (1 << 19) ? "Yes" : "No");
402 printf(" Lower Write Granularity: %d bytes\n",
403 vscc & (1 << 18) ? 64 : 1);
404 printf(" Lower Block / Sector Erase Size: ");
405 switch ((vscc >> 16) & 0x3) {
406 case 0:
407 printf("256 Byte\n");
408 break;
409 case 1:
410 printf("4KB\n");
411 break;
412 case 2:
413 printf("8KB\n");
414 break;
415 case 3:
416 printf("64KB\n");
417 break;
418 }
419
420 printf(" Upper Erase Opcode: 0x%02x\n",
421 (vscc >> 8) & 0xff);
422 printf(" Upper Write Enable on Write Status: 0x%02x\n",
423 vscc & (1 << 4) ? 0x06 : 0x50);
424 printf(" Upper Write Status Required: %s\n",
425 vscc & (1 << 3) ? "Yes" : "No");
426 printf(" Upper Write Granularity: %d bytes\n",
427 vscc & (1 << 2) ? 64 : 1);
428 printf(" Upper Block / Sector Erase Size: ");
429 switch (vscc & 0x3) {
430 case 0:
431 printf("256 Byte\n");
432 break;
433 case 1:
434 printf("4KB\n");
435 break;
436 case 2:
437 printf("8KB\n");
438 break;
439 case 3:
440 printf("64KB\n");
441 break;
442 }
443}
444
445static void dump_vtba(vtba_t *vtba, int vtl)
446{
447 int i;
448 int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
449
450 printf("ME VSCC table:\n");
451 for (i = 0; i < num; i++) {
452 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
453 dump_jid(vtba->entry[i].jid);
454 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
455 dump_vscc(vtba->entry[i].vscc);
456 }
457 printf("\n");
458}
459
460static void dump_oem(uint8_t *oem)
461{
462 int i, j;
463 printf("OEM Section:\n");
464 for (i = 0; i < 4; i++) {
465 printf("%02x:", i << 4);
466 for (j = 0; j < 16; j++)
467 printf(" %02x", oem[(i<<4)+j]);
468 printf ("\n");
469 }
470 printf ("\n");
471}
472
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700473static void dump_fd(char *image, int size)
474{
475 fdbar_t *fdb = find_fd(image, size);
476 if (!fdb)
477 exit(EXIT_FAILURE);
478
479 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
480 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
481 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
482 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
483 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
484
485 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
486 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
487 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
488 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
489 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
490
491 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
492 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
493 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
494
495 printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700496 printf(" Intel ME VSCC Table Length (VTL): %d\n",
497 (fdb->flumap1 >> 8) & 0xff);
498 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
499 (fdb->flumap1 & 0xff) << 4);
500 dump_vtba((vtba_t *)
501 (image + ((fdb->flumap1 & 0xff) << 4)),
502 (fdb->flumap1 >> 8) & 0xff);
503 dump_oem((uint8_t *)image + 0xf00);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700504 dump_frba((frba_t *)
505 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)));
506 dump_fcba((fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4)));
507 dump_fpsba((fpsba_t *)
508 (image + (((fdb->flmap1 >> 16) & 0xff) << 4)));
509 dump_fmba((fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4)));
510 dump_fmsba((fmsba_t *) (image + (((fdb->flmap2) & 0xff) << 4)));
511}
512
Chris Douglass03ce0142014-02-26 13:30:13 -0500513static void dump_layout(char *image, int size, char *layout_fname)
514{
515 fdbar_t *fdb = find_fd(image, size);
516 if (!fdb)
517 exit(EXIT_FAILURE);
518
519 dump_frba_layout((frba_t *)
520 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)),
521 layout_fname);
522}
523
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700524static void write_regions(char *image, int size)
525{
526 int i;
527
528 fdbar_t *fdb = find_fd(image, size);
529 if (!fdb)
530 exit(EXIT_FAILURE);
531
532 frba_t *frba =
533 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
534
Chris Douglasse2718652014-02-28 08:54:41 -0500535 for (i = 0; i < NUM_REGIONS; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700536 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700537 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700538 if (region.size > 0) {
539 int region_fd;
540 region_fd = open(region_filename(i),
541 O_WRONLY | O_CREAT | O_TRUNC,
542 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
543 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700544 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700545 close(region_fd);
546 }
547 }
548}
549
550static void write_image(char *filename, char *image, int size)
551{
552 char new_filename[FILENAME_MAX]; // allow long file names
553 int new_fd;
554
555 strncpy(new_filename, filename, FILENAME_MAX);
556 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
557
558 printf("Writing new image to %s\n", new_filename);
559
560 // Now write out new image
561 new_fd = open(new_filename,
562 O_WRONLY | O_CREAT | O_TRUNC,
563 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
564 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700565 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700566 close(new_fd);
567}
568
569static void set_spi_frequency(char *filename, char *image, int size,
570 enum spi_frequency freq)
571{
572 fdbar_t *fdb = find_fd(image, size);
573 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
574
575 /* clear bits 21-29 */
576 fcba->flcomp &= ~0x3fe00000;
577 /* Read ID and Read Status Clock Frequency */
578 fcba->flcomp |= freq << 27;
579 /* Write and Erase Clock Frequency */
580 fcba->flcomp |= freq << 24;
581 /* Fast Read Clock Frequency */
582 fcba->flcomp |= freq << 21;
583
584 write_image(filename, image, size);
585}
586
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700587static void set_em100_mode(char *filename, char *image, int size)
588{
589 fdbar_t *fdb = find_fd(image, size);
590 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
591
592 fcba->flcomp &= ~(1 << 30);
593 set_spi_frequency(filename, image, size, SPI_FREQUENCY_20MHZ);
594}
595
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700596static void lock_descriptor(char *filename, char *image, int size)
597{
598 fdbar_t *fdb = find_fd(image, size);
599 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
600 /* TODO: Dynamically take Platform Data Region and GbE Region
601 * into regard.
602 */
603 fmba->flmstr1 = 0x0a0b0000;
604 fmba->flmstr2 = 0x0c0d0000;
605 fmba->flmstr3 = 0x08080118;
606
607 write_image(filename, image, size);
608}
609
610static void unlock_descriptor(char *filename, char *image, int size)
611{
612 fdbar_t *fdb = find_fd(image, size);
613 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
614 fmba->flmstr1 = 0xffff0000;
615 fmba->flmstr2 = 0xffff0000;
616 fmba->flmstr3 = 0x08080118;
617
618 write_image(filename, image, size);
619}
620
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700621void inject_region(char *filename, char *image, int size, int region_type,
622 char *region_fname)
623{
624 fdbar_t *fdb = find_fd(image, size);
625 if (!fdb)
626 exit(EXIT_FAILURE);
627 frba_t *frba =
628 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700629
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700630 region_t region = get_region(frba, region_type);
631 if (region.size <= 0xfff) {
632 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
633 region_name(region_type));
634 exit(EXIT_FAILURE);
635 }
636
637 int region_fd = open(region_fname, O_RDONLY);
638 if (region_fd == -1) {
639 perror("Could not open file");
640 exit(EXIT_FAILURE);
641 }
642 struct stat buf;
643 if (fstat(region_fd, &buf) == -1) {
644 perror("Could not stat file");
645 exit(EXIT_FAILURE);
646 }
647 int region_size = buf.st_size;
648
649 printf("File %s is %d bytes\n", region_fname, region_size);
650
651 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -0800652 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700653 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
654 " bytes. Not injecting.\n",
655 region_name(region_type), region.size,
656 region.size, region_size, region_size);
657 exit(EXIT_FAILURE);
658 }
659
660 int offset = 0;
661 if ((region_type == 1) && (region_size < region.size)) {
662 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
663 " bytes. Padding before injecting.\n",
664 region_name(region_type), region.size,
665 region.size, region_size, region_size);
666 offset = region.size - region_size;
667 memset(image + region.base, 0xff, offset);
668 }
669
Stefan Reinauer5e93b372012-09-25 13:30:48 -0700670 if (size < region.base + offset + region_size) {
671 fprintf(stderr, "Output file is too small. (%d < %d)\n",
672 size, region.base + offset + region_size);
673 exit(EXIT_FAILURE);
674 }
675
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700676 if (read(region_fd, image + region.base + offset, region_size)
677 != region_size) {
678 perror("Could not read file");
679 exit(EXIT_FAILURE);
680 }
681
682 close(region_fd);
683
684 printf("Adding %s as the %s section of %s\n",
685 region_fname, region_name(region_type), filename);
686 write_image(filename, image, size);
687}
688
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500689unsigned int next_pow2(unsigned int x)
690{
691 unsigned int y = 1;
692 if (x == 0)
693 return 0;
694 while (y <= x)
695 y = y << 1;
696
697 return y;
698}
699
700/**
701 * Determine if two memory regions overlap.
702 *
703 * @param r1, r2 Memory regions to compare.
704 * @return 0 if the two regions are seperate
705 * @return 1 if the two regions overlap
706 */
707static int regions_collide(region_t r1, region_t r2)
708{
709 if ((r1.size == 0) || (r2.size == 0))
710 return 0;
711
712 if ( ((r1.base >= r2.base) && (r1.base <= r2.limit)) ||
713 ((r1.limit >= r2.base) && (r1.limit <= r2.limit)) )
714 return 1;
715
716 return 0;
717}
718
719void new_layout(char *filename, char *image, int size, char *layout_fname)
720{
721 FILE *romlayout;
722 char tempstr[256];
723 char layout_region_name[256];
724 int i, j;
725 int region_number;
Chris Douglasse2718652014-02-28 08:54:41 -0500726 region_t current_regions[NUM_REGIONS];
727 region_t new_regions[NUM_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500728 int new_extent = 0;
729 char *new_image;
730
731 /* load current descriptor map and regions */
732 fdbar_t *fdb = find_fd(image, size);
733 if (!fdb)
734 exit(EXIT_FAILURE);
735
736 frba_t *frba =
737 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
738
Chris Douglasse2718652014-02-28 08:54:41 -0500739 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500740 current_regions[i] = get_region(frba, i);
741 new_regions[i] = get_region(frba, i);
742 }
743
744 /* read new layout */
745 romlayout = fopen(layout_fname, "r");
746
747 if (!romlayout) {
748 perror("Could not read layout file.\n");
749 exit(EXIT_FAILURE);
750 }
751
752 while (!feof(romlayout)) {
753 char *tstr1, *tstr2;
754
755 if (2 != fscanf(romlayout, "%s %s\n", tempstr,
756 layout_region_name))
757 continue;
758
759 region_number = region_num(layout_region_name);
760 if (region_number < 0)
761 continue;
762
763 tstr1 = strtok(tempstr, ":");
764 tstr2 = strtok(NULL, ":");
765 if (!tstr1 || !tstr2) {
766 fprintf(stderr, "Could not parse layout file.\n");
767 exit(EXIT_FAILURE);
768 }
769 new_regions[region_number].base = strtol(tstr1,
770 (char **)NULL, 16);
771 new_regions[region_number].limit = strtol(tstr2,
772 (char **)NULL, 16);
773 new_regions[region_number].size =
774 new_regions[region_number].limit -
775 new_regions[region_number].base + 1;
776
777 if (new_regions[region_number].size < 0)
778 new_regions[region_number].size = 0;
779 }
780 fclose(romlayout);
781
782 /* check new layout */
Chris Douglasse2718652014-02-28 08:54:41 -0500783 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500784 if (new_regions[i].size == 0)
785 continue;
786
787 if (new_regions[i].size < current_regions[i].size) {
788 printf("DANGER: Region %s is shrinking.\n",
789 region_name(i));
790 printf(" The region will be truncated to fit.\n");
791 printf(" This may result in an unusable image.\n");
792 }
793
Chris Douglasse2718652014-02-28 08:54:41 -0500794 for (j = i + 1; j < NUM_REGIONS; j++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500795 if (regions_collide(new_regions[i], new_regions[j])) {
796 fprintf(stderr, "Regions would overlap.\n");
797 exit(EXIT_FAILURE);
798 }
799 }
800
801 /* detect if the image size should grow */
802 if (new_extent < new_regions[i].limit)
803 new_extent = new_regions[i].limit;
804 }
805
806 new_extent = next_pow2(new_extent - 1);
807 if (new_extent != size) {
808 printf("The image has changed in size.\n");
809 printf("The old image is %d bytes.\n", size);
810 printf("The new image is %d bytes.\n", new_extent);
811 }
812
813 /* copy regions to a new image */
814 new_image = malloc(new_extent);
815 memset(new_image, 0xff, new_extent);
Chris Douglasse2718652014-02-28 08:54:41 -0500816 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500817 int copy_size = new_regions[i].size;
818 int offset_current = 0, offset_new = 0;
819 region_t current = current_regions[i];
820 region_t new = new_regions[i];
821
822 if (new.size == 0)
823 continue;
824
825 if (new.size > current.size) {
826 /* copy from the end of the current region */
827 copy_size = current.size;
828 offset_new = new.size - current.size;
829 }
830
831 if (new.size < current.size) {
832 /* copy to the end of the new region */
833 offset_current = current.size - new.size;
834 }
835
836 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
837 region_name(i), copy_size);
838 printf(" from %08x+%08x:%08x (%10d)\n", current.base,
839 offset_current, current.limit, current.size);
840 printf(" to %08x+%08x:%08x (%10d)\n", new.base,
841 offset_new, new.limit, new.size);
842
843 memcpy(new_image + new.base + offset_new,
844 image + current.base + offset_current,
845 copy_size);
846 }
847
848 /* update new descriptor regions */
849 fdb = find_fd(new_image, new_extent);
850 if (!fdb)
851 exit(EXIT_FAILURE);
852
853 frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Chris Douglasse2718652014-02-28 08:54:41 -0500854 for (i = 1; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500855 set_region(frba, i, new_regions[i]);
856 }
857
858 write_image(filename, new_image, new_extent);
859 free(new_image);
860}
861
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700862static void print_version(void)
863{
864 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
865 printf("Copyright (C) 2011 Google Inc.\n\n");
866 printf
867 ("This program is free software: you can redistribute it and/or modify\n"
868 "it under the terms of the GNU General Public License as published by\n"
869 "the Free Software Foundation, version 2 of the License.\n\n"
870 "This program is distributed in the hope that it will be useful,\n"
871 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
872 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
873 "GNU General Public License for more details.\n\n"
874 "You should have received a copy of the GNU General Public License\n"
875 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n");
876}
877
878static void print_usage(const char *name)
879{
880 printf("usage: %s [-vhdix?] <filename>\n", name);
881 printf("\n"
882 " -d | --dump: dump intel firmware descriptor\n"
Chris Douglass03ce0142014-02-26 13:30:13 -0500883 " -f | --layout <filename> dump regions into a flashrom layout file\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700884 " -x | --extract: extract intel fd modules\n"
885 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500886 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700887 " -s | --spifreq <20|33|50> set the SPI frequency\n"
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700888 " -e | --em100 set SPI frequency to 20MHz and disable\n"
889 " Dual Output Fast Read Support\n"
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700890 " -l | --lock Lock firmware descriptor and ME region\n"
891 " -u | --unlock Unlock firmware descriptor and ME region\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700892 " -v | --version: print the version\n"
893 " -h | --help: print this help\n\n"
894 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
895 "\n");
896}
897
898int main(int argc, char *argv[])
899{
900 int opt, option_index = 0;
901 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700902 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500903 int mode_layout = 0, mode_newlayout = 0;
Chris Douglass03ce0142014-02-26 13:30:13 -0500904 char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700905 int region_type = -1, inputfreq = 0;
906 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
907
908 static struct option long_options[] = {
909 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -0500910 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700911 {"extract", 0, NULL, 'x'},
912 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500913 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700914 {"spifreq", 1, NULL, 's'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700915 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700916 {"lock", 0, NULL, 'l'},
917 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700918 {"version", 0, NULL, 'v'},
919 {"help", 0, NULL, 'h'},
920 {0, 0, 0, 0}
921 };
922
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500923 while ((opt = getopt_long(argc, argv, "df:xi:n:s:eluvh?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700924 long_options, &option_index)) != EOF) {
925 switch (opt) {
926 case 'd':
927 mode_dump = 1;
928 break;
Chris Douglass03ce0142014-02-26 13:30:13 -0500929 case 'f':
930 mode_layout = 1;
931 layout_fname = strdup(optarg);
932 if (!layout_fname) {
933 fprintf(stderr, "No layout file specified\n");
934 print_usage(argv[0]);
935 exit(EXIT_FAILURE);
936 }
937 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700938 case 'x':
939 mode_extract = 1;
940 break;
941 case 'i':
942 // separate type and file name
943 region_type_string = strdup(optarg);
944 region_fname = strchr(region_type_string, ':');
945 if (!region_fname) {
946 print_usage(argv[0]);
947 exit(EXIT_FAILURE);
948 }
949 region_fname[0] = '\0';
950 region_fname++;
951 // Descriptor, BIOS, ME, GbE, Platform
952 // valid type?
953 if (!strcasecmp("Descriptor", region_type_string))
954 region_type = 0;
955 else if (!strcasecmp("BIOS", region_type_string))
956 region_type = 1;
957 else if (!strcasecmp("ME", region_type_string))
958 region_type = 2;
959 else if (!strcasecmp("GbE", region_type_string))
960 region_type = 3;
961 else if (!strcasecmp("Platform", region_type_string))
962 region_type = 4;
963 if (region_type == -1) {
964 fprintf(stderr, "No such region type: '%s'\n\n",
965 region_type_string);
966 print_usage(argv[0]);
967 exit(EXIT_FAILURE);
968 }
969 mode_inject = 1;
970 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500971 case 'n':
972 mode_newlayout = 1;
973 layout_fname = strdup(optarg);
974 if (!layout_fname) {
975 fprintf(stderr, "No layout file specified\n");
976 print_usage(argv[0]);
977 exit(EXIT_FAILURE);
978 }
979 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700980 case 's':
981 // Parse the requested SPI frequency
982 inputfreq = strtol(optarg, NULL, 0);
983 switch (inputfreq) {
984 case 20:
985 spifreq = SPI_FREQUENCY_20MHZ;
986 break;
987 case 33:
988 spifreq = SPI_FREQUENCY_33MHZ;
989 break;
990 case 50:
991 spifreq = SPI_FREQUENCY_50MHZ;
992 break;
993 default:
994 fprintf(stderr, "Invalid SPI Frequency: %d\n",
995 inputfreq);
996 print_usage(argv[0]);
997 exit(EXIT_FAILURE);
998 }
999 mode_spifreq = 1;
1000 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001001 case 'e':
1002 mode_em100 = 1;
1003 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001004 case 'l':
1005 mode_locked = 1;
1006 if (mode_unlocked == 1) {
1007 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1008 exit(EXIT_FAILURE);
1009 }
1010 break;
1011 case 'u':
1012 mode_unlocked = 1;
1013 if (mode_locked == 1) {
1014 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1015 exit(EXIT_FAILURE);
1016 }
1017 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001018 case 'v':
1019 print_version();
1020 exit(EXIT_SUCCESS);
1021 break;
1022 case 'h':
1023 case '?':
1024 default:
1025 print_usage(argv[0]);
1026 exit(EXIT_SUCCESS);
1027 break;
1028 }
1029 }
1030
Chris Douglass03ce0142014-02-26 13:30:13 -05001031 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001032 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001033 mode_locked)) > 1) {
1034 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001035 print_usage(argv[0]);
1036 exit(EXIT_FAILURE);
1037 }
1038
Chris Douglass03ce0142014-02-26 13:30:13 -05001039 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001040 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Chris Douglass03ce0142014-02-26 13:30:13 -05001041 mode_unlocked) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001042 fprintf(stderr, "You need to specify a mode.\n\n");
1043 print_usage(argv[0]);
1044 exit(EXIT_FAILURE);
1045 }
1046
1047 if (optind + 1 != argc) {
1048 fprintf(stderr, "You need to specify a file.\n\n");
1049 print_usage(argv[0]);
1050 exit(EXIT_FAILURE);
1051 }
1052
1053 char *filename = argv[optind];
1054 int bios_fd = open(filename, O_RDONLY);
1055 if (bios_fd == -1) {
1056 perror("Could not open file");
1057 exit(EXIT_FAILURE);
1058 }
1059 struct stat buf;
1060 if (fstat(bios_fd, &buf) == -1) {
1061 perror("Could not stat file");
1062 exit(EXIT_FAILURE);
1063 }
1064 int size = buf.st_size;
1065
1066 printf("File %s is %d bytes\n", filename, size);
1067
1068 char *image = malloc(size);
1069 if (!image) {
1070 printf("Out of memory.\n");
1071 exit(EXIT_FAILURE);
1072 }
1073
1074 if (read(bios_fd, image, size) != size) {
1075 perror("Could not read file");
1076 exit(EXIT_FAILURE);
1077 }
1078
1079 close(bios_fd);
1080
1081 if (mode_dump)
1082 dump_fd(image, size);
1083
Chris Douglass03ce0142014-02-26 13:30:13 -05001084 if (mode_layout)
1085 dump_layout(image, size, layout_fname);
1086
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001087 if (mode_extract)
1088 write_regions(image, size);
1089
1090 if (mode_inject)
1091 inject_region(filename, image, size, region_type,
1092 region_fname);
1093
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001094 if (mode_newlayout)
1095 new_layout(filename, image, size, layout_fname);
1096
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001097 if (mode_spifreq)
1098 set_spi_frequency(filename, image, size, spifreq);
1099
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001100 if (mode_em100)
1101 set_em100_mode(filename, image, size);
1102
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001103 if(mode_locked)
1104 lock_descriptor(filename, image, size);
1105
1106 if (mode_unlocked)
1107 unlock_descriptor(filename, image, size);
1108
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001109 free(image);
1110
1111 return 0;
1112}