blob: 2835ba838b6fc5cc148ea94283cad3f5ccc02723 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003
4#include <unistd.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <getopt.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080012#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060013#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014#include "ifdtool.h"
15
Scott Duplichanf2c98372014-12-12 21:03:06 -060016#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
Bill XIE612ec0e2017-08-30 16:10:27 +080020/**
21 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
22 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
23 * @param base: base address represented with char* type.
24 * @param limit: upper limit of the legal address.
25 *
26 */
27#define PTR_IN_RANGE(ptr, base, limit) \
28 ((const char *)(ptr) >= (base) && \
29 (const char *)&(ptr)[1] <= (base) + (limit))
30
Duncan Laurie1f7fd722015-06-22 11:14:48 -070031static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080032static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080033static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010034static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070035static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050036
Duncan Laurie1f7fd722015-06-22 11:14:48 -070037static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060038 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
39 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
40 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
41 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
42 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
43 { "Reserved", "res1", "flashregion_5_reserved.bin", NULL },
44 { "Reserved", "res2", "flashregion_6_reserved.bin", NULL },
45 { "Reserved", "res3", "flashregion_7_reserved.bin", NULL },
46 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Chris Douglass03ce0142014-02-26 13:30:13 -050047};
48
Bill XIEb3e15a22017-09-07 18:34:50 +080049/* port from flashrom */
50static const char *const ich_chipset_names[] = {
51 "Unknown ICH",
52 "ICH",
53 "ICH2345",
54 "ICH6",
55 "SCH U",
56 "Atom E6xx",
57 "Atom S1220 S1240 S1260",
58 "ICH7",
59 "ICH8",
60 "ICH9",
61 "ICH10",
62 "5 series Ibex Peak",
63 "6 series Cougar Point",
64 "7 series Panther Point",
65 "8 series Lynx Point",
66 "Baytrail",
67 "8 series Lynx Point LP",
68 "8 series Wellsburg",
69 "9 series Wildcat Point",
70 "9 series Wildcat Point LP",
71 "100 series Sunrise Point",
72 "C620 series Lewisburg",
73 NULL
74};
75
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070076static fdbar_t *find_fd(char *image, int size)
77{
78 int i, found = 0;
79
80 /* Scan for FD signature */
81 for (i = 0; i < (size - 4); i += 4) {
82 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
83 found = 1;
84 break; // signature found.
85 }
86 }
87
88 if (!found) {
89 printf("No Flash Descriptor found in this image\n");
90 return NULL;
91 }
92
Bill XIE612ec0e2017-08-30 16:10:27 +080093 fdbar_t *fdb = (fdbar_t *) (image + i);
94 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
95}
96
Stefan Tauner0d226142018-08-05 18:56:53 +020097static char *find_flumap(char *image, int size)
98{
99 /* The upper map is located in the word before the 256B-long OEM section
100 * at the end of the 4kB-long flash descriptor. In the official
101 * documentation this is defined as FDBAR + 0xEFC. However, starting
102 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
103 * has moved 16 bytes back to offset 0x10 of the image. Although
104 * official documentation still maintains the offset relative to FDBAR
105 * this is wrong and a simple fixed offset from the start of the image
106 * works.
107 */
108 char *flumap = image + 4096 - 256 - 4;
109 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
110}
111
Bill XIE612ec0e2017-08-30 16:10:27 +0800112static fcba_t *find_fcba(char *image, int size)
113{
114 fdbar_t *fdb = find_fd(image, size);
115 if (!fdb)
116 return NULL;
117 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
118 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
119
120}
121
122static fmba_t *find_fmba(char *image, int size)
123{
124 fdbar_t *fdb = find_fd(image, size);
125 if (!fdb)
126 return NULL;
127 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
128 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
129}
130
131static frba_t *find_frba(char *image, int size)
132{
133 fdbar_t *fdb = find_fd(image, size);
134 if (!fdb)
135 return NULL;
136 frba_t *frba =
137 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
138 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
139}
140
141static fpsba_t *find_fpsba(char *image, int size)
142{
143 fdbar_t *fdb = find_fd(image, size);
144 if (!fdb)
145 return NULL;
146 fpsba_t *fpsba =
147 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200148
149 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
150 if ((((char *)fpsba) + SSL) >= (image + size))
151 return NULL;
152 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800153}
154
155static fmsba_t *find_fmsba(char *image, int size)
156{
157 fdbar_t *fdb = find_fd(image, size);
158 if (!fdb)
159 return NULL;
160 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
161 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700162}
163
Bill XIEb3e15a22017-09-07 18:34:50 +0800164/* port from flashrom */
165static enum ich_chipset guess_ich_chipset(const fdbar_t *fdb)
166{
167 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
168 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
169 uint32_t isl = (fdb->flmap1 >> 24);
170 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
171
172 if (iccriba == 0x00) {
173 if (msl == 0 && isl <= 2)
174 return CHIPSET_ICH8;
175 else if (isl <= 2)
176 return CHIPSET_ICH9;
177 else if (isl <= 10)
178 return CHIPSET_ICH10;
179 else if (isl <= 16)
180 return CHIPSET_5_SERIES_IBEX_PEAK;
181 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
182 return CHIPSET_5_SERIES_IBEX_PEAK;
183 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
184 if (msl == 0 && isl <= 17)
185 return CHIPSET_BAYTRAIL;
186 else if (msl <= 1 && isl <= 18)
187 return CHIPSET_6_SERIES_COUGAR_POINT;
188 else if (msl <= 1 && isl <= 21)
189 return CHIPSET_8_SERIES_LYNX_POINT;
190 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
191 return CHIPSET_9_SERIES_WILDCAT_POINT;
192 } else if (nm == 6) {
193 return CHIPSET_C620_SERIES_LEWISBURG;
194 } else {
195 return CHIPSET_100_SERIES_SUNRISE_POINT;
196 }
197}
198
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700199/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700200 * Some newer platforms have re-defined the FCBA field that was used to
201 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
202 * have the required FCBA field, but are IFD v2 and return true if current
203 * platform is one of them.
204 */
205static int is_platform_ifd_2(void)
206{
207 static const int ifd_2_platforms[] = {
208 PLATFORM_GLK,
209 PLATFORM_CNL,
Aamir Bohra1018be22018-06-29 15:08:50 +0530210 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700211 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530212 PLATFORM_JSL,
Subrata Banik46f80732020-03-14 15:01:42 +0530213 PLATFORM_ADL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700214 };
215 unsigned int i;
216
217 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
218 if (platform == ifd_2_platforms[i])
219 return 1;
220 }
221
222 return 0;
223}
224
225/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700226 * There is no version field in the descriptor so to determine
227 * if this is a new descriptor format we check the hardcoded SPI
228 * read frequency to see if it is fixed at 20MHz or 17MHz.
229 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700230static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700231{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700232 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800233 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800234 const fdbar_t *fdb = find_fd(image, size);
Jacob Garber9bb04612019-05-08 13:40:45 -0600235 if (!fcba || !fdb)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700236 exit(EXIT_FAILURE);
237
Bill XIEb3e15a22017-09-07 18:34:50 +0800238 chipset = guess_ich_chipset(fdb);
239 /* TODO: port ifd_version and max_regions
240 * against guess_ich_chipset()
241 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700242 read_freq = (fcba->flcomp >> 17) & 7;
243
244 switch (read_freq) {
245 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700246 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700247 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700248 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700249 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700250 default:
251 fprintf(stderr, "Unknown descriptor version: %d\n",
252 read_freq);
253 exit(EXIT_FAILURE);
254 }
255}
256
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700257static void check_ifd_version(char *image, int size)
258{
259 if (is_platform_ifd_2())
260 ifd_version = IFD_VERSION_2;
261 else
262 ifd_version = get_ifd_version_from_fcba(image, size);
263
264 if (ifd_version == IFD_VERSION_1)
265 max_regions = MAX_REGIONS_OLD;
266 else
267 max_regions = MAX_REGIONS;
268}
269
Bill XIEfa5f9942017-09-12 11:22:29 +0800270static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700271{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500272 int base_mask;
273 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700274 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700275 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500276
277 if (ifd_version >= IFD_VERSION_2)
278 base_mask = 0x7fff;
279 else
280 base_mask = 0xfff;
281
282 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700283
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400284 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800285 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700286 exit (EXIT_FAILURE);
287 }
288
Bill XIE4651d452017-09-12 11:54:48 +0800289 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700290 region.base = (flreg & base_mask) << 12;
291 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700292 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500293
Chris Douglass03ce0142014-02-26 13:30:13 -0500294 if (region.size < 0)
295 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700296
297 return region;
298}
299
Bill XIEfa5f9942017-09-12 11:22:29 +0800300static void set_region(frba_t *frba, unsigned int region_type,
301 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500302{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400303 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800304 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500305 exit (EXIT_FAILURE);
306 }
Bill XIE4651d452017-09-12 11:54:48 +0800307
308 frba->flreg[region_type] =
309 (((region->limit >> 12) & 0x7fff) << 16) |
310 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500311}
312
Bill XIEfa5f9942017-09-12 11:22:29 +0800313static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700314{
Bill XIEfa5f9942017-09-12 11:22:29 +0800315 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316 fprintf(stderr, "Invalid region type.\n");
317 exit (EXIT_FAILURE);
318 }
319
Chris Douglass03ce0142014-02-26 13:30:13 -0500320 return region_names[region_type].pretty;
321}
322
Bill XIEfa5f9942017-09-12 11:22:29 +0800323static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500324{
Bill XIEfa5f9942017-09-12 11:22:29 +0800325 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500326 fprintf(stderr, "Invalid region type.\n");
327 exit (EXIT_FAILURE);
328 }
329
330 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700331}
332
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500333static int region_num(const char *name)
334{
Bill XIEfa5f9942017-09-12 11:22:29 +0800335 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500336
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200337 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500338 if (strcasecmp(name, region_names[i].pretty) == 0)
339 return i;
340 if (strcasecmp(name, region_names[i].terse) == 0)
341 return i;
342 }
343
344 return -1;
345}
346
Bill XIEfa5f9942017-09-12 11:22:29 +0800347static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700348{
Bill XIEfa5f9942017-09-12 11:22:29 +0800349 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700350 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700351 exit (EXIT_FAILURE);
352 }
353
Bill XIE1bf65062017-09-12 11:31:37 +0800354 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355}
356
Bill XIEfa5f9942017-09-12 11:22:29 +0800357static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700358{
359 region_t region = get_region(frba, num);
360 printf(" Flash Region %d (%s): %08x - %08x %s\n",
361 num, region_name(num), region.base, region.limit,
362 region.size < 1 ? "(unused)" : "");
363}
364
Bill XIEfa5f9942017-09-12 11:22:29 +0800365static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
366 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500367{
368 region_t region = get_region(frba, num);
369 snprintf(buf, bufsize, "%08x:%08x %s\n",
370 region.base, region.limit, region_name_short(num));
371}
372
Bill XIEfa5f9942017-09-12 11:22:29 +0800373static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700374{
Bill XIE4651d452017-09-12 11:54:48 +0800375 unsigned int i;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700376 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800377 for (i = 0; i < max_regions; i++) {
378 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
379 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700380 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700381}
382
Bill XIEfa5f9942017-09-12 11:22:29 +0800383static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500384{
385 char buf[LAYOUT_LINELEN];
386 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800387 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500388
389 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
390 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
391 if (layout_fd == -1) {
392 perror("Could not open file");
393 exit(EXIT_FAILURE);
394 }
395
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200396 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200397 region_t region = get_region(frba, i);
398 /* is region invalid? */
399 if (region.size < 1)
400 continue;
401
Chris Douglass03ce0142014-02-26 13:30:13 -0500402 dump_region_layout(buf, bufsize, i, frba);
403 if (write(layout_fd, buf, strlen(buf)) < 0) {
404 perror("Could not write to file");
405 exit(EXIT_FAILURE);
406 }
407 }
408 close(layout_fd);
409 printf("Wrote layout to %s\n", layout_fname);
410}
411
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700412static void decode_spi_frequency(unsigned int freq)
413{
414 switch (freq) {
415 case SPI_FREQUENCY_20MHZ:
416 printf("20MHz");
417 break;
418 case SPI_FREQUENCY_33MHZ:
419 printf("33MHz");
420 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700421 case SPI_FREQUENCY_48MHZ:
422 printf("48MHz");
423 break;
424 case SPI_FREQUENCY_50MHZ_30MHZ:
425 switch (ifd_version) {
426 case IFD_VERSION_1:
427 printf("50MHz");
428 break;
429 case IFD_VERSION_2:
430 printf("30MHz");
431 break;
432 }
433 break;
434 case SPI_FREQUENCY_17MHZ:
435 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700436 break;
437 default:
438 printf("unknown<%x>MHz", freq);
439 }
440}
441
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700442static void decode_component_density(unsigned int density)
443{
444 switch (density) {
445 case COMPONENT_DENSITY_512KB:
446 printf("512KB");
447 break;
448 case COMPONENT_DENSITY_1MB:
449 printf("1MB");
450 break;
451 case COMPONENT_DENSITY_2MB:
452 printf("2MB");
453 break;
454 case COMPONENT_DENSITY_4MB:
455 printf("4MB");
456 break;
457 case COMPONENT_DENSITY_8MB:
458 printf("8MB");
459 break;
460 case COMPONENT_DENSITY_16MB:
461 printf("16MB");
462 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700463 case COMPONENT_DENSITY_32MB:
464 printf("32MB");
465 break;
466 case COMPONENT_DENSITY_64MB:
467 printf("64MB");
468 break;
469 case COMPONENT_DENSITY_UNUSED:
470 printf("UNUSED");
471 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700472 default:
473 printf("unknown<%x>MB", density);
474 }
475}
476
Bill XIEfa5f9942017-09-12 11:22:29 +0800477static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700478{
479 printf("\nFound Component Section\n");
480 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700481 printf(" Dual Output Fast Read Support: %ssupported\n",
482 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700483 printf(" Read ID/Read Status Clock Frequency: ");
484 decode_spi_frequency((fcba->flcomp >> 27) & 7);
485 printf("\n Write/Erase Clock Frequency: ");
486 decode_spi_frequency((fcba->flcomp >> 24) & 7);
487 printf("\n Fast Read Clock Frequency: ");
488 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700489 printf("\n Fast Read Support: %ssupported",
490 (fcba->flcomp & (1 << 20))?"":"not ");
491 printf("\n Read Clock Frequency: ");
492 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700493
494 switch (ifd_version) {
495 case IFD_VERSION_1:
496 printf("\n Component 2 Density: ");
497 decode_component_density((fcba->flcomp >> 3) & 7);
498 printf("\n Component 1 Density: ");
499 decode_component_density(fcba->flcomp & 7);
500 break;
501 case IFD_VERSION_2:
502 printf("\n Component 2 Density: ");
503 decode_component_density((fcba->flcomp >> 4) & 0xf);
504 printf("\n Component 1 Density: ");
505 decode_component_density(fcba->flcomp & 0xf);
506 break;
507 }
508
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700509 printf("\n");
510 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700511 printf(" Invalid Instruction 3: 0x%02x\n",
512 (fcba->flill >> 24) & 0xff);
513 printf(" Invalid Instruction 2: 0x%02x\n",
514 (fcba->flill >> 16) & 0xff);
515 printf(" Invalid Instruction 1: 0x%02x\n",
516 (fcba->flill >> 8) & 0xff);
517 printf(" Invalid Instruction 0: 0x%02x\n",
518 fcba->flill & 0xff);
519 printf("FLPB 0x%08x\n", fcba->flpb);
520 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
521 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700522}
523
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200524static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700525{
Bill XIE4651d452017-09-12 11:54:48 +0800526 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200527 /* SoC Strap Length, aka PSL, aka ISL */
528 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
529
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700530 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200531 for (i = 0; i < SSL; i++)
532 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800533
534 if (ifd_version >= IFD_VERSION_2) {
535 printf("HAP bit is %sset\n",
536 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
537 } else if (chipset >= CHIPSET_ICH8
538 && chipset <= CHIPSET_ICH10) {
539 printf("ICH_MeDisable bit is %sset\n",
540 fpsba->pchstrp[0] & 1 ? "" : "not ");
541 } else {
542 printf("AltMeDisable bit is %sset\n",
543 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
544 }
545
Bill XIE4651d452017-09-12 11:54:48 +0800546 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700547}
548
549static void decode_flmstr(uint32_t flmstr)
550{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700551 int wr_shift, rd_shift;
552 if (ifd_version >= IFD_VERSION_2) {
553 wr_shift = FLMSTR_WR_SHIFT_V2;
554 rd_shift = FLMSTR_RD_SHIFT_V2;
555 } else {
556 wr_shift = FLMSTR_WR_SHIFT_V1;
557 rd_shift = FLMSTR_RD_SHIFT_V1;
558 }
559
560 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700561 if (ifd_version >= IFD_VERSION_2)
562 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700563 (flmstr & (1 << (wr_shift + 8))) ?
564 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700565 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700566 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700567 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700568 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700569 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700570 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700571 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700572 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700573 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700574 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700575
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700576 if (ifd_version >= IFD_VERSION_2)
577 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700578 (flmstr & (1 << (rd_shift + 8))) ?
579 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700580 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700581 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700582 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700583 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700584 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700585 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700586 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700587 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700588 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700589 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700590
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700591 /* Requestor ID doesn't exist for ifd 2 */
592 if (ifd_version < IFD_VERSION_2)
593 printf(" Requester ID: 0x%04x\n\n",
594 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700595}
596
Bill XIEfa5f9942017-09-12 11:22:29 +0800597static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700598{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700599 printf("Found Master Section\n");
600 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
601 decode_flmstr(fmba->flmstr1);
602 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
603 decode_flmstr(fmba->flmstr2);
604 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
605 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700606 if (ifd_version >= IFD_VERSION_2) {
607 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
608 decode_flmstr(fmba->flmstr5);
609 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700610}
611
Bill XIEfa5f9942017-09-12 11:22:29 +0800612static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700613{
Bill XIE612ec0e2017-08-30 16:10:27 +0800614 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700615 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800616 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
617 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800618
619 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
620 printf("MCH_MeDisable bit is %sset\n",
621 fmsba->data[0] & 1 ? "" : "not ");
622 printf("MCH_AltMeDisable bit is %sset\n",
623 fmsba->data[0] & (1 << 7) ? "" : "not ");
624 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700625}
626
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700627static void dump_jid(uint32_t jid)
628{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100629 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700630 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100631 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200632 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100633 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200634 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700635}
636
637static void dump_vscc(uint32_t vscc)
638{
639 printf(" Lower Erase Opcode: 0x%02x\n",
640 vscc >> 24);
641 printf(" Lower Write Enable on Write Status: 0x%02x\n",
642 vscc & (1 << 20) ? 0x06 : 0x50);
643 printf(" Lower Write Status Required: %s\n",
644 vscc & (1 << 19) ? "Yes" : "No");
645 printf(" Lower Write Granularity: %d bytes\n",
646 vscc & (1 << 18) ? 64 : 1);
647 printf(" Lower Block / Sector Erase Size: ");
648 switch ((vscc >> 16) & 0x3) {
649 case 0:
650 printf("256 Byte\n");
651 break;
652 case 1:
653 printf("4KB\n");
654 break;
655 case 2:
656 printf("8KB\n");
657 break;
658 case 3:
659 printf("64KB\n");
660 break;
661 }
662
663 printf(" Upper Erase Opcode: 0x%02x\n",
664 (vscc >> 8) & 0xff);
665 printf(" Upper Write Enable on Write Status: 0x%02x\n",
666 vscc & (1 << 4) ? 0x06 : 0x50);
667 printf(" Upper Write Status Required: %s\n",
668 vscc & (1 << 3) ? "Yes" : "No");
669 printf(" Upper Write Granularity: %d bytes\n",
670 vscc & (1 << 2) ? 64 : 1);
671 printf(" Upper Block / Sector Erase Size: ");
672 switch (vscc & 0x3) {
673 case 0:
674 printf("256 Byte\n");
675 break;
676 case 1:
677 printf("4KB\n");
678 break;
679 case 2:
680 printf("8KB\n");
681 break;
682 case 3:
683 printf("64KB\n");
684 break;
685 }
686}
687
Bill XIEfa5f9942017-09-12 11:22:29 +0800688static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700689{
690 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200691 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
692 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700693
694 printf("ME VSCC table:\n");
695 for (i = 0; i < num; i++) {
696 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
697 dump_jid(vtba->entry[i].jid);
698 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
699 dump_vscc(vtba->entry[i].vscc);
700 }
701 printf("\n");
702}
703
Bill XIEfa5f9942017-09-12 11:22:29 +0800704static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700705{
706 int i, j;
707 printf("OEM Section:\n");
708 for (i = 0; i < 4; i++) {
709 printf("%02x:", i << 4);
710 for (j = 0; j < 16; j++)
711 printf(" %02x", oem[(i<<4)+j]);
712 printf ("\n");
713 }
714 printf ("\n");
715}
716
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700717static void dump_fd(char *image, int size)
718{
Bill XIE612ec0e2017-08-30 16:10:27 +0800719 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700720 if (!fdb)
721 exit(EXIT_FAILURE);
722
Bill XIEb3e15a22017-09-07 18:34:50 +0800723 printf("ICH Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700724 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
725 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
726 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
727 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
728 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
729
730 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
731 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
732 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
733 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
734 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
735
736 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
737 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
738 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
739
Stefan Tauner0d226142018-08-05 18:56:53 +0200740 char *flumap = find_flumap(image, size);
741 uint32_t flumap1 = *(uint32_t *)flumap;
742 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700743 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200744 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700745 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200746 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700747 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200748 (image + ((flumap1 & 0xff) << 4)),
749 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800750 dump_oem((const uint8_t *)image + 0xf00);
751
752 const frba_t *frba = find_frba(image, size);
753 const fcba_t *fcba = find_fcba(image, size);
754 const fpsba_t *fpsba = find_fpsba(image, size);
755 const fmba_t *fmba = find_fmba(image, size);
756 const fmsba_t *fmsba = find_fmsba(image, size);
757
758 if (frba && fcba && fpsba && fmba && fmsba) {
759 dump_frba(frba);
760 dump_fcba(fcba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200761 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800762 dump_fmba(fmba);
763 dump_fmsba(fmsba);
764 } else {
765 printf("FD is corrupted!\n");
766 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700767}
768
Bill XIEfa5f9942017-09-12 11:22:29 +0800769static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500770{
Bill XIE612ec0e2017-08-30 16:10:27 +0800771 const frba_t *frba = find_frba(image, size);
772 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500773 exit(EXIT_FAILURE);
774
Bill XIE612ec0e2017-08-30 16:10:27 +0800775 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500776}
777
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700778static void write_regions(char *image, int size)
779{
Bill XIEfa5f9942017-09-12 11:22:29 +0800780 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800781 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700782
Bill XIE612ec0e2017-08-30 16:10:27 +0800783 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700784 exit(EXIT_FAILURE);
785
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700786 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700787 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700788 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700789 if (region.size > 0) {
790 int region_fd;
791 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600792 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700793 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200794 if (region_fd < 0) {
795 perror("Error while trying to open file");
796 exit(EXIT_FAILURE);
797 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700798 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700799 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700800 close(region_fd);
801 }
802 }
803}
804
Mathew Kingc7ddc992019-08-08 14:59:25 -0600805static void validate_layout(char *image, int size)
806{
807 uint i, errors = 0;
808 struct fmap *fmap;
809 long int fmap_loc = fmap_find((uint8_t *)image, size);
810 const frba_t *frba = find_frba(image, size);
811
812 if (fmap_loc < 0 || !frba)
813 exit(EXIT_FAILURE);
814
815 fmap = (struct fmap *)(image + fmap_loc);
816
817 for (i = 0; i < max_regions; i++) {
818 if (region_names[i].fmapname == NULL)
819 continue;
820
821 region_t region = get_region(frba, i);
822
823 if (region.size == 0)
824 continue;
825
826 const struct fmap_area *area =
827 fmap_find_area(fmap, region_names[i].fmapname);
828
829 if (!area)
830 continue;
831
832 if ((uint)region.base != area->offset ||
833 (uint)region.size != area->size) {
834 printf("Region mismatch between %s and %s\n",
835 region_names[i].terse, area->name);
836 printf(" Descriptor region %s:\n", region_names[i].terse);
837 printf(" offset: 0x%08x\n", region.base);
838 printf(" length: 0x%08x\n", region.size);
839 printf(" FMAP area %s:\n", area->name);
840 printf(" offset: 0x%08x\n", area->offset);
841 printf(" length: 0x%08x\n", area->size);
842 errors++;
843 }
844 }
845
846 if (errors > 0)
847 exit(EXIT_FAILURE);
848}
849
Bill XIEfa5f9942017-09-12 11:22:29 +0800850static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700851{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700852 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100853 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700854
855 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100856 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600857 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700858 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200859 if (new_fd < 0) {
860 perror("Error while trying to open file");
861 exit(EXIT_FAILURE);
862 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700863 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700864 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700865 close(new_fd);
866}
867
Bill XIEfa5f9942017-09-12 11:22:29 +0800868static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700869 enum spi_frequency freq)
870{
Bill XIE612ec0e2017-08-30 16:10:27 +0800871 fcba_t *fcba = find_fcba(image, size);
872 if (!fcba)
873 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700874
875 /* clear bits 21-29 */
876 fcba->flcomp &= ~0x3fe00000;
877 /* Read ID and Read Status Clock Frequency */
878 fcba->flcomp |= freq << 27;
879 /* Write and Erase Clock Frequency */
880 fcba->flcomp |= freq << 24;
881 /* Fast Read Clock Frequency */
882 fcba->flcomp |= freq << 21;
883
884 write_image(filename, image, size);
885}
886
Bill XIEfa5f9942017-09-12 11:22:29 +0800887static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700888{
Bill XIE612ec0e2017-08-30 16:10:27 +0800889 fcba_t *fcba = find_fcba(image, size);
890 if (!fcba)
891 exit(EXIT_FAILURE);
892
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700893 int freq;
894
895 switch (ifd_version) {
896 case IFD_VERSION_1:
897 freq = SPI_FREQUENCY_20MHZ;
898 break;
899 case IFD_VERSION_2:
900 freq = SPI_FREQUENCY_17MHZ;
901 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700902 default:
903 freq = SPI_FREQUENCY_17MHZ;
904 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700905 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700906
907 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700908 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700909}
910
Bill XIEfa5f9942017-09-12 11:22:29 +0800911static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100912 unsigned int density)
913{
Bill XIE612ec0e2017-08-30 16:10:27 +0800914 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200915 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800916 if (!fcba)
917 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100918
919 printf("Setting chip density to ");
920 decode_component_density(density);
921 printf("\n");
922
923 switch (ifd_version) {
924 case IFD_VERSION_1:
925 /* fail if selected density is not supported by this version */
926 if ( (density == COMPONENT_DENSITY_32MB) ||
927 (density == COMPONENT_DENSITY_64MB) ||
928 (density == COMPONENT_DENSITY_UNUSED) ) {
929 printf("error: Selected density not supported in IFD version 1.\n");
930 exit(EXIT_FAILURE);
931 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200932 mask = 0x7;
933 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100934 break;
935 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200936 mask = 0xf;
937 chip2_offset = 4;
938 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100939 default:
940 printf("error: Unknown IFD version\n");
941 exit(EXIT_FAILURE);
942 break;
943 }
944
945 /* clear chip density for corresponding chip */
946 switch (selected_chip) {
947 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200948 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100949 break;
950 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200951 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100952 break;
953 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200954 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +0100955 break;
956 }
957
958 /* set the new density */
959 if (selected_chip == 1 || selected_chip == 0)
960 fcba->flcomp |= (density); /* first chip */
961 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200962 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +0100963
964 write_image(filename, image, size);
965}
966
Duncan Laurie7775d672019-06-06 13:39:26 -0700967static int check_region(const frba_t *frba, unsigned int region_type)
968{
969 region_t region;
970
971 if (!frba)
972 return 0;
973
974 region = get_region(frba, region_type);
975 return !!((region.base < region.limit) && (region.size > 0));
976}
977
Bill XIEfa5f9942017-09-12 11:22:29 +0800978static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700979{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700980 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800981 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -0700982 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800983 if (!fmba)
984 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700985
986 if (ifd_version >= IFD_VERSION_2) {
987 wr_shift = FLMSTR_WR_SHIFT_V2;
988 rd_shift = FLMSTR_RD_SHIFT_V2;
989
990 /* Clear non-reserved bits */
991 fmba->flmstr1 &= 0xff;
992 fmba->flmstr2 &= 0xff;
993 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -0800994 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700995 } else {
996 wr_shift = FLMSTR_WR_SHIFT_V1;
997 rd_shift = FLMSTR_RD_SHIFT_V1;
998
999 fmba->flmstr1 = 0;
1000 fmba->flmstr2 = 0;
1001 /* Requestor ID */
1002 fmba->flmstr3 = 0x118;
1003 }
1004
Andrey Petrov96ecb772016-10-31 19:31:54 -07001005 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001006 case PLATFORM_APL:
1007 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001008 /* CPU/BIOS can read descriptor and BIOS */
1009 fmba->flmstr1 |= 0x3 << rd_shift;
1010 /* CPU/BIOS can write BIOS */
1011 fmba->flmstr1 |= 0x2 << wr_shift;
1012 /* TXE can read descriptor, BIOS and Device Expansion */
1013 fmba->flmstr2 |= 0x23 << rd_shift;
1014 /* TXE can only write Device Expansion */
1015 fmba->flmstr2 |= 0x20 << wr_shift;
1016 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001017 case PLATFORM_CNL:
1018 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001019 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001020 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301021 case PLATFORM_JSL:
Subrata Banik46f80732020-03-14 15:01:42 +05301022 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001023 /* CPU/BIOS can read descriptor and BIOS. */
1024 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1025 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1026 /* CPU/BIOS can write BIOS. */
1027 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1028 /* ME can read descriptor and ME. */
1029 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1030 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001031 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001032 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1033 if (check_region(frba, REGION_GBE)) {
1034 /* BIOS can read/write GbE. */
1035 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1036 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1037 /* ME can read GbE. */
1038 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1039 /* GbE can read descriptor and read/write GbE.. */
1040 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1041 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1042 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1043 }
1044 if (check_region(frba, REGION_PDR)) {
1045 /* BIOS can read/write PDR. */
1046 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1047 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1048 }
1049 if (check_region(frba, REGION_EC)) {
1050 /* BIOS can read EC. */
1051 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1052 /* EC can read descriptor and read/write EC. */
1053 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1054 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1055 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1056 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001057 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001058 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001059 /* CPU/BIOS can read descriptor and BIOS. */
1060 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1061 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1062 /* CPU/BIOS can write BIOS. */
1063 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1064 /* ME can read descriptor and ME. */
1065 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1066 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1067 /* ME can write ME. */
1068 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1069 if (check_region(frba, REGION_GBE)) {
1070 /* BIOS can read GbE. */
1071 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1072 /* BIOS can write GbE. */
1073 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1074 /* ME can read GbE. */
1075 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1076 /* ME can write GbE. */
1077 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1078 /* GbE can write GbE. */
1079 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1080 /* GbE can read GbE. */
1081 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1082 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001083 break;
1084 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001085
1086 write_image(filename, image, size);
1087}
1088
Bill XIEfa5f9942017-09-12 11:22:29 +08001089static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001090{
Bill XIE612ec0e2017-08-30 16:10:27 +08001091 fmba_t *fmba = find_fmba(image, size);
1092 if (!fmba)
1093 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001094
1095 if (ifd_version >= IFD_VERSION_2) {
1096 /* Access bits for each region are read: 19:8 write: 31:20 */
1097 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1098 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1099 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001100 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001101 } else {
1102 fmba->flmstr1 = 0xffff0000;
1103 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001104 /* Keep chipset specific Requester ID */
1105 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001106 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001107
1108 write_image(filename, image, size);
1109}
1110
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001111static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1112 const unsigned int value)
1113{
1114 if (!fpsba || !fdb) {
1115 fprintf(stderr, "Internal error\n");
1116 exit(EXIT_FAILURE);
1117 }
1118
1119 /* SoC Strap Length, aka PSL, aka ISL */
1120 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1121 if (strap >= SSL) {
1122 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1123 exit(EXIT_FAILURE);
1124 }
1125 fpsba->pchstrp[strap] = value;
1126}
1127
Bill XIEb3e15a22017-09-07 18:34:50 +08001128/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001129static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001130{
1131 if (ifd_version >= IFD_VERSION_2) {
1132 printf("%sting the HAP bit to %s Intel ME...\n",
1133 altmedisable?"Set":"Unset",
1134 altmedisable?"disable":"enable");
1135 if (altmedisable)
1136 fpsba->pchstrp[0] |= (1 << 16);
1137 else
1138 fpsba->pchstrp[0] &= ~(1 << 16);
1139 } else {
1140 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1141 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1142 "and MCH_AltMeDisable to %s Intel ME...\n",
1143 altmedisable?"Set":"Unset",
1144 altmedisable?"disable":"enable");
1145 if (altmedisable) {
1146 /* MCH_MeDisable */
1147 fmsba->data[0] |= 1;
1148 /* MCH_AltMeDisable */
1149 fmsba->data[0] |= (1 << 7);
1150 /* ICH_MeDisable */
1151 fpsba->pchstrp[0] |= 1;
1152 } else {
1153 fmsba->data[0] &= ~1;
1154 fmsba->data[0] &= ~(1 << 7);
1155 fpsba->pchstrp[0] &= ~1;
1156 }
1157 } else {
1158 printf("%sting the AltMeDisable to %s Intel ME...\n",
1159 altmedisable?"Set":"Unset",
1160 altmedisable?"disable":"enable");
1161 if (altmedisable)
1162 fpsba->pchstrp[10] |= (1 << 7);
1163 else
1164 fpsba->pchstrp[10] &= ~(1 << 7);
1165 }
1166 }
1167}
1168
Jacob Garber595d9262019-06-27 17:33:10 -06001169static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001170 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001171{
Bill XIE612ec0e2017-08-30 16:10:27 +08001172 frba_t *frba = find_frba(image, size);
1173 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001174 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001175
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001176 region_t region = get_region(frba, region_type);
1177 if (region.size <= 0xfff) {
1178 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1179 region_name(region_type));
1180 exit(EXIT_FAILURE);
1181 }
1182
Scott Duplichanf2c98372014-12-12 21:03:06 -06001183 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001184 if (region_fd == -1) {
1185 perror("Could not open file");
1186 exit(EXIT_FAILURE);
1187 }
1188 struct stat buf;
1189 if (fstat(region_fd, &buf) == -1) {
1190 perror("Could not stat file");
1191 exit(EXIT_FAILURE);
1192 }
1193 int region_size = buf.st_size;
1194
1195 printf("File %s is %d bytes\n", region_fname, region_size);
1196
1197 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001198 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001199 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1200 " bytes. Not injecting.\n",
1201 region_name(region_type), region.size,
1202 region.size, region_size, region_size);
1203 exit(EXIT_FAILURE);
1204 }
1205
1206 int offset = 0;
1207 if ((region_type == 1) && (region_size < region.size)) {
1208 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1209 " bytes. Padding before injecting.\n",
1210 region_name(region_type), region.size,
1211 region.size, region_size, region_size);
1212 offset = region.size - region_size;
1213 memset(image + region.base, 0xff, offset);
1214 }
1215
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001216 if (size < region.base + offset + region_size) {
1217 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1218 size, region.base + offset + region_size);
1219 exit(EXIT_FAILURE);
1220 }
1221
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001222 if (read(region_fd, image + region.base + offset, region_size)
1223 != region_size) {
1224 perror("Could not read file");
1225 exit(EXIT_FAILURE);
1226 }
1227
1228 close(region_fd);
1229
1230 printf("Adding %s as the %s section of %s\n",
1231 region_fname, region_name(region_type), filename);
1232 write_image(filename, image, size);
1233}
1234
Jacob Garber595d9262019-06-27 17:33:10 -06001235static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001236{
1237 unsigned int y = 1;
1238 if (x == 0)
1239 return 0;
1240 while (y <= x)
1241 y = y << 1;
1242
1243 return y;
1244}
1245
1246/**
1247 * Determine if two memory regions overlap.
1248 *
1249 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001250 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001251 * @return 1 if the two regions overlap
1252 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001253static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001254{
Bill XIEfa5f9942017-09-12 11:22:29 +08001255 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001256 return 0;
1257
Nico Huber844eda02019-01-05 00:06:19 +01001258 /* r1 should be either completely below or completely above r2 */
1259 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001260}
1261
Jacob Garber595d9262019-06-27 17:33:10 -06001262static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001263 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001264{
1265 FILE *romlayout;
1266 char tempstr[256];
1267 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001268 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001269 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001270 region_t current_regions[MAX_REGIONS];
1271 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001272 int new_extent = 0;
1273 char *new_image;
1274
1275 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001276 frba_t *frba = find_frba(image, size);
1277 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001278 exit(EXIT_FAILURE);
1279
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001280 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001281 current_regions[i] = get_region(frba, i);
1282 new_regions[i] = get_region(frba, i);
1283 }
1284
1285 /* read new layout */
1286 romlayout = fopen(layout_fname, "r");
1287
1288 if (!romlayout) {
1289 perror("Could not read layout file.\n");
1290 exit(EXIT_FAILURE);
1291 }
1292
1293 while (!feof(romlayout)) {
1294 char *tstr1, *tstr2;
1295
Patrick Georgi802ad522014-08-09 17:12:23 +02001296 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001297 layout_region_name))
1298 continue;
1299
1300 region_number = region_num(layout_region_name);
1301 if (region_number < 0)
1302 continue;
1303
1304 tstr1 = strtok(tempstr, ":");
1305 tstr2 = strtok(NULL, ":");
1306 if (!tstr1 || !tstr2) {
1307 fprintf(stderr, "Could not parse layout file.\n");
1308 exit(EXIT_FAILURE);
1309 }
1310 new_regions[region_number].base = strtol(tstr1,
1311 (char **)NULL, 16);
1312 new_regions[region_number].limit = strtol(tstr2,
1313 (char **)NULL, 16);
1314 new_regions[region_number].size =
1315 new_regions[region_number].limit -
1316 new_regions[region_number].base + 1;
1317
1318 if (new_regions[region_number].size < 0)
1319 new_regions[region_number].size = 0;
1320 }
1321 fclose(romlayout);
1322
1323 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001324 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001325 if (new_regions[i].size == 0)
1326 continue;
1327
1328 if (new_regions[i].size < current_regions[i].size) {
1329 printf("DANGER: Region %s is shrinking.\n",
1330 region_name(i));
1331 printf(" The region will be truncated to fit.\n");
1332 printf(" This may result in an unusable image.\n");
1333 }
1334
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001335 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001336 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001337 fprintf(stderr, "Regions would overlap.\n");
1338 exit(EXIT_FAILURE);
1339 }
1340 }
1341
1342 /* detect if the image size should grow */
1343 if (new_extent < new_regions[i].limit)
1344 new_extent = new_regions[i].limit;
1345 }
1346
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001347 /* check if the image is actually a Flash Descriptor region */
1348 if (size == new_regions[0].size) {
1349 printf("The image is a single Flash Descriptor:\n");
1350 printf(" Only the descriptor will be modified\n");
1351 new_extent = size;
1352 } else {
1353 new_extent = next_pow2(new_extent - 1);
1354 if (new_extent != size) {
1355 printf("The image has changed in size.\n");
1356 printf("The old image is %d bytes.\n", size);
1357 printf("The new image is %d bytes.\n", new_extent);
1358 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001359 }
1360
1361 /* copy regions to a new image */
1362 new_image = malloc(new_extent);
1363 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001364 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001365 int copy_size = new_regions[i].size;
1366 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001367 const region_t *current = &current_regions[i];
1368 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001369
Bill XIEfa5f9942017-09-12 11:22:29 +08001370 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001371 continue;
1372
Bill XIEfa5f9942017-09-12 11:22:29 +08001373 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001374 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001375 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001376 if (i == REGION_BIOS)
1377 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001378 }
1379
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001380 if ((i == REGION_BIOS) && (new->size < current->size)) {
1381 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001382 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001383 }
1384
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001385 if (size < current->base + offset_current + copy_size) {
1386 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1387 region_name(i));
1388 continue;
1389 };
1390
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001391 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1392 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001393 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1394 offset_current, current->limit, current->size);
1395 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1396 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001397
Bill XIEfa5f9942017-09-12 11:22:29 +08001398 memcpy(new_image + new->base + offset_new,
1399 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001400 copy_size);
1401 }
1402
1403 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001404 frba = find_frba(new_image, new_extent);
1405 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001406 exit(EXIT_FAILURE);
1407
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001408 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001409 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001410 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001411
1412 write_image(filename, new_image, new_extent);
1413 free(new_image);
1414}
1415
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001416static void print_version(void)
1417{
1418 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1419 printf("Copyright (C) 2011 Google Inc.\n\n");
1420 printf
1421 ("This program is free software: you can redistribute it and/or modify\n"
1422 "it under the terms of the GNU General Public License as published by\n"
1423 "the Free Software Foundation, version 2 of the License.\n\n"
1424 "This program is distributed in the hope that it will be useful,\n"
1425 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1426 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001427 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001428}
1429
1430static void print_usage(const char *name)
1431{
1432 printf("usage: %s [-vhdix?] <filename>\n", name);
1433 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001434 " -d | --dump: dump intel firmware descriptor\n"
1435 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1436 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1437 " -x | --extract: extract intel fd modules\n"
1438 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1439 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001440 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001441 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1442 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1443 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1444 " can only be used once per run:\n"
1445 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1446 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1447 " Dual Output Fast Read Support\n"
1448 " -l | --lock Lock firmware descriptor and ME region\n"
1449 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001450 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1451 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001452 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301453 " adl - Alder Lake\n"
1454 " aplk - Apollo Lake\n"
1455 " cnl - Cannon Lake\n"
1456 " glk - Gemini Lake\n"
1457 " icl - Ice Lake\n"
1458 " jsl - Jasper Lake\n"
1459 " sklkbl - Sky Lake/Kaby Lake\n"
1460 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001461 " -S | --setpchstrap Write a PCH strap\n"
1462 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001463 " -v | --version: print the version\n"
1464 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001465 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1466 "\n");
1467}
1468
1469int main(int argc, char *argv[])
1470{
1471 int opt, option_index = 0;
1472 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001473 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001474 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001475 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001476 char *region_type_string = NULL, *region_fname = NULL;
1477 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001478 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001479 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001480 unsigned int value = 0;
1481 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001482 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001483 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1484
Bill XIEfa5f9942017-09-12 11:22:29 +08001485 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001486 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001487 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001488 {"extract", 0, NULL, 'x'},
1489 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001490 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001491 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001492 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001493 {"density", 1, NULL, 'D'},
1494 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001495 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001496 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001497 {"lock", 0, NULL, 'l'},
1498 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001499 {"version", 0, NULL, 'v'},
1500 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001501 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001502 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001503 {"setpchstrap", 1, NULL, 'S'},
1504 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001505 {0, 0, 0, 0}
1506 };
1507
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001508 while ((opt = getopt_long(argc, argv, "S:V:df:D:C:M:xi:n:O:s:p:eluvth?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001509 long_options, &option_index)) != EOF) {
1510 switch (opt) {
1511 case 'd':
1512 mode_dump = 1;
1513 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001514 case 'S':
1515 mode_setstrap = 1;
1516 pchstrap = strtoul(optarg, NULL, 0);
1517 break;
1518 case 'V':
1519 value = strtoul(optarg, NULL, 0);
1520 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001521 case 'f':
1522 mode_layout = 1;
1523 layout_fname = strdup(optarg);
1524 if (!layout_fname) {
1525 fprintf(stderr, "No layout file specified\n");
1526 print_usage(argv[0]);
1527 exit(EXIT_FAILURE);
1528 }
1529 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001530 case 'x':
1531 mode_extract = 1;
1532 break;
1533 case 'i':
1534 // separate type and file name
1535 region_type_string = strdup(optarg);
1536 region_fname = strchr(region_type_string, ':');
1537 if (!region_fname) {
1538 print_usage(argv[0]);
1539 exit(EXIT_FAILURE);
1540 }
1541 region_fname[0] = '\0';
1542 region_fname++;
1543 // Descriptor, BIOS, ME, GbE, Platform
1544 // valid type?
1545 if (!strcasecmp("Descriptor", region_type_string))
1546 region_type = 0;
1547 else if (!strcasecmp("BIOS", region_type_string))
1548 region_type = 1;
1549 else if (!strcasecmp("ME", region_type_string))
1550 region_type = 2;
1551 else if (!strcasecmp("GbE", region_type_string))
1552 region_type = 3;
1553 else if (!strcasecmp("Platform", region_type_string))
1554 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001555 else if (!strcasecmp("EC", region_type_string))
1556 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001557 if (region_type == -1) {
1558 fprintf(stderr, "No such region type: '%s'\n\n",
1559 region_type_string);
1560 print_usage(argv[0]);
1561 exit(EXIT_FAILURE);
1562 }
1563 mode_inject = 1;
1564 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001565 case 'n':
1566 mode_newlayout = 1;
1567 layout_fname = strdup(optarg);
1568 if (!layout_fname) {
1569 fprintf(stderr, "No layout file specified\n");
1570 print_usage(argv[0]);
1571 exit(EXIT_FAILURE);
1572 }
1573 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001574 case 'O':
1575 new_filename = strdup(optarg);
1576 if (!new_filename) {
1577 fprintf(stderr, "No output filename specified\n");
1578 print_usage(argv[0]);
1579 exit(EXIT_FAILURE);
1580 }
1581 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001582 case 'D':
1583 mode_density = 1;
1584 new_density = strtoul(optarg, NULL, 0);
1585 switch (new_density) {
1586 case 512:
1587 new_density = COMPONENT_DENSITY_512KB;
1588 break;
1589 case 1:
1590 new_density = COMPONENT_DENSITY_1MB;
1591 break;
1592 case 2:
1593 new_density = COMPONENT_DENSITY_2MB;
1594 break;
1595 case 4:
1596 new_density = COMPONENT_DENSITY_4MB;
1597 break;
1598 case 8:
1599 new_density = COMPONENT_DENSITY_8MB;
1600 break;
1601 case 16:
1602 new_density = COMPONENT_DENSITY_16MB;
1603 break;
1604 case 32:
1605 new_density = COMPONENT_DENSITY_32MB;
1606 break;
1607 case 64:
1608 new_density = COMPONENT_DENSITY_64MB;
1609 break;
1610 case 0:
1611 new_density = COMPONENT_DENSITY_UNUSED;
1612 break;
1613 default:
1614 printf("error: Unknown density\n");
1615 print_usage(argv[0]);
1616 exit(EXIT_FAILURE);
1617 }
1618 break;
1619 case 'C':
1620 selected_chip = strtol(optarg, NULL, 0);
1621 if (selected_chip > 2) {
1622 fprintf(stderr, "error: Invalid chip selection\n");
1623 print_usage(argv[0]);
1624 exit(EXIT_FAILURE);
1625 }
1626 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001627 case 'M':
1628 mode_altmedisable = 1;
1629 altmedisable = strtol(optarg, NULL, 0);
1630 if (altmedisable > 1) {
1631 fprintf(stderr, "error: Illegal value\n");
1632 print_usage(argv[0]);
1633 exit(EXIT_FAILURE);
1634 }
1635 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001636 case 's':
1637 // Parse the requested SPI frequency
1638 inputfreq = strtol(optarg, NULL, 0);
1639 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001640 case 17:
1641 spifreq = SPI_FREQUENCY_17MHZ;
1642 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001643 case 20:
1644 spifreq = SPI_FREQUENCY_20MHZ;
1645 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001646 case 30:
1647 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1648 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001649 case 33:
1650 spifreq = SPI_FREQUENCY_33MHZ;
1651 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001652 case 48:
1653 spifreq = SPI_FREQUENCY_48MHZ;
1654 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001655 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001656 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001657 break;
1658 default:
1659 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1660 inputfreq);
1661 print_usage(argv[0]);
1662 exit(EXIT_FAILURE);
1663 }
1664 mode_spifreq = 1;
1665 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001666 case 'e':
1667 mode_em100 = 1;
1668 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001669 case 'l':
1670 mode_locked = 1;
1671 if (mode_unlocked == 1) {
1672 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1673 exit(EXIT_FAILURE);
1674 }
1675 break;
1676 case 'u':
1677 mode_unlocked = 1;
1678 if (mode_locked == 1) {
1679 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1680 exit(EXIT_FAILURE);
1681 }
1682 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001683 case 'p':
1684 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001685 platform = PLATFORM_APL;
1686 } else if (!strcmp(optarg, "cnl")) {
1687 platform = PLATFORM_CNL;
1688 } else if (!strcmp(optarg, "glk")) {
1689 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301690 } else if (!strcmp(optarg, "icl")) {
1691 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301692 } else if (!strcmp(optarg, "jsl")) {
1693 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001694 } else if (!strcmp(optarg, "sklkbl")) {
1695 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001696 } else if (!strcmp(optarg, "tgl")) {
1697 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301698 } else if (!strcmp(optarg, "adl")) {
1699 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001700 } else {
1701 fprintf(stderr, "Unknown platform: %s\n", optarg);
1702 exit(EXIT_FAILURE);
1703 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001704 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001705 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001706 case 't':
1707 mode_validate = 1;
1708 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001709 case 'v':
1710 print_version();
1711 exit(EXIT_SUCCESS);
1712 break;
1713 case 'h':
1714 case '?':
1715 default:
1716 print_usage(argv[0]);
1717 exit(EXIT_SUCCESS);
1718 break;
1719 }
1720 }
1721
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001722 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001723 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001724 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001725 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001726 print_usage(argv[0]);
1727 exit(EXIT_FAILURE);
1728 }
1729
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001730 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001731 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001732 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001733 fprintf(stderr, "You need to specify a mode.\n\n");
1734 print_usage(argv[0]);
1735 exit(EXIT_FAILURE);
1736 }
1737
1738 if (optind + 1 != argc) {
1739 fprintf(stderr, "You need to specify a file.\n\n");
1740 print_usage(argv[0]);
1741 exit(EXIT_FAILURE);
1742 }
1743
1744 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001745 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001746 if (bios_fd == -1) {
1747 perror("Could not open file");
1748 exit(EXIT_FAILURE);
1749 }
1750 struct stat buf;
1751 if (fstat(bios_fd, &buf) == -1) {
1752 perror("Could not stat file");
1753 exit(EXIT_FAILURE);
1754 }
1755 int size = buf.st_size;
1756
1757 printf("File %s is %d bytes\n", filename, size);
1758
1759 char *image = malloc(size);
1760 if (!image) {
1761 printf("Out of memory.\n");
1762 exit(EXIT_FAILURE);
1763 }
1764
1765 if (read(bios_fd, image, size) != size) {
1766 perror("Could not read file");
1767 exit(EXIT_FAILURE);
1768 }
1769
1770 close(bios_fd);
1771
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001772 // generate new filename
1773 if (new_filename == NULL) {
1774 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1775 if (!new_filename) {
1776 printf("Out of memory.\n");
1777 exit(EXIT_FAILURE);
1778 }
1779 // - 5: leave room for ".new\0"
1780 strcpy(new_filename, filename);
1781 strcat(new_filename, ".new");
1782 }
1783
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001784 check_ifd_version(image, size);
1785
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001786 if (mode_dump)
1787 dump_fd(image, size);
1788
Chris Douglass03ce0142014-02-26 13:30:13 -05001789 if (mode_layout)
1790 dump_layout(image, size, layout_fname);
1791
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001792 if (mode_extract)
1793 write_regions(image, size);
1794
Mathew Kingc7ddc992019-08-08 14:59:25 -06001795 if (mode_validate)
1796 validate_layout(image, size);
1797
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001798 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001799 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001800 region_fname);
1801
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001802 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001803 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001804
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001805 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001806 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001807
Jan Tatjefa317512016-03-11 00:52:07 +01001808 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001809 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001810
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001811 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001812 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001813
Alexander Couzensd12ea112016-09-10 13:33:05 +02001814 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001815 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001816
1817 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001818 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001819
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001820 if (mode_setstrap) {
1821 fpsba_t *fpsba = find_fpsba(image, size);
1822 const fdbar_t *fdb = find_fd(image, size);
1823 set_pchstrap(fpsba, fdb, pchstrap, value);
1824 write_image(new_filename, image, size);
1825 }
1826
Bill XIEb3e15a22017-09-07 18:34:50 +08001827 if (mode_altmedisable) {
1828 fpsba_t *fpsba = find_fpsba(image, size);
1829 fmsba_t *fmsba = find_fmsba(image, size);
1830 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001831 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001832 }
1833
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001834 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001835 free(image);
1836
1837 return 0;
1838}