blob: deef1b1feeeaefc727f11b0d612f64744f0a5fa5 [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
Patrick Georgi440daf72014-08-03 12:14:25 +0200555 // - 5: leave room for ".new\0"
556 strncpy(new_filename, filename, FILENAME_MAX - 5);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700557 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
558
559 printf("Writing new image to %s\n", new_filename);
560
561 // Now write out new image
562 new_fd = open(new_filename,
563 O_WRONLY | O_CREAT | O_TRUNC,
564 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
565 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700566 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700567 close(new_fd);
568}
569
570static void set_spi_frequency(char *filename, char *image, int size,
571 enum spi_frequency freq)
572{
573 fdbar_t *fdb = find_fd(image, size);
574 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
575
576 /* clear bits 21-29 */
577 fcba->flcomp &= ~0x3fe00000;
578 /* Read ID and Read Status Clock Frequency */
579 fcba->flcomp |= freq << 27;
580 /* Write and Erase Clock Frequency */
581 fcba->flcomp |= freq << 24;
582 /* Fast Read Clock Frequency */
583 fcba->flcomp |= freq << 21;
584
585 write_image(filename, image, size);
586}
587
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700588static void set_em100_mode(char *filename, char *image, int size)
589{
590 fdbar_t *fdb = find_fd(image, size);
591 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
592
593 fcba->flcomp &= ~(1 << 30);
594 set_spi_frequency(filename, image, size, SPI_FREQUENCY_20MHZ);
595}
596
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700597static void lock_descriptor(char *filename, char *image, int size)
598{
599 fdbar_t *fdb = find_fd(image, size);
600 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
601 /* TODO: Dynamically take Platform Data Region and GbE Region
602 * into regard.
603 */
604 fmba->flmstr1 = 0x0a0b0000;
605 fmba->flmstr2 = 0x0c0d0000;
606 fmba->flmstr3 = 0x08080118;
607
608 write_image(filename, image, size);
609}
610
611static void unlock_descriptor(char *filename, char *image, int size)
612{
613 fdbar_t *fdb = find_fd(image, size);
614 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
615 fmba->flmstr1 = 0xffff0000;
616 fmba->flmstr2 = 0xffff0000;
617 fmba->flmstr3 = 0x08080118;
618
619 write_image(filename, image, size);
620}
621
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700622void inject_region(char *filename, char *image, int size, int region_type,
623 char *region_fname)
624{
625 fdbar_t *fdb = find_fd(image, size);
626 if (!fdb)
627 exit(EXIT_FAILURE);
628 frba_t *frba =
629 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700630
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700631 region_t region = get_region(frba, region_type);
632 if (region.size <= 0xfff) {
633 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
634 region_name(region_type));
635 exit(EXIT_FAILURE);
636 }
637
638 int region_fd = open(region_fname, O_RDONLY);
639 if (region_fd == -1) {
640 perror("Could not open file");
641 exit(EXIT_FAILURE);
642 }
643 struct stat buf;
644 if (fstat(region_fd, &buf) == -1) {
645 perror("Could not stat file");
646 exit(EXIT_FAILURE);
647 }
648 int region_size = buf.st_size;
649
650 printf("File %s is %d bytes\n", region_fname, region_size);
651
652 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -0800653 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700654 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
655 " bytes. Not injecting.\n",
656 region_name(region_type), region.size,
657 region.size, region_size, region_size);
658 exit(EXIT_FAILURE);
659 }
660
661 int offset = 0;
662 if ((region_type == 1) && (region_size < region.size)) {
663 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
664 " bytes. Padding before injecting.\n",
665 region_name(region_type), region.size,
666 region.size, region_size, region_size);
667 offset = region.size - region_size;
668 memset(image + region.base, 0xff, offset);
669 }
670
Stefan Reinauer5e93b372012-09-25 13:30:48 -0700671 if (size < region.base + offset + region_size) {
672 fprintf(stderr, "Output file is too small. (%d < %d)\n",
673 size, region.base + offset + region_size);
674 exit(EXIT_FAILURE);
675 }
676
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700677 if (read(region_fd, image + region.base + offset, region_size)
678 != region_size) {
679 perror("Could not read file");
680 exit(EXIT_FAILURE);
681 }
682
683 close(region_fd);
684
685 printf("Adding %s as the %s section of %s\n",
686 region_fname, region_name(region_type), filename);
687 write_image(filename, image, size);
688}
689
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500690unsigned int next_pow2(unsigned int x)
691{
692 unsigned int y = 1;
693 if (x == 0)
694 return 0;
695 while (y <= x)
696 y = y << 1;
697
698 return y;
699}
700
701/**
702 * Determine if two memory regions overlap.
703 *
704 * @param r1, r2 Memory regions to compare.
705 * @return 0 if the two regions are seperate
706 * @return 1 if the two regions overlap
707 */
708static int regions_collide(region_t r1, region_t r2)
709{
710 if ((r1.size == 0) || (r2.size == 0))
711 return 0;
712
713 if ( ((r1.base >= r2.base) && (r1.base <= r2.limit)) ||
714 ((r1.limit >= r2.base) && (r1.limit <= r2.limit)) )
715 return 1;
716
717 return 0;
718}
719
720void new_layout(char *filename, char *image, int size, char *layout_fname)
721{
722 FILE *romlayout;
723 char tempstr[256];
724 char layout_region_name[256];
725 int i, j;
726 int region_number;
Chris Douglasse2718652014-02-28 08:54:41 -0500727 region_t current_regions[NUM_REGIONS];
728 region_t new_regions[NUM_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500729 int new_extent = 0;
730 char *new_image;
731
732 /* load current descriptor map and regions */
733 fdbar_t *fdb = find_fd(image, size);
734 if (!fdb)
735 exit(EXIT_FAILURE);
736
737 frba_t *frba =
738 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
739
Chris Douglasse2718652014-02-28 08:54:41 -0500740 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500741 current_regions[i] = get_region(frba, i);
742 new_regions[i] = get_region(frba, i);
743 }
744
745 /* read new layout */
746 romlayout = fopen(layout_fname, "r");
747
748 if (!romlayout) {
749 perror("Could not read layout file.\n");
750 exit(EXIT_FAILURE);
751 }
752
753 while (!feof(romlayout)) {
754 char *tstr1, *tstr2;
755
756 if (2 != fscanf(romlayout, "%s %s\n", tempstr,
757 layout_region_name))
758 continue;
759
760 region_number = region_num(layout_region_name);
761 if (region_number < 0)
762 continue;
763
764 tstr1 = strtok(tempstr, ":");
765 tstr2 = strtok(NULL, ":");
766 if (!tstr1 || !tstr2) {
767 fprintf(stderr, "Could not parse layout file.\n");
768 exit(EXIT_FAILURE);
769 }
770 new_regions[region_number].base = strtol(tstr1,
771 (char **)NULL, 16);
772 new_regions[region_number].limit = strtol(tstr2,
773 (char **)NULL, 16);
774 new_regions[region_number].size =
775 new_regions[region_number].limit -
776 new_regions[region_number].base + 1;
777
778 if (new_regions[region_number].size < 0)
779 new_regions[region_number].size = 0;
780 }
781 fclose(romlayout);
782
783 /* check new layout */
Chris Douglasse2718652014-02-28 08:54:41 -0500784 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500785 if (new_regions[i].size == 0)
786 continue;
787
788 if (new_regions[i].size < current_regions[i].size) {
789 printf("DANGER: Region %s is shrinking.\n",
790 region_name(i));
791 printf(" The region will be truncated to fit.\n");
792 printf(" This may result in an unusable image.\n");
793 }
794
Chris Douglasse2718652014-02-28 08:54:41 -0500795 for (j = i + 1; j < NUM_REGIONS; j++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500796 if (regions_collide(new_regions[i], new_regions[j])) {
797 fprintf(stderr, "Regions would overlap.\n");
798 exit(EXIT_FAILURE);
799 }
800 }
801
802 /* detect if the image size should grow */
803 if (new_extent < new_regions[i].limit)
804 new_extent = new_regions[i].limit;
805 }
806
807 new_extent = next_pow2(new_extent - 1);
808 if (new_extent != size) {
809 printf("The image has changed in size.\n");
810 printf("The old image is %d bytes.\n", size);
811 printf("The new image is %d bytes.\n", new_extent);
812 }
813
814 /* copy regions to a new image */
815 new_image = malloc(new_extent);
816 memset(new_image, 0xff, new_extent);
Chris Douglasse2718652014-02-28 08:54:41 -0500817 for (i = 0; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500818 int copy_size = new_regions[i].size;
819 int offset_current = 0, offset_new = 0;
820 region_t current = current_regions[i];
821 region_t new = new_regions[i];
822
823 if (new.size == 0)
824 continue;
825
826 if (new.size > current.size) {
827 /* copy from the end of the current region */
828 copy_size = current.size;
829 offset_new = new.size - current.size;
830 }
831
832 if (new.size < current.size) {
833 /* copy to the end of the new region */
834 offset_current = current.size - new.size;
835 }
836
837 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
838 region_name(i), copy_size);
839 printf(" from %08x+%08x:%08x (%10d)\n", current.base,
840 offset_current, current.limit, current.size);
841 printf(" to %08x+%08x:%08x (%10d)\n", new.base,
842 offset_new, new.limit, new.size);
843
844 memcpy(new_image + new.base + offset_new,
845 image + current.base + offset_current,
846 copy_size);
847 }
848
849 /* update new descriptor regions */
850 fdb = find_fd(new_image, new_extent);
851 if (!fdb)
852 exit(EXIT_FAILURE);
853
854 frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Chris Douglasse2718652014-02-28 08:54:41 -0500855 for (i = 1; i < NUM_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500856 set_region(frba, i, new_regions[i]);
857 }
858
859 write_image(filename, new_image, new_extent);
860 free(new_image);
861}
862
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700863static void print_version(void)
864{
865 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
866 printf("Copyright (C) 2011 Google Inc.\n\n");
867 printf
868 ("This program is free software: you can redistribute it and/or modify\n"
869 "it under the terms of the GNU General Public License as published by\n"
870 "the Free Software Foundation, version 2 of the License.\n\n"
871 "This program is distributed in the hope that it will be useful,\n"
872 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
873 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
874 "GNU General Public License for more details.\n\n"
875 "You should have received a copy of the GNU General Public License\n"
876 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n");
877}
878
879static void print_usage(const char *name)
880{
881 printf("usage: %s [-vhdix?] <filename>\n", name);
882 printf("\n"
883 " -d | --dump: dump intel firmware descriptor\n"
Chris Douglass03ce0142014-02-26 13:30:13 -0500884 " -f | --layout <filename> dump regions into a flashrom layout file\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700885 " -x | --extract: extract intel fd modules\n"
886 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500887 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700888 " -s | --spifreq <20|33|50> set the SPI frequency\n"
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700889 " -e | --em100 set SPI frequency to 20MHz and disable\n"
890 " Dual Output Fast Read Support\n"
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700891 " -l | --lock Lock firmware descriptor and ME region\n"
892 " -u | --unlock Unlock firmware descriptor and ME region\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700893 " -v | --version: print the version\n"
894 " -h | --help: print this help\n\n"
895 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
896 "\n");
897}
898
899int main(int argc, char *argv[])
900{
901 int opt, option_index = 0;
902 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700903 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500904 int mode_layout = 0, mode_newlayout = 0;
Chris Douglass03ce0142014-02-26 13:30:13 -0500905 char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700906 int region_type = -1, inputfreq = 0;
907 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
908
909 static struct option long_options[] = {
910 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -0500911 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700912 {"extract", 0, NULL, 'x'},
913 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500914 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700915 {"spifreq", 1, NULL, 's'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700916 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700917 {"lock", 0, NULL, 'l'},
918 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700919 {"version", 0, NULL, 'v'},
920 {"help", 0, NULL, 'h'},
921 {0, 0, 0, 0}
922 };
923
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500924 while ((opt = getopt_long(argc, argv, "df:xi:n:s:eluvh?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700925 long_options, &option_index)) != EOF) {
926 switch (opt) {
927 case 'd':
928 mode_dump = 1;
929 break;
Chris Douglass03ce0142014-02-26 13:30:13 -0500930 case 'f':
931 mode_layout = 1;
932 layout_fname = strdup(optarg);
933 if (!layout_fname) {
934 fprintf(stderr, "No layout file specified\n");
935 print_usage(argv[0]);
936 exit(EXIT_FAILURE);
937 }
938 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700939 case 'x':
940 mode_extract = 1;
941 break;
942 case 'i':
943 // separate type and file name
944 region_type_string = strdup(optarg);
945 region_fname = strchr(region_type_string, ':');
946 if (!region_fname) {
947 print_usage(argv[0]);
948 exit(EXIT_FAILURE);
949 }
950 region_fname[0] = '\0';
951 region_fname++;
952 // Descriptor, BIOS, ME, GbE, Platform
953 // valid type?
954 if (!strcasecmp("Descriptor", region_type_string))
955 region_type = 0;
956 else if (!strcasecmp("BIOS", region_type_string))
957 region_type = 1;
958 else if (!strcasecmp("ME", region_type_string))
959 region_type = 2;
960 else if (!strcasecmp("GbE", region_type_string))
961 region_type = 3;
962 else if (!strcasecmp("Platform", region_type_string))
963 region_type = 4;
964 if (region_type == -1) {
965 fprintf(stderr, "No such region type: '%s'\n\n",
966 region_type_string);
967 print_usage(argv[0]);
968 exit(EXIT_FAILURE);
969 }
970 mode_inject = 1;
971 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500972 case 'n':
973 mode_newlayout = 1;
974 layout_fname = strdup(optarg);
975 if (!layout_fname) {
976 fprintf(stderr, "No layout file specified\n");
977 print_usage(argv[0]);
978 exit(EXIT_FAILURE);
979 }
980 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700981 case 's':
982 // Parse the requested SPI frequency
983 inputfreq = strtol(optarg, NULL, 0);
984 switch (inputfreq) {
985 case 20:
986 spifreq = SPI_FREQUENCY_20MHZ;
987 break;
988 case 33:
989 spifreq = SPI_FREQUENCY_33MHZ;
990 break;
991 case 50:
992 spifreq = SPI_FREQUENCY_50MHZ;
993 break;
994 default:
995 fprintf(stderr, "Invalid SPI Frequency: %d\n",
996 inputfreq);
997 print_usage(argv[0]);
998 exit(EXIT_FAILURE);
999 }
1000 mode_spifreq = 1;
1001 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001002 case 'e':
1003 mode_em100 = 1;
1004 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001005 case 'l':
1006 mode_locked = 1;
1007 if (mode_unlocked == 1) {
1008 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1009 exit(EXIT_FAILURE);
1010 }
1011 break;
1012 case 'u':
1013 mode_unlocked = 1;
1014 if (mode_locked == 1) {
1015 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1016 exit(EXIT_FAILURE);
1017 }
1018 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001019 case 'v':
1020 print_version();
1021 exit(EXIT_SUCCESS);
1022 break;
1023 case 'h':
1024 case '?':
1025 default:
1026 print_usage(argv[0]);
1027 exit(EXIT_SUCCESS);
1028 break;
1029 }
1030 }
1031
Chris Douglass03ce0142014-02-26 13:30:13 -05001032 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001033 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001034 mode_locked)) > 1) {
1035 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001036 print_usage(argv[0]);
1037 exit(EXIT_FAILURE);
1038 }
1039
Chris Douglass03ce0142014-02-26 13:30:13 -05001040 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001041 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Chris Douglass03ce0142014-02-26 13:30:13 -05001042 mode_unlocked) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001043 fprintf(stderr, "You need to specify a mode.\n\n");
1044 print_usage(argv[0]);
1045 exit(EXIT_FAILURE);
1046 }
1047
1048 if (optind + 1 != argc) {
1049 fprintf(stderr, "You need to specify a file.\n\n");
1050 print_usage(argv[0]);
1051 exit(EXIT_FAILURE);
1052 }
1053
1054 char *filename = argv[optind];
1055 int bios_fd = open(filename, O_RDONLY);
1056 if (bios_fd == -1) {
1057 perror("Could not open file");
1058 exit(EXIT_FAILURE);
1059 }
1060 struct stat buf;
1061 if (fstat(bios_fd, &buf) == -1) {
1062 perror("Could not stat file");
1063 exit(EXIT_FAILURE);
1064 }
1065 int size = buf.st_size;
1066
1067 printf("File %s is %d bytes\n", filename, size);
1068
1069 char *image = malloc(size);
1070 if (!image) {
1071 printf("Out of memory.\n");
1072 exit(EXIT_FAILURE);
1073 }
1074
1075 if (read(bios_fd, image, size) != size) {
1076 perror("Could not read file");
1077 exit(EXIT_FAILURE);
1078 }
1079
1080 close(bios_fd);
1081
1082 if (mode_dump)
1083 dump_fd(image, size);
1084
Chris Douglass03ce0142014-02-26 13:30:13 -05001085 if (mode_layout)
1086 dump_layout(image, size, layout_fname);
1087
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001088 if (mode_extract)
1089 write_regions(image, size);
1090
1091 if (mode_inject)
1092 inject_region(filename, image, size, region_type,
1093 region_fname);
1094
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001095 if (mode_newlayout)
1096 new_layout(filename, image, size, layout_fname);
1097
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001098 if (mode_spifreq)
1099 set_spi_frequency(filename, image, size, spifreq);
1100
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001101 if (mode_em100)
1102 set_em100_mode(filename, image, size);
1103
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001104 if(mode_locked)
1105 lock_descriptor(filename, image, size);
1106
1107 if (mode_unlocked)
1108 unlock_descriptor(filename, image, size);
1109
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001110 free(image);
1111
1112 return 0;
1113}