blob: 8397f5c1571346b5591b5ce75454119815ce8924 [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.
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014 */
15
16#include <unistd.h>
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20#include <getopt.h>
21#include <fcntl.h>
22#include <sys/types.h>
23#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080024#include <commonlib/helpers.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070025#include "ifdtool.h"
26
Scott Duplichanf2c98372014-12-12 21:03:06 -060027#ifndef O_BINARY
28#define O_BINARY 0
29#endif
30
Bill XIE612ec0e2017-08-30 16:10:27 +080031/**
32 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
33 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
34 * @param base: base address represented with char* type.
35 * @param limit: upper limit of the legal address.
36 *
37 */
38#define PTR_IN_RANGE(ptr, base, limit) \
39 ((const char *)(ptr) >= (base) && \
40 (const char *)&(ptr)[1] <= (base) + (limit))
41
Duncan Laurie1f7fd722015-06-22 11:14:48 -070042static int ifd_version;
Bill XIEfa5f9942017-09-12 11:22:29 +080043static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010044static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070045static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050046
Duncan Laurie1f7fd722015-06-22 11:14:48 -070047static const struct region_name region_names[MAX_REGIONS] = {
Bill XIE1bf65062017-09-12 11:31:37 +080048 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin" },
49 { "BIOS", "bios", "flashregion_1_bios.bin" },
50 { "Intel ME", "me", "flashregion_2_intel_me.bin" },
51 { "GbE", "gbe", "flashregion_3_gbe.bin" },
52 { "Platform Data", "pd", "flashregion_4_platform_data.bin" },
53 { "Reserved", "res1", "flashregion_5_reserved.bin" },
54 { "Reserved", "res2", "flashregion_6_reserved.bin" },
55 { "Reserved", "res3", "flashregion_7_reserved.bin" },
56 { "EC", "ec", "flashregion_8_ec.bin" },
Chris Douglass03ce0142014-02-26 13:30:13 -050057};
58
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070059static fdbar_t *find_fd(char *image, int size)
60{
61 int i, found = 0;
62
63 /* Scan for FD signature */
64 for (i = 0; i < (size - 4); i += 4) {
65 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
66 found = 1;
67 break; // signature found.
68 }
69 }
70
71 if (!found) {
72 printf("No Flash Descriptor found in this image\n");
73 return NULL;
74 }
75
Bill XIE612ec0e2017-08-30 16:10:27 +080076 fdbar_t *fdb = (fdbar_t *) (image + i);
77 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
78}
79
80static fcba_t *find_fcba(char *image, int size)
81{
82 fdbar_t *fdb = find_fd(image, size);
83 if (!fdb)
84 return NULL;
85 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
86 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
87
88}
89
90static fmba_t *find_fmba(char *image, int size)
91{
92 fdbar_t *fdb = find_fd(image, size);
93 if (!fdb)
94 return NULL;
95 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
96 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
97}
98
99static frba_t *find_frba(char *image, int size)
100{
101 fdbar_t *fdb = find_fd(image, size);
102 if (!fdb)
103 return NULL;
104 frba_t *frba =
105 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
106 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
107}
108
109static fpsba_t *find_fpsba(char *image, int size)
110{
111 fdbar_t *fdb = find_fd(image, size);
112 if (!fdb)
113 return NULL;
114 fpsba_t *fpsba =
115 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
116 return PTR_IN_RANGE(fpsba, image, size) ? fpsba : NULL;
117}
118
119static fmsba_t *find_fmsba(char *image, int size)
120{
121 fdbar_t *fdb = find_fd(image, size);
122 if (!fdb)
123 return NULL;
124 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
125 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700126}
127
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700128/*
129 * There is no version field in the descriptor so to determine
130 * if this is a new descriptor format we check the hardcoded SPI
131 * read frequency to see if it is fixed at 20MHz or 17MHz.
132 */
133static void check_ifd_version(char *image, int size)
134{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700135 int read_freq;
136
Bill XIE612ec0e2017-08-30 16:10:27 +0800137 const fcba_t *fcba = find_fcba(image, size);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700138 if (!fcba)
139 exit(EXIT_FAILURE);
140
141 read_freq = (fcba->flcomp >> 17) & 7;
142
143 switch (read_freq) {
144 case SPI_FREQUENCY_20MHZ:
145 ifd_version = IFD_VERSION_1;
Alexander Couzensa81bef12016-10-08 00:29:15 +0200146 max_regions = MAX_REGIONS_OLD;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700147 break;
148 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700149 case SPI_FREQUENCY_50MHZ_30MHZ:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700150 ifd_version = IFD_VERSION_2;
Alexander Couzensa81bef12016-10-08 00:29:15 +0200151 max_regions = MAX_REGIONS;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700152 break;
153 default:
154 fprintf(stderr, "Unknown descriptor version: %d\n",
155 read_freq);
156 exit(EXIT_FAILURE);
157 }
158}
159
Bill XIEfa5f9942017-09-12 11:22:29 +0800160static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700161{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500162 int base_mask;
163 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700164 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700165 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500166
167 if (ifd_version >= IFD_VERSION_2)
168 base_mask = 0x7fff;
169 else
170 base_mask = 0xfff;
171
172 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700173
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400174 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800175 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700176 exit (EXIT_FAILURE);
177 }
178
Bill XIE4651d452017-09-12 11:54:48 +0800179 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700180 region.base = (flreg & base_mask) << 12;
181 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700182 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500183
Chris Douglass03ce0142014-02-26 13:30:13 -0500184 if (region.size < 0)
185 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700186
187 return region;
188}
189
Bill XIEfa5f9942017-09-12 11:22:29 +0800190static void set_region(frba_t *frba, unsigned int region_type,
191 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500192{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400193 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800194 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500195 exit (EXIT_FAILURE);
196 }
Bill XIE4651d452017-09-12 11:54:48 +0800197
198 frba->flreg[region_type] =
199 (((region->limit >> 12) & 0x7fff) << 16) |
200 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500201}
202
Bill XIEfa5f9942017-09-12 11:22:29 +0800203static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700204{
Bill XIEfa5f9942017-09-12 11:22:29 +0800205 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700206 fprintf(stderr, "Invalid region type.\n");
207 exit (EXIT_FAILURE);
208 }
209
Chris Douglass03ce0142014-02-26 13:30:13 -0500210 return region_names[region_type].pretty;
211}
212
Bill XIEfa5f9942017-09-12 11:22:29 +0800213static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500214{
Bill XIEfa5f9942017-09-12 11:22:29 +0800215 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500216 fprintf(stderr, "Invalid region type.\n");
217 exit (EXIT_FAILURE);
218 }
219
220 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700221}
222
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500223static int region_num(const char *name)
224{
Bill XIEfa5f9942017-09-12 11:22:29 +0800225 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500226
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200227 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500228 if (strcasecmp(name, region_names[i].pretty) == 0)
229 return i;
230 if (strcasecmp(name, region_names[i].terse) == 0)
231 return i;
232 }
233
234 return -1;
235}
236
Bill XIEfa5f9942017-09-12 11:22:29 +0800237static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700238{
Bill XIEfa5f9942017-09-12 11:22:29 +0800239 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700240 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700241 exit (EXIT_FAILURE);
242 }
243
Bill XIE1bf65062017-09-12 11:31:37 +0800244 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700245}
246
Bill XIEfa5f9942017-09-12 11:22:29 +0800247static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700248{
249 region_t region = get_region(frba, num);
250 printf(" Flash Region %d (%s): %08x - %08x %s\n",
251 num, region_name(num), region.base, region.limit,
252 region.size < 1 ? "(unused)" : "");
253}
254
Bill XIEfa5f9942017-09-12 11:22:29 +0800255static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
256 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500257{
258 region_t region = get_region(frba, num);
259 snprintf(buf, bufsize, "%08x:%08x %s\n",
260 region.base, region.limit, region_name_short(num));
261}
262
Bill XIEfa5f9942017-09-12 11:22:29 +0800263static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700264{
Bill XIE4651d452017-09-12 11:54:48 +0800265 unsigned int i;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700266 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800267 for (i = 0; i < max_regions; i++) {
268 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
269 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700270 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700271}
272
Bill XIEfa5f9942017-09-12 11:22:29 +0800273static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500274{
275 char buf[LAYOUT_LINELEN];
276 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800277 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500278
279 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
280 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
281 if (layout_fd == -1) {
282 perror("Could not open file");
283 exit(EXIT_FAILURE);
284 }
285
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200286 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200287 region_t region = get_region(frba, i);
288 /* is region invalid? */
289 if (region.size < 1)
290 continue;
291
Chris Douglass03ce0142014-02-26 13:30:13 -0500292 dump_region_layout(buf, bufsize, i, frba);
293 if (write(layout_fd, buf, strlen(buf)) < 0) {
294 perror("Could not write to file");
295 exit(EXIT_FAILURE);
296 }
297 }
298 close(layout_fd);
299 printf("Wrote layout to %s\n", layout_fname);
300}
301
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700302static void decode_spi_frequency(unsigned int freq)
303{
304 switch (freq) {
305 case SPI_FREQUENCY_20MHZ:
306 printf("20MHz");
307 break;
308 case SPI_FREQUENCY_33MHZ:
309 printf("33MHz");
310 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700311 case SPI_FREQUENCY_48MHZ:
312 printf("48MHz");
313 break;
314 case SPI_FREQUENCY_50MHZ_30MHZ:
315 switch (ifd_version) {
316 case IFD_VERSION_1:
317 printf("50MHz");
318 break;
319 case IFD_VERSION_2:
320 printf("30MHz");
321 break;
322 }
323 break;
324 case SPI_FREQUENCY_17MHZ:
325 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700326 break;
327 default:
328 printf("unknown<%x>MHz", freq);
329 }
330}
331
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700332static void decode_component_density(unsigned int density)
333{
334 switch (density) {
335 case COMPONENT_DENSITY_512KB:
336 printf("512KB");
337 break;
338 case COMPONENT_DENSITY_1MB:
339 printf("1MB");
340 break;
341 case COMPONENT_DENSITY_2MB:
342 printf("2MB");
343 break;
344 case COMPONENT_DENSITY_4MB:
345 printf("4MB");
346 break;
347 case COMPONENT_DENSITY_8MB:
348 printf("8MB");
349 break;
350 case COMPONENT_DENSITY_16MB:
351 printf("16MB");
352 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700353 case COMPONENT_DENSITY_32MB:
354 printf("32MB");
355 break;
356 case COMPONENT_DENSITY_64MB:
357 printf("64MB");
358 break;
359 case COMPONENT_DENSITY_UNUSED:
360 printf("UNUSED");
361 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700362 default:
363 printf("unknown<%x>MB", density);
364 }
365}
366
Bill XIEfa5f9942017-09-12 11:22:29 +0800367static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700368{
369 printf("\nFound Component Section\n");
370 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700371 printf(" Dual Output Fast Read Support: %ssupported\n",
372 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700373 printf(" Read ID/Read Status Clock Frequency: ");
374 decode_spi_frequency((fcba->flcomp >> 27) & 7);
375 printf("\n Write/Erase Clock Frequency: ");
376 decode_spi_frequency((fcba->flcomp >> 24) & 7);
377 printf("\n Fast Read Clock Frequency: ");
378 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700379 printf("\n Fast Read Support: %ssupported",
380 (fcba->flcomp & (1 << 20))?"":"not ");
381 printf("\n Read Clock Frequency: ");
382 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700383
384 switch (ifd_version) {
385 case IFD_VERSION_1:
386 printf("\n Component 2 Density: ");
387 decode_component_density((fcba->flcomp >> 3) & 7);
388 printf("\n Component 1 Density: ");
389 decode_component_density(fcba->flcomp & 7);
390 break;
391 case IFD_VERSION_2:
392 printf("\n Component 2 Density: ");
393 decode_component_density((fcba->flcomp >> 4) & 0xf);
394 printf("\n Component 1 Density: ");
395 decode_component_density(fcba->flcomp & 0xf);
396 break;
397 }
398
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700399 printf("\n");
400 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700401 printf(" Invalid Instruction 3: 0x%02x\n",
402 (fcba->flill >> 24) & 0xff);
403 printf(" Invalid Instruction 2: 0x%02x\n",
404 (fcba->flill >> 16) & 0xff);
405 printf(" Invalid Instruction 1: 0x%02x\n",
406 (fcba->flill >> 8) & 0xff);
407 printf(" Invalid Instruction 0: 0x%02x\n",
408 fcba->flill & 0xff);
409 printf("FLPB 0x%08x\n", fcba->flpb);
410 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
411 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700412}
413
Bill XIEfa5f9942017-09-12 11:22:29 +0800414static void dump_fpsba(const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700415{
Bill XIE4651d452017-09-12 11:54:48 +0800416 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700417 printf("Found PCH Strap Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800418 for (i = 0; i < ARRAY_SIZE(fpsba->pchstrp); i++)
419 printf("PCHSTRP%u:%s 0x%08x\n", i,
420 i < 10 ? " " : "", fpsba->pchstrp[i]);
421 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700422}
423
424static void decode_flmstr(uint32_t flmstr)
425{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700426 int wr_shift, rd_shift;
427 if (ifd_version >= IFD_VERSION_2) {
428 wr_shift = FLMSTR_WR_SHIFT_V2;
429 rd_shift = FLMSTR_RD_SHIFT_V2;
430 } else {
431 wr_shift = FLMSTR_WR_SHIFT_V1;
432 rd_shift = FLMSTR_RD_SHIFT_V1;
433 }
434
435 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700436 if (ifd_version >= IFD_VERSION_2)
437 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700438 (flmstr & (1 << (wr_shift + 8))) ?
439 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700440 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700441 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700442 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700443 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700444 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700445 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700446 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700447 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700448 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700449 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700450
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700451 if (ifd_version >= IFD_VERSION_2)
452 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700453 (flmstr & (1 << (rd_shift + 8))) ?
454 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700455 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700456 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700457 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700458 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700459 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700460 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700461 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700462 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700463 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700464 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700465
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700466 /* Requestor ID doesn't exist for ifd 2 */
467 if (ifd_version < IFD_VERSION_2)
468 printf(" Requester ID: 0x%04x\n\n",
469 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700470}
471
Bill XIEfa5f9942017-09-12 11:22:29 +0800472static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700473{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700474 printf("Found Master Section\n");
475 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
476 decode_flmstr(fmba->flmstr1);
477 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
478 decode_flmstr(fmba->flmstr2);
479 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
480 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700481 if (ifd_version >= IFD_VERSION_2) {
482 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
483 decode_flmstr(fmba->flmstr5);
484 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700485}
486
Bill XIEfa5f9942017-09-12 11:22:29 +0800487static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700488{
Bill XIE612ec0e2017-08-30 16:10:27 +0800489 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700490 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800491 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
492 printf("????: 0x%08x\n", fmsba->data[i]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700493}
494
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700495static void dump_jid(uint32_t jid)
496{
497 printf(" SPI Componend Device ID 1: 0x%02x\n",
498 (jid >> 16) & 0xff);
499 printf(" SPI Componend Device ID 0: 0x%02x\n",
500 (jid >> 8) & 0xff);
501 printf(" SPI Componend Vendor ID: 0x%02x\n",
502 jid & 0xff);
503}
504
505static void dump_vscc(uint32_t vscc)
506{
507 printf(" Lower Erase Opcode: 0x%02x\n",
508 vscc >> 24);
509 printf(" Lower Write Enable on Write Status: 0x%02x\n",
510 vscc & (1 << 20) ? 0x06 : 0x50);
511 printf(" Lower Write Status Required: %s\n",
512 vscc & (1 << 19) ? "Yes" : "No");
513 printf(" Lower Write Granularity: %d bytes\n",
514 vscc & (1 << 18) ? 64 : 1);
515 printf(" Lower Block / Sector Erase Size: ");
516 switch ((vscc >> 16) & 0x3) {
517 case 0:
518 printf("256 Byte\n");
519 break;
520 case 1:
521 printf("4KB\n");
522 break;
523 case 2:
524 printf("8KB\n");
525 break;
526 case 3:
527 printf("64KB\n");
528 break;
529 }
530
531 printf(" Upper Erase Opcode: 0x%02x\n",
532 (vscc >> 8) & 0xff);
533 printf(" Upper Write Enable on Write Status: 0x%02x\n",
534 vscc & (1 << 4) ? 0x06 : 0x50);
535 printf(" Upper Write Status Required: %s\n",
536 vscc & (1 << 3) ? "Yes" : "No");
537 printf(" Upper Write Granularity: %d bytes\n",
538 vscc & (1 << 2) ? 64 : 1);
539 printf(" Upper Block / Sector Erase Size: ");
540 switch (vscc & 0x3) {
541 case 0:
542 printf("256 Byte\n");
543 break;
544 case 1:
545 printf("4KB\n");
546 break;
547 case 2:
548 printf("8KB\n");
549 break;
550 case 3:
551 printf("64KB\n");
552 break;
553 }
554}
555
Bill XIEfa5f9942017-09-12 11:22:29 +0800556static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700557{
558 int i;
559 int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
560
561 printf("ME VSCC table:\n");
562 for (i = 0; i < num; i++) {
563 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
564 dump_jid(vtba->entry[i].jid);
565 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
566 dump_vscc(vtba->entry[i].vscc);
567 }
568 printf("\n");
569}
570
Bill XIEfa5f9942017-09-12 11:22:29 +0800571static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700572{
573 int i, j;
574 printf("OEM Section:\n");
575 for (i = 0; i < 4; i++) {
576 printf("%02x:", i << 4);
577 for (j = 0; j < 16; j++)
578 printf(" %02x", oem[(i<<4)+j]);
579 printf ("\n");
580 }
581 printf ("\n");
582}
583
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700584static void dump_fd(char *image, int size)
585{
Bill XIE612ec0e2017-08-30 16:10:27 +0800586 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700587 if (!fdb)
588 exit(EXIT_FAILURE);
589
590 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
591 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
592 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
593 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
594 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
595
596 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
597 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
598 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
599 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
600 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
601
602 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
603 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
604 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
605
606 printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700607 printf(" Intel ME VSCC Table Length (VTL): %d\n",
608 (fdb->flumap1 >> 8) & 0xff);
609 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
610 (fdb->flumap1 & 0xff) << 4);
611 dump_vtba((vtba_t *)
612 (image + ((fdb->flumap1 & 0xff) << 4)),
613 (fdb->flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800614 dump_oem((const uint8_t *)image + 0xf00);
615
616 const frba_t *frba = find_frba(image, size);
617 const fcba_t *fcba = find_fcba(image, size);
618 const fpsba_t *fpsba = find_fpsba(image, size);
619 const fmba_t *fmba = find_fmba(image, size);
620 const fmsba_t *fmsba = find_fmsba(image, size);
621
622 if (frba && fcba && fpsba && fmba && fmsba) {
623 dump_frba(frba);
624 dump_fcba(fcba);
625 dump_fpsba(fpsba);
626 dump_fmba(fmba);
627 dump_fmsba(fmsba);
628 } else {
629 printf("FD is corrupted!\n");
630 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700631}
632
Bill XIEfa5f9942017-09-12 11:22:29 +0800633static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500634{
Bill XIE612ec0e2017-08-30 16:10:27 +0800635 const frba_t *frba = find_frba(image, size);
636 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500637 exit(EXIT_FAILURE);
638
Bill XIE612ec0e2017-08-30 16:10:27 +0800639 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500640}
641
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700642static void write_regions(char *image, int size)
643{
Bill XIEfa5f9942017-09-12 11:22:29 +0800644 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800645 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700646
Bill XIE612ec0e2017-08-30 16:10:27 +0800647 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700648 exit(EXIT_FAILURE);
649
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700650 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700651 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700652 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700653 if (region.size > 0) {
654 int region_fd;
655 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600656 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700657 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200658 if (region_fd < 0) {
659 perror("Error while trying to open file");
660 exit(EXIT_FAILURE);
661 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700662 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700663 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700664 close(region_fd);
665 }
666 }
667}
668
Bill XIEfa5f9942017-09-12 11:22:29 +0800669static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700670{
671 char new_filename[FILENAME_MAX]; // allow long file names
672 int new_fd;
673
Patrick Georgi440daf72014-08-03 12:14:25 +0200674 // - 5: leave room for ".new\0"
675 strncpy(new_filename, filename, FILENAME_MAX - 5);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700676 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
677
678 printf("Writing new image to %s\n", new_filename);
679
680 // Now write out new image
681 new_fd = open(new_filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600682 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700683 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200684 if (new_fd < 0) {
685 perror("Error while trying to open file");
686 exit(EXIT_FAILURE);
687 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700688 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700689 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700690 close(new_fd);
691}
692
Bill XIEfa5f9942017-09-12 11:22:29 +0800693static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700694 enum spi_frequency freq)
695{
Bill XIE612ec0e2017-08-30 16:10:27 +0800696 fcba_t *fcba = find_fcba(image, size);
697 if (!fcba)
698 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700699
700 /* clear bits 21-29 */
701 fcba->flcomp &= ~0x3fe00000;
702 /* Read ID and Read Status Clock Frequency */
703 fcba->flcomp |= freq << 27;
704 /* Write and Erase Clock Frequency */
705 fcba->flcomp |= freq << 24;
706 /* Fast Read Clock Frequency */
707 fcba->flcomp |= freq << 21;
708
709 write_image(filename, image, size);
710}
711
Bill XIEfa5f9942017-09-12 11:22:29 +0800712static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700713{
Bill XIE612ec0e2017-08-30 16:10:27 +0800714 fcba_t *fcba = find_fcba(image, size);
715 if (!fcba)
716 exit(EXIT_FAILURE);
717
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700718 int freq;
719
720 switch (ifd_version) {
721 case IFD_VERSION_1:
722 freq = SPI_FREQUENCY_20MHZ;
723 break;
724 case IFD_VERSION_2:
725 freq = SPI_FREQUENCY_17MHZ;
726 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700727 default:
728 freq = SPI_FREQUENCY_17MHZ;
729 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700730 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700731
732 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700733 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700734}
735
Bill XIEfa5f9942017-09-12 11:22:29 +0800736static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100737 unsigned int density)
738{
Bill XIE612ec0e2017-08-30 16:10:27 +0800739 fcba_t *fcba = find_fcba(image, size);
740 if (!fcba)
741 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100742
743 printf("Setting chip density to ");
744 decode_component_density(density);
745 printf("\n");
746
747 switch (ifd_version) {
748 case IFD_VERSION_1:
749 /* fail if selected density is not supported by this version */
750 if ( (density == COMPONENT_DENSITY_32MB) ||
751 (density == COMPONENT_DENSITY_64MB) ||
752 (density == COMPONENT_DENSITY_UNUSED) ) {
753 printf("error: Selected density not supported in IFD version 1.\n");
754 exit(EXIT_FAILURE);
755 }
756 break;
757 case IFD_VERSION_2:
758 /* I do not have a version 2 IFD nor do i have the docs. */
759 printf("error: Changing the chip density for IFD version 2 has not been"
760 " implemented yet.\n");
761 exit(EXIT_FAILURE);
762 default:
763 printf("error: Unknown IFD version\n");
764 exit(EXIT_FAILURE);
765 break;
766 }
767
768 /* clear chip density for corresponding chip */
769 switch (selected_chip) {
770 case 1:
771 fcba->flcomp &= ~(0x7);
772 break;
773 case 2:
774 fcba->flcomp &= ~(0x7 << 3);
775 break;
776 default: /*both chips*/
777 fcba->flcomp &= ~(0x3F);
778 break;
779 }
780
781 /* set the new density */
782 if (selected_chip == 1 || selected_chip == 0)
783 fcba->flcomp |= (density); /* first chip */
784 if (selected_chip == 2 || selected_chip == 0)
785 fcba->flcomp |= (density << 3); /* second chip */
786
787 write_image(filename, image, size);
788}
789
Bill XIEfa5f9942017-09-12 11:22:29 +0800790static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700791{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700792 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800793 fmba_t *fmba = find_fmba(image, size);
794 if (!fmba)
795 exit(EXIT_FAILURE);
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700796 /* TODO: Dynamically take Platform Data Region and GbE Region
797 * into regard.
798 */
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700799
800 if (ifd_version >= IFD_VERSION_2) {
801 wr_shift = FLMSTR_WR_SHIFT_V2;
802 rd_shift = FLMSTR_RD_SHIFT_V2;
803
804 /* Clear non-reserved bits */
805 fmba->flmstr1 &= 0xff;
806 fmba->flmstr2 &= 0xff;
807 fmba->flmstr3 &= 0xff;
808 } else {
809 wr_shift = FLMSTR_WR_SHIFT_V1;
810 rd_shift = FLMSTR_RD_SHIFT_V1;
811
812 fmba->flmstr1 = 0;
813 fmba->flmstr2 = 0;
814 /* Requestor ID */
815 fmba->flmstr3 = 0x118;
816 }
817
Andrey Petrov96ecb772016-10-31 19:31:54 -0700818 switch (platform) {
819 case PLATFORM_APOLLOLAKE:
820 /* CPU/BIOS can read descriptor and BIOS */
821 fmba->flmstr1 |= 0x3 << rd_shift;
822 /* CPU/BIOS can write BIOS */
823 fmba->flmstr1 |= 0x2 << wr_shift;
824 /* TXE can read descriptor, BIOS and Device Expansion */
825 fmba->flmstr2 |= 0x23 << rd_shift;
826 /* TXE can only write Device Expansion */
827 fmba->flmstr2 |= 0x20 << wr_shift;
828 break;
829 default:
830 /* CPU/BIOS can read descriptor, BIOS, and GbE. */
831 fmba->flmstr1 |= 0xb << rd_shift;
832 /* CPU/BIOS can write BIOS and GbE. */
833 fmba->flmstr1 |= 0xa << wr_shift;
834 /* ME can read descriptor, ME, and GbE. */
835 fmba->flmstr2 |= 0xd << rd_shift;
836 /* ME can write ME and GbE. */
837 fmba->flmstr2 |= 0xc << wr_shift;
838 /* GbE can write only GbE. */
839 fmba->flmstr3 |= 0x8 << rd_shift;
840 /* GbE can read only GbE. */
841 fmba->flmstr3 |= 0x8 << wr_shift;
842 break;
843 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700844
845 write_image(filename, image, size);
846}
847
Bill XIEfa5f9942017-09-12 11:22:29 +0800848static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700849{
Bill XIE612ec0e2017-08-30 16:10:27 +0800850 fmba_t *fmba = find_fmba(image, size);
851 if (!fmba)
852 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700853
854 if (ifd_version >= IFD_VERSION_2) {
855 /* Access bits for each region are read: 19:8 write: 31:20 */
856 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
857 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
858 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
859 } else {
860 fmba->flmstr1 = 0xffff0000;
861 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +0100862 /* Keep chipset specific Requester ID */
863 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700864 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700865
866 write_image(filename, image, size);
867}
868
Bill XIEfa5f9942017-09-12 11:22:29 +0800869void inject_region(const char *filename, char *image, int size,
870 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700871{
Bill XIE612ec0e2017-08-30 16:10:27 +0800872 frba_t *frba = find_frba(image, size);
873 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700874 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700875
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700876 region_t region = get_region(frba, region_type);
877 if (region.size <= 0xfff) {
878 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
879 region_name(region_type));
880 exit(EXIT_FAILURE);
881 }
882
Scott Duplichanf2c98372014-12-12 21:03:06 -0600883 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700884 if (region_fd == -1) {
885 perror("Could not open file");
886 exit(EXIT_FAILURE);
887 }
888 struct stat buf;
889 if (fstat(region_fd, &buf) == -1) {
890 perror("Could not stat file");
891 exit(EXIT_FAILURE);
892 }
893 int region_size = buf.st_size;
894
895 printf("File %s is %d bytes\n", region_fname, region_size);
896
897 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -0800898 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700899 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
900 " bytes. Not injecting.\n",
901 region_name(region_type), region.size,
902 region.size, region_size, region_size);
903 exit(EXIT_FAILURE);
904 }
905
906 int offset = 0;
907 if ((region_type == 1) && (region_size < region.size)) {
908 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
909 " bytes. Padding before injecting.\n",
910 region_name(region_type), region.size,
911 region.size, region_size, region_size);
912 offset = region.size - region_size;
913 memset(image + region.base, 0xff, offset);
914 }
915
Stefan Reinauer5e93b372012-09-25 13:30:48 -0700916 if (size < region.base + offset + region_size) {
917 fprintf(stderr, "Output file is too small. (%d < %d)\n",
918 size, region.base + offset + region_size);
919 exit(EXIT_FAILURE);
920 }
921
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700922 if (read(region_fd, image + region.base + offset, region_size)
923 != region_size) {
924 perror("Could not read file");
925 exit(EXIT_FAILURE);
926 }
927
928 close(region_fd);
929
930 printf("Adding %s as the %s section of %s\n",
931 region_fname, region_name(region_type), filename);
932 write_image(filename, image, size);
933}
934
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500935unsigned int next_pow2(unsigned int x)
936{
937 unsigned int y = 1;
938 if (x == 0)
939 return 0;
940 while (y <= x)
941 y = y << 1;
942
943 return y;
944}
945
946/**
947 * Determine if two memory regions overlap.
948 *
949 * @param r1, r2 Memory regions to compare.
950 * @return 0 if the two regions are seperate
951 * @return 1 if the two regions overlap
952 */
Bill XIEfa5f9942017-09-12 11:22:29 +0800953static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500954{
Bill XIEfa5f9942017-09-12 11:22:29 +0800955 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500956 return 0;
957
Bill XIEfa5f9942017-09-12 11:22:29 +0800958 if ( ((r1->base >= r2->base) && (r1->base <= r2->limit)) ||
959 ((r1->limit >= r2->base) && (r1->limit <= r2->limit)) )
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500960 return 1;
961
962 return 0;
963}
964
Bill XIEfa5f9942017-09-12 11:22:29 +0800965void new_layout(const char *filename, char *image, int size,
966 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500967{
968 FILE *romlayout;
969 char tempstr[256];
970 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +0800971 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500972 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700973 region_t current_regions[MAX_REGIONS];
974 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500975 int new_extent = 0;
976 char *new_image;
977
978 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +0800979 frba_t *frba = find_frba(image, size);
980 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500981 exit(EXIT_FAILURE);
982
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200983 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500984 current_regions[i] = get_region(frba, i);
985 new_regions[i] = get_region(frba, i);
986 }
987
988 /* read new layout */
989 romlayout = fopen(layout_fname, "r");
990
991 if (!romlayout) {
992 perror("Could not read layout file.\n");
993 exit(EXIT_FAILURE);
994 }
995
996 while (!feof(romlayout)) {
997 char *tstr1, *tstr2;
998
Patrick Georgi802ad522014-08-09 17:12:23 +0200999 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001000 layout_region_name))
1001 continue;
1002
1003 region_number = region_num(layout_region_name);
1004 if (region_number < 0)
1005 continue;
1006
1007 tstr1 = strtok(tempstr, ":");
1008 tstr2 = strtok(NULL, ":");
1009 if (!tstr1 || !tstr2) {
1010 fprintf(stderr, "Could not parse layout file.\n");
1011 exit(EXIT_FAILURE);
1012 }
1013 new_regions[region_number].base = strtol(tstr1,
1014 (char **)NULL, 16);
1015 new_regions[region_number].limit = strtol(tstr2,
1016 (char **)NULL, 16);
1017 new_regions[region_number].size =
1018 new_regions[region_number].limit -
1019 new_regions[region_number].base + 1;
1020
1021 if (new_regions[region_number].size < 0)
1022 new_regions[region_number].size = 0;
1023 }
1024 fclose(romlayout);
1025
1026 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001027 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001028 if (new_regions[i].size == 0)
1029 continue;
1030
1031 if (new_regions[i].size < current_regions[i].size) {
1032 printf("DANGER: Region %s is shrinking.\n",
1033 region_name(i));
1034 printf(" The region will be truncated to fit.\n");
1035 printf(" This may result in an unusable image.\n");
1036 }
1037
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001038 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001039 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001040 fprintf(stderr, "Regions would overlap.\n");
1041 exit(EXIT_FAILURE);
1042 }
1043 }
1044
1045 /* detect if the image size should grow */
1046 if (new_extent < new_regions[i].limit)
1047 new_extent = new_regions[i].limit;
1048 }
1049
1050 new_extent = next_pow2(new_extent - 1);
1051 if (new_extent != size) {
1052 printf("The image has changed in size.\n");
1053 printf("The old image is %d bytes.\n", size);
1054 printf("The new image is %d bytes.\n", new_extent);
1055 }
1056
1057 /* copy regions to a new image */
1058 new_image = malloc(new_extent);
1059 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001060 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001061 int copy_size = new_regions[i].size;
1062 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001063 const region_t *current = &current_regions[i];
1064 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001065
Bill XIEfa5f9942017-09-12 11:22:29 +08001066 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001067 continue;
1068
Bill XIEfa5f9942017-09-12 11:22:29 +08001069 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001070 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001071 copy_size = current->size;
1072 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001073 }
1074
Bill XIEfa5f9942017-09-12 11:22:29 +08001075 if (new->size < current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001076 /* copy to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001077 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001078 }
1079
1080 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1081 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001082 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1083 offset_current, current->limit, current->size);
1084 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1085 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001086
Bill XIEfa5f9942017-09-12 11:22:29 +08001087 memcpy(new_image + new->base + offset_new,
1088 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001089 copy_size);
1090 }
1091
1092 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001093 frba = find_frba(new_image, new_extent);
1094 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001095 exit(EXIT_FAILURE);
1096
Bill XIE612ec0e2017-08-30 16:10:27 +08001097 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001098 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001099
1100 write_image(filename, new_image, new_extent);
1101 free(new_image);
1102}
1103
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001104static void print_version(void)
1105{
1106 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1107 printf("Copyright (C) 2011 Google Inc.\n\n");
1108 printf
1109 ("This program is free software: you can redistribute it and/or modify\n"
1110 "it under the terms of the GNU General Public License as published by\n"
1111 "the Free Software Foundation, version 2 of the License.\n\n"
1112 "This program is distributed in the hope that it will be useful,\n"
1113 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1114 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001115 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001116}
1117
1118static void print_usage(const char *name)
1119{
1120 printf("usage: %s [-vhdix?] <filename>\n", name);
1121 printf("\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001122 " -d | --dump: dump intel firmware descriptor\n"
1123 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1124 " -x | --extract: extract intel fd modules\n"
1125 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1126 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
1127 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
Jan Tatjefa317512016-03-11 00:52:07 +01001128 " -D | --density <512|1|2|4|8|16> set chip density (512 in KByte, others in MByte)\n"
1129 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1130 " can only be used once per run:\n"
1131 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001132 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1133 " Dual Output Fast Read Support\n"
1134 " -l | --lock Lock firmware descriptor and ME region\n"
1135 " -u | --unlock Unlock firmware descriptor and ME region\n"
Andrey Petrov96ecb772016-10-31 19:31:54 -07001136 " -p | --platform Add platform-specific quirks\n"
1137 " aplk - Apollo Lake\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001138 " -v | --version: print the version\n"
1139 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001140 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1141 "\n");
1142}
1143
1144int main(int argc, char *argv[])
1145{
1146 int opt, option_index = 0;
1147 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001148 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001149 int mode_layout = 0, mode_newlayout = 0, mode_density = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001150 char *region_type_string = NULL, *region_fname = NULL;
1151 const char *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001152 int region_type = -1, inputfreq = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001153 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001154 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1155
Bill XIEfa5f9942017-09-12 11:22:29 +08001156 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001157 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001158 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001159 {"extract", 0, NULL, 'x'},
1160 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001161 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001162 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001163 {"density", 1, NULL, 'D'},
1164 {"chip", 1, NULL, 'C'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001165 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001166 {"lock", 0, NULL, 'l'},
1167 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001168 {"version", 0, NULL, 'v'},
1169 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001170 {"platform", 0, NULL, 'p'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001171 {0, 0, 0, 0}
1172 };
1173
Andrey Petrov96ecb772016-10-31 19:31:54 -07001174 while ((opt = getopt_long(argc, argv, "df:D:C:xi:n:s:p:eluvh?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001175 long_options, &option_index)) != EOF) {
1176 switch (opt) {
1177 case 'd':
1178 mode_dump = 1;
1179 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001180 case 'f':
1181 mode_layout = 1;
1182 layout_fname = strdup(optarg);
1183 if (!layout_fname) {
1184 fprintf(stderr, "No layout file specified\n");
1185 print_usage(argv[0]);
1186 exit(EXIT_FAILURE);
1187 }
1188 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001189 case 'x':
1190 mode_extract = 1;
1191 break;
1192 case 'i':
1193 // separate type and file name
1194 region_type_string = strdup(optarg);
1195 region_fname = strchr(region_type_string, ':');
1196 if (!region_fname) {
1197 print_usage(argv[0]);
1198 exit(EXIT_FAILURE);
1199 }
1200 region_fname[0] = '\0';
1201 region_fname++;
1202 // Descriptor, BIOS, ME, GbE, Platform
1203 // valid type?
1204 if (!strcasecmp("Descriptor", region_type_string))
1205 region_type = 0;
1206 else if (!strcasecmp("BIOS", region_type_string))
1207 region_type = 1;
1208 else if (!strcasecmp("ME", region_type_string))
1209 region_type = 2;
1210 else if (!strcasecmp("GbE", region_type_string))
1211 region_type = 3;
1212 else if (!strcasecmp("Platform", region_type_string))
1213 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001214 else if (!strcasecmp("EC", region_type_string))
1215 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001216 if (region_type == -1) {
1217 fprintf(stderr, "No such region type: '%s'\n\n",
1218 region_type_string);
1219 print_usage(argv[0]);
1220 exit(EXIT_FAILURE);
1221 }
1222 mode_inject = 1;
1223 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001224 case 'n':
1225 mode_newlayout = 1;
1226 layout_fname = strdup(optarg);
1227 if (!layout_fname) {
1228 fprintf(stderr, "No layout file specified\n");
1229 print_usage(argv[0]);
1230 exit(EXIT_FAILURE);
1231 }
1232 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001233 case 'D':
1234 mode_density = 1;
1235 new_density = strtoul(optarg, NULL, 0);
1236 switch (new_density) {
1237 case 512:
1238 new_density = COMPONENT_DENSITY_512KB;
1239 break;
1240 case 1:
1241 new_density = COMPONENT_DENSITY_1MB;
1242 break;
1243 case 2:
1244 new_density = COMPONENT_DENSITY_2MB;
1245 break;
1246 case 4:
1247 new_density = COMPONENT_DENSITY_4MB;
1248 break;
1249 case 8:
1250 new_density = COMPONENT_DENSITY_8MB;
1251 break;
1252 case 16:
1253 new_density = COMPONENT_DENSITY_16MB;
1254 break;
1255 case 32:
1256 new_density = COMPONENT_DENSITY_32MB;
1257 break;
1258 case 64:
1259 new_density = COMPONENT_DENSITY_64MB;
1260 break;
1261 case 0:
1262 new_density = COMPONENT_DENSITY_UNUSED;
1263 break;
1264 default:
1265 printf("error: Unknown density\n");
1266 print_usage(argv[0]);
1267 exit(EXIT_FAILURE);
1268 }
1269 break;
1270 case 'C':
1271 selected_chip = strtol(optarg, NULL, 0);
1272 if (selected_chip > 2) {
1273 fprintf(stderr, "error: Invalid chip selection\n");
1274 print_usage(argv[0]);
1275 exit(EXIT_FAILURE);
1276 }
1277 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001278 case 's':
1279 // Parse the requested SPI frequency
1280 inputfreq = strtol(optarg, NULL, 0);
1281 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001282 case 17:
1283 spifreq = SPI_FREQUENCY_17MHZ;
1284 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001285 case 20:
1286 spifreq = SPI_FREQUENCY_20MHZ;
1287 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001288 case 30:
1289 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1290 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001291 case 33:
1292 spifreq = SPI_FREQUENCY_33MHZ;
1293 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001294 case 48:
1295 spifreq = SPI_FREQUENCY_48MHZ;
1296 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001297 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001298 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001299 break;
1300 default:
1301 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1302 inputfreq);
1303 print_usage(argv[0]);
1304 exit(EXIT_FAILURE);
1305 }
1306 mode_spifreq = 1;
1307 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001308 case 'e':
1309 mode_em100 = 1;
1310 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001311 case 'l':
1312 mode_locked = 1;
1313 if (mode_unlocked == 1) {
1314 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1315 exit(EXIT_FAILURE);
1316 }
1317 break;
1318 case 'u':
1319 mode_unlocked = 1;
1320 if (mode_locked == 1) {
1321 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1322 exit(EXIT_FAILURE);
1323 }
1324 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001325 case 'p':
1326 if (!strcmp(optarg, "aplk")) {
1327 platform = PLATFORM_APOLLOLAKE;
1328 } else {
1329 fprintf(stderr, "Unknown platform: %s\n", optarg);
1330 exit(EXIT_FAILURE);
1331 }
1332 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001333 case 'v':
1334 print_version();
1335 exit(EXIT_SUCCESS);
1336 break;
1337 case 'h':
1338 case '?':
1339 default:
1340 print_usage(argv[0]);
1341 exit(EXIT_SUCCESS);
1342 break;
1343 }
1344 }
1345
Chris Douglass03ce0142014-02-26 13:30:13 -05001346 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001347 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001348 mode_locked)) > 1) {
1349 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001350 print_usage(argv[0]);
1351 exit(EXIT_FAILURE);
1352 }
1353
Chris Douglass03ce0142014-02-26 13:30:13 -05001354 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001355 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Jan Tatjefa317512016-03-11 00:52:07 +01001356 mode_unlocked + mode_density) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001357 fprintf(stderr, "You need to specify a mode.\n\n");
1358 print_usage(argv[0]);
1359 exit(EXIT_FAILURE);
1360 }
1361
1362 if (optind + 1 != argc) {
1363 fprintf(stderr, "You need to specify a file.\n\n");
1364 print_usage(argv[0]);
1365 exit(EXIT_FAILURE);
1366 }
1367
1368 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001369 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001370 if (bios_fd == -1) {
1371 perror("Could not open file");
1372 exit(EXIT_FAILURE);
1373 }
1374 struct stat buf;
1375 if (fstat(bios_fd, &buf) == -1) {
1376 perror("Could not stat file");
1377 exit(EXIT_FAILURE);
1378 }
1379 int size = buf.st_size;
1380
1381 printf("File %s is %d bytes\n", filename, size);
1382
1383 char *image = malloc(size);
1384 if (!image) {
1385 printf("Out of memory.\n");
1386 exit(EXIT_FAILURE);
1387 }
1388
1389 if (read(bios_fd, image, size) != size) {
1390 perror("Could not read file");
1391 exit(EXIT_FAILURE);
1392 }
1393
1394 close(bios_fd);
1395
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001396 check_ifd_version(image, size);
1397
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001398 if (mode_dump)
1399 dump_fd(image, size);
1400
Chris Douglass03ce0142014-02-26 13:30:13 -05001401 if (mode_layout)
1402 dump_layout(image, size, layout_fname);
1403
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001404 if (mode_extract)
1405 write_regions(image, size);
1406
1407 if (mode_inject)
1408 inject_region(filename, image, size, region_type,
1409 region_fname);
1410
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001411 if (mode_newlayout)
1412 new_layout(filename, image, size, layout_fname);
1413
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001414 if (mode_spifreq)
1415 set_spi_frequency(filename, image, size, spifreq);
1416
Jan Tatjefa317512016-03-11 00:52:07 +01001417 if (mode_density)
1418 set_chipdensity(filename, image, size, new_density);
1419
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001420 if (mode_em100)
1421 set_em100_mode(filename, image, size);
1422
Alexander Couzensd12ea112016-09-10 13:33:05 +02001423 if (mode_locked)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001424 lock_descriptor(filename, image, size);
1425
1426 if (mode_unlocked)
1427 unlock_descriptor(filename, image, size);
1428
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001429 free(image);
1430
1431 return 0;
1432}