blob: 3db3977bf501ff0c1da806194d6a36f0617dbe22 [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,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700213 };
214 unsigned int i;
215
216 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
217 if (platform == ifd_2_platforms[i])
218 return 1;
219 }
220
221 return 0;
222}
223
224/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700225 * There is no version field in the descriptor so to determine
226 * if this is a new descriptor format we check the hardcoded SPI
227 * read frequency to see if it is fixed at 20MHz or 17MHz.
228 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700229static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700230{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700231 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800232 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800233 const fdbar_t *fdb = find_fd(image, size);
Jacob Garber9bb04612019-05-08 13:40:45 -0600234 if (!fcba || !fdb)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700235 exit(EXIT_FAILURE);
236
Bill XIEb3e15a22017-09-07 18:34:50 +0800237 chipset = guess_ich_chipset(fdb);
238 /* TODO: port ifd_version and max_regions
239 * against guess_ich_chipset()
240 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700241 read_freq = (fcba->flcomp >> 17) & 7;
242
243 switch (read_freq) {
244 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700245 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700246 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700247 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700248 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700249 default:
250 fprintf(stderr, "Unknown descriptor version: %d\n",
251 read_freq);
252 exit(EXIT_FAILURE);
253 }
254}
255
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700256static void check_ifd_version(char *image, int size)
257{
258 if (is_platform_ifd_2())
259 ifd_version = IFD_VERSION_2;
260 else
261 ifd_version = get_ifd_version_from_fcba(image, size);
262
263 if (ifd_version == IFD_VERSION_1)
264 max_regions = MAX_REGIONS_OLD;
265 else
266 max_regions = MAX_REGIONS;
267}
268
Bill XIEfa5f9942017-09-12 11:22:29 +0800269static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700270{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500271 int base_mask;
272 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700273 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700274 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500275
276 if (ifd_version >= IFD_VERSION_2)
277 base_mask = 0x7fff;
278 else
279 base_mask = 0xfff;
280
281 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700282
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400283 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800284 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700285 exit (EXIT_FAILURE);
286 }
287
Bill XIE4651d452017-09-12 11:54:48 +0800288 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700289 region.base = (flreg & base_mask) << 12;
290 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700291 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500292
Chris Douglass03ce0142014-02-26 13:30:13 -0500293 if (region.size < 0)
294 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700295
296 return region;
297}
298
Bill XIEfa5f9942017-09-12 11:22:29 +0800299static void set_region(frba_t *frba, unsigned int region_type,
300 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500301{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400302 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800303 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500304 exit (EXIT_FAILURE);
305 }
Bill XIE4651d452017-09-12 11:54:48 +0800306
307 frba->flreg[region_type] =
308 (((region->limit >> 12) & 0x7fff) << 16) |
309 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500310}
311
Bill XIEfa5f9942017-09-12 11:22:29 +0800312static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700313{
Bill XIEfa5f9942017-09-12 11:22:29 +0800314 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700315 fprintf(stderr, "Invalid region type.\n");
316 exit (EXIT_FAILURE);
317 }
318
Chris Douglass03ce0142014-02-26 13:30:13 -0500319 return region_names[region_type].pretty;
320}
321
Bill XIEfa5f9942017-09-12 11:22:29 +0800322static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500323{
Bill XIEfa5f9942017-09-12 11:22:29 +0800324 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500325 fprintf(stderr, "Invalid region type.\n");
326 exit (EXIT_FAILURE);
327 }
328
329 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700330}
331
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500332static int region_num(const char *name)
333{
Bill XIEfa5f9942017-09-12 11:22:29 +0800334 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500335
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200336 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500337 if (strcasecmp(name, region_names[i].pretty) == 0)
338 return i;
339 if (strcasecmp(name, region_names[i].terse) == 0)
340 return i;
341 }
342
343 return -1;
344}
345
Bill XIEfa5f9942017-09-12 11:22:29 +0800346static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700347{
Bill XIEfa5f9942017-09-12 11:22:29 +0800348 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700349 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700350 exit (EXIT_FAILURE);
351 }
352
Bill XIE1bf65062017-09-12 11:31:37 +0800353 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700354}
355
Bill XIEfa5f9942017-09-12 11:22:29 +0800356static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700357{
358 region_t region = get_region(frba, num);
359 printf(" Flash Region %d (%s): %08x - %08x %s\n",
360 num, region_name(num), region.base, region.limit,
361 region.size < 1 ? "(unused)" : "");
362}
363
Bill XIEfa5f9942017-09-12 11:22:29 +0800364static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
365 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500366{
367 region_t region = get_region(frba, num);
368 snprintf(buf, bufsize, "%08x:%08x %s\n",
369 region.base, region.limit, region_name_short(num));
370}
371
Bill XIEfa5f9942017-09-12 11:22:29 +0800372static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700373{
Bill XIE4651d452017-09-12 11:54:48 +0800374 unsigned int i;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700375 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800376 for (i = 0; i < max_regions; i++) {
377 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
378 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700379 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700380}
381
Bill XIEfa5f9942017-09-12 11:22:29 +0800382static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500383{
384 char buf[LAYOUT_LINELEN];
385 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800386 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500387
388 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
389 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
390 if (layout_fd == -1) {
391 perror("Could not open file");
392 exit(EXIT_FAILURE);
393 }
394
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200395 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200396 region_t region = get_region(frba, i);
397 /* is region invalid? */
398 if (region.size < 1)
399 continue;
400
Chris Douglass03ce0142014-02-26 13:30:13 -0500401 dump_region_layout(buf, bufsize, i, frba);
402 if (write(layout_fd, buf, strlen(buf)) < 0) {
403 perror("Could not write to file");
404 exit(EXIT_FAILURE);
405 }
406 }
407 close(layout_fd);
408 printf("Wrote layout to %s\n", layout_fname);
409}
410
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700411static void decode_spi_frequency(unsigned int freq)
412{
413 switch (freq) {
414 case SPI_FREQUENCY_20MHZ:
415 printf("20MHz");
416 break;
417 case SPI_FREQUENCY_33MHZ:
418 printf("33MHz");
419 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700420 case SPI_FREQUENCY_48MHZ:
421 printf("48MHz");
422 break;
423 case SPI_FREQUENCY_50MHZ_30MHZ:
424 switch (ifd_version) {
425 case IFD_VERSION_1:
426 printf("50MHz");
427 break;
428 case IFD_VERSION_2:
429 printf("30MHz");
430 break;
431 }
432 break;
433 case SPI_FREQUENCY_17MHZ:
434 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700435 break;
436 default:
437 printf("unknown<%x>MHz", freq);
438 }
439}
440
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700441static void decode_component_density(unsigned int density)
442{
443 switch (density) {
444 case COMPONENT_DENSITY_512KB:
445 printf("512KB");
446 break;
447 case COMPONENT_DENSITY_1MB:
448 printf("1MB");
449 break;
450 case COMPONENT_DENSITY_2MB:
451 printf("2MB");
452 break;
453 case COMPONENT_DENSITY_4MB:
454 printf("4MB");
455 break;
456 case COMPONENT_DENSITY_8MB:
457 printf("8MB");
458 break;
459 case COMPONENT_DENSITY_16MB:
460 printf("16MB");
461 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700462 case COMPONENT_DENSITY_32MB:
463 printf("32MB");
464 break;
465 case COMPONENT_DENSITY_64MB:
466 printf("64MB");
467 break;
468 case COMPONENT_DENSITY_UNUSED:
469 printf("UNUSED");
470 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700471 default:
472 printf("unknown<%x>MB", density);
473 }
474}
475
Bill XIEfa5f9942017-09-12 11:22:29 +0800476static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700477{
478 printf("\nFound Component Section\n");
479 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700480 printf(" Dual Output Fast Read Support: %ssupported\n",
481 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700482 printf(" Read ID/Read Status Clock Frequency: ");
483 decode_spi_frequency((fcba->flcomp >> 27) & 7);
484 printf("\n Write/Erase Clock Frequency: ");
485 decode_spi_frequency((fcba->flcomp >> 24) & 7);
486 printf("\n Fast Read Clock Frequency: ");
487 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700488 printf("\n Fast Read Support: %ssupported",
489 (fcba->flcomp & (1 << 20))?"":"not ");
490 printf("\n Read Clock Frequency: ");
491 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700492
493 switch (ifd_version) {
494 case IFD_VERSION_1:
495 printf("\n Component 2 Density: ");
496 decode_component_density((fcba->flcomp >> 3) & 7);
497 printf("\n Component 1 Density: ");
498 decode_component_density(fcba->flcomp & 7);
499 break;
500 case IFD_VERSION_2:
501 printf("\n Component 2 Density: ");
502 decode_component_density((fcba->flcomp >> 4) & 0xf);
503 printf("\n Component 1 Density: ");
504 decode_component_density(fcba->flcomp & 0xf);
505 break;
506 }
507
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700508 printf("\n");
509 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700510 printf(" Invalid Instruction 3: 0x%02x\n",
511 (fcba->flill >> 24) & 0xff);
512 printf(" Invalid Instruction 2: 0x%02x\n",
513 (fcba->flill >> 16) & 0xff);
514 printf(" Invalid Instruction 1: 0x%02x\n",
515 (fcba->flill >> 8) & 0xff);
516 printf(" Invalid Instruction 0: 0x%02x\n",
517 fcba->flill & 0xff);
518 printf("FLPB 0x%08x\n", fcba->flpb);
519 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
520 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700521}
522
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200523static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700524{
Bill XIE4651d452017-09-12 11:54:48 +0800525 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200526 /* SoC Strap Length, aka PSL, aka ISL */
527 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
528
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700529 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200530 for (i = 0; i < SSL; i++)
531 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800532
533 if (ifd_version >= IFD_VERSION_2) {
534 printf("HAP bit is %sset\n",
535 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
536 } else if (chipset >= CHIPSET_ICH8
537 && chipset <= CHIPSET_ICH10) {
538 printf("ICH_MeDisable bit is %sset\n",
539 fpsba->pchstrp[0] & 1 ? "" : "not ");
540 } else {
541 printf("AltMeDisable bit is %sset\n",
542 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
543 }
544
Bill XIE4651d452017-09-12 11:54:48 +0800545 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700546}
547
548static void decode_flmstr(uint32_t flmstr)
549{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700550 int wr_shift, rd_shift;
551 if (ifd_version >= IFD_VERSION_2) {
552 wr_shift = FLMSTR_WR_SHIFT_V2;
553 rd_shift = FLMSTR_RD_SHIFT_V2;
554 } else {
555 wr_shift = FLMSTR_WR_SHIFT_V1;
556 rd_shift = FLMSTR_RD_SHIFT_V1;
557 }
558
559 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700560 if (ifd_version >= IFD_VERSION_2)
561 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700562 (flmstr & (1 << (wr_shift + 8))) ?
563 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700564 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700565 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700566 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700567 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700568 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700569 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700570 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700571 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700572 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700573 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700574
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700575 if (ifd_version >= IFD_VERSION_2)
576 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700577 (flmstr & (1 << (rd_shift + 8))) ?
578 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700579 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700580 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700581 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700582 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700583 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700584 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700585 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700586 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700587 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700588 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700589
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700590 /* Requestor ID doesn't exist for ifd 2 */
591 if (ifd_version < IFD_VERSION_2)
592 printf(" Requester ID: 0x%04x\n\n",
593 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700594}
595
Bill XIEfa5f9942017-09-12 11:22:29 +0800596static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700597{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700598 printf("Found Master Section\n");
599 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
600 decode_flmstr(fmba->flmstr1);
601 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
602 decode_flmstr(fmba->flmstr2);
603 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
604 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700605 if (ifd_version >= IFD_VERSION_2) {
606 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
607 decode_flmstr(fmba->flmstr5);
608 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700609}
610
Bill XIEfa5f9942017-09-12 11:22:29 +0800611static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700612{
Bill XIE612ec0e2017-08-30 16:10:27 +0800613 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700614 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800615 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
616 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800617
618 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
619 printf("MCH_MeDisable bit is %sset\n",
620 fmsba->data[0] & 1 ? "" : "not ");
621 printf("MCH_AltMeDisable bit is %sset\n",
622 fmsba->data[0] & (1 << 7) ? "" : "not ");
623 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700624}
625
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700626static void dump_jid(uint32_t jid)
627{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100628 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700629 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100630 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200631 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100632 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200633 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700634}
635
636static void dump_vscc(uint32_t vscc)
637{
638 printf(" Lower Erase Opcode: 0x%02x\n",
639 vscc >> 24);
640 printf(" Lower Write Enable on Write Status: 0x%02x\n",
641 vscc & (1 << 20) ? 0x06 : 0x50);
642 printf(" Lower Write Status Required: %s\n",
643 vscc & (1 << 19) ? "Yes" : "No");
644 printf(" Lower Write Granularity: %d bytes\n",
645 vscc & (1 << 18) ? 64 : 1);
646 printf(" Lower Block / Sector Erase Size: ");
647 switch ((vscc >> 16) & 0x3) {
648 case 0:
649 printf("256 Byte\n");
650 break;
651 case 1:
652 printf("4KB\n");
653 break;
654 case 2:
655 printf("8KB\n");
656 break;
657 case 3:
658 printf("64KB\n");
659 break;
660 }
661
662 printf(" Upper Erase Opcode: 0x%02x\n",
663 (vscc >> 8) & 0xff);
664 printf(" Upper Write Enable on Write Status: 0x%02x\n",
665 vscc & (1 << 4) ? 0x06 : 0x50);
666 printf(" Upper Write Status Required: %s\n",
667 vscc & (1 << 3) ? "Yes" : "No");
668 printf(" Upper Write Granularity: %d bytes\n",
669 vscc & (1 << 2) ? 64 : 1);
670 printf(" Upper Block / Sector Erase Size: ");
671 switch (vscc & 0x3) {
672 case 0:
673 printf("256 Byte\n");
674 break;
675 case 1:
676 printf("4KB\n");
677 break;
678 case 2:
679 printf("8KB\n");
680 break;
681 case 3:
682 printf("64KB\n");
683 break;
684 }
685}
686
Bill XIEfa5f9942017-09-12 11:22:29 +0800687static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700688{
689 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200690 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
691 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700692
693 printf("ME VSCC table:\n");
694 for (i = 0; i < num; i++) {
695 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
696 dump_jid(vtba->entry[i].jid);
697 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
698 dump_vscc(vtba->entry[i].vscc);
699 }
700 printf("\n");
701}
702
Bill XIEfa5f9942017-09-12 11:22:29 +0800703static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700704{
705 int i, j;
706 printf("OEM Section:\n");
707 for (i = 0; i < 4; i++) {
708 printf("%02x:", i << 4);
709 for (j = 0; j < 16; j++)
710 printf(" %02x", oem[(i<<4)+j]);
711 printf ("\n");
712 }
713 printf ("\n");
714}
715
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700716static void dump_fd(char *image, int size)
717{
Bill XIE612ec0e2017-08-30 16:10:27 +0800718 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700719 if (!fdb)
720 exit(EXIT_FAILURE);
721
Bill XIEb3e15a22017-09-07 18:34:50 +0800722 printf("ICH Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700723 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
724 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
725 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
726 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
727 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
728
729 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
730 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
731 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
732 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
733 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
734
735 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
736 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
737 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
738
Stefan Tauner0d226142018-08-05 18:56:53 +0200739 char *flumap = find_flumap(image, size);
740 uint32_t flumap1 = *(uint32_t *)flumap;
741 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700742 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200743 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700744 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200745 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700746 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200747 (image + ((flumap1 & 0xff) << 4)),
748 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800749 dump_oem((const uint8_t *)image + 0xf00);
750
751 const frba_t *frba = find_frba(image, size);
752 const fcba_t *fcba = find_fcba(image, size);
753 const fpsba_t *fpsba = find_fpsba(image, size);
754 const fmba_t *fmba = find_fmba(image, size);
755 const fmsba_t *fmsba = find_fmsba(image, size);
756
757 if (frba && fcba && fpsba && fmba && fmsba) {
758 dump_frba(frba);
759 dump_fcba(fcba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200760 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800761 dump_fmba(fmba);
762 dump_fmsba(fmsba);
763 } else {
764 printf("FD is corrupted!\n");
765 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700766}
767
Bill XIEfa5f9942017-09-12 11:22:29 +0800768static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500769{
Bill XIE612ec0e2017-08-30 16:10:27 +0800770 const frba_t *frba = find_frba(image, size);
771 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500772 exit(EXIT_FAILURE);
773
Bill XIE612ec0e2017-08-30 16:10:27 +0800774 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500775}
776
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700777static void write_regions(char *image, int size)
778{
Bill XIEfa5f9942017-09-12 11:22:29 +0800779 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800780 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700781
Bill XIE612ec0e2017-08-30 16:10:27 +0800782 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700783 exit(EXIT_FAILURE);
784
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700785 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700786 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700787 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700788 if (region.size > 0) {
789 int region_fd;
790 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600791 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700792 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200793 if (region_fd < 0) {
794 perror("Error while trying to open file");
795 exit(EXIT_FAILURE);
796 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700797 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700798 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700799 close(region_fd);
800 }
801 }
802}
803
Mathew Kingc7ddc992019-08-08 14:59:25 -0600804static void validate_layout(char *image, int size)
805{
806 uint i, errors = 0;
807 struct fmap *fmap;
808 long int fmap_loc = fmap_find((uint8_t *)image, size);
809 const frba_t *frba = find_frba(image, size);
810
811 if (fmap_loc < 0 || !frba)
812 exit(EXIT_FAILURE);
813
814 fmap = (struct fmap *)(image + fmap_loc);
815
816 for (i = 0; i < max_regions; i++) {
817 if (region_names[i].fmapname == NULL)
818 continue;
819
820 region_t region = get_region(frba, i);
821
822 if (region.size == 0)
823 continue;
824
825 const struct fmap_area *area =
826 fmap_find_area(fmap, region_names[i].fmapname);
827
828 if (!area)
829 continue;
830
831 if ((uint)region.base != area->offset ||
832 (uint)region.size != area->size) {
833 printf("Region mismatch between %s and %s\n",
834 region_names[i].terse, area->name);
835 printf(" Descriptor region %s:\n", region_names[i].terse);
836 printf(" offset: 0x%08x\n", region.base);
837 printf(" length: 0x%08x\n", region.size);
838 printf(" FMAP area %s:\n", area->name);
839 printf(" offset: 0x%08x\n", area->offset);
840 printf(" length: 0x%08x\n", area->size);
841 errors++;
842 }
843 }
844
845 if (errors > 0)
846 exit(EXIT_FAILURE);
847}
848
Bill XIEfa5f9942017-09-12 11:22:29 +0800849static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700850{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700851 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100852 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700853
854 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100855 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600856 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700857 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200858 if (new_fd < 0) {
859 perror("Error while trying to open file");
860 exit(EXIT_FAILURE);
861 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700862 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700863 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700864 close(new_fd);
865}
866
Bill XIEfa5f9942017-09-12 11:22:29 +0800867static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700868 enum spi_frequency freq)
869{
Bill XIE612ec0e2017-08-30 16:10:27 +0800870 fcba_t *fcba = find_fcba(image, size);
871 if (!fcba)
872 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700873
874 /* clear bits 21-29 */
875 fcba->flcomp &= ~0x3fe00000;
876 /* Read ID and Read Status Clock Frequency */
877 fcba->flcomp |= freq << 27;
878 /* Write and Erase Clock Frequency */
879 fcba->flcomp |= freq << 24;
880 /* Fast Read Clock Frequency */
881 fcba->flcomp |= freq << 21;
882
883 write_image(filename, image, size);
884}
885
Bill XIEfa5f9942017-09-12 11:22:29 +0800886static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700887{
Bill XIE612ec0e2017-08-30 16:10:27 +0800888 fcba_t *fcba = find_fcba(image, size);
889 if (!fcba)
890 exit(EXIT_FAILURE);
891
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700892 int freq;
893
894 switch (ifd_version) {
895 case IFD_VERSION_1:
896 freq = SPI_FREQUENCY_20MHZ;
897 break;
898 case IFD_VERSION_2:
899 freq = SPI_FREQUENCY_17MHZ;
900 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700901 default:
902 freq = SPI_FREQUENCY_17MHZ;
903 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700904 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700905
906 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700907 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700908}
909
Bill XIEfa5f9942017-09-12 11:22:29 +0800910static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100911 unsigned int density)
912{
Bill XIE612ec0e2017-08-30 16:10:27 +0800913 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200914 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800915 if (!fcba)
916 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100917
918 printf("Setting chip density to ");
919 decode_component_density(density);
920 printf("\n");
921
922 switch (ifd_version) {
923 case IFD_VERSION_1:
924 /* fail if selected density is not supported by this version */
925 if ( (density == COMPONENT_DENSITY_32MB) ||
926 (density == COMPONENT_DENSITY_64MB) ||
927 (density == COMPONENT_DENSITY_UNUSED) ) {
928 printf("error: Selected density not supported in IFD version 1.\n");
929 exit(EXIT_FAILURE);
930 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200931 mask = 0x7;
932 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100933 break;
934 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200935 mask = 0xf;
936 chip2_offset = 4;
937 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100938 default:
939 printf("error: Unknown IFD version\n");
940 exit(EXIT_FAILURE);
941 break;
942 }
943
944 /* clear chip density for corresponding chip */
945 switch (selected_chip) {
946 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200947 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100948 break;
949 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200950 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100951 break;
952 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200953 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +0100954 break;
955 }
956
957 /* set the new density */
958 if (selected_chip == 1 || selected_chip == 0)
959 fcba->flcomp |= (density); /* first chip */
960 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200961 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +0100962
963 write_image(filename, image, size);
964}
965
Duncan Laurie7775d672019-06-06 13:39:26 -0700966static int check_region(const frba_t *frba, unsigned int region_type)
967{
968 region_t region;
969
970 if (!frba)
971 return 0;
972
973 region = get_region(frba, region_type);
974 return !!((region.base < region.limit) && (region.size > 0));
975}
976
Bill XIEfa5f9942017-09-12 11:22:29 +0800977static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700978{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700979 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800980 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -0700981 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800982 if (!fmba)
983 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700984
985 if (ifd_version >= IFD_VERSION_2) {
986 wr_shift = FLMSTR_WR_SHIFT_V2;
987 rd_shift = FLMSTR_RD_SHIFT_V2;
988
989 /* Clear non-reserved bits */
990 fmba->flmstr1 &= 0xff;
991 fmba->flmstr2 &= 0xff;
992 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -0800993 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700994 } else {
995 wr_shift = FLMSTR_WR_SHIFT_V1;
996 rd_shift = FLMSTR_RD_SHIFT_V1;
997
998 fmba->flmstr1 = 0;
999 fmba->flmstr2 = 0;
1000 /* Requestor ID */
1001 fmba->flmstr3 = 0x118;
1002 }
1003
Andrey Petrov96ecb772016-10-31 19:31:54 -07001004 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001005 case PLATFORM_APL:
1006 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001007 /* CPU/BIOS can read descriptor and BIOS */
1008 fmba->flmstr1 |= 0x3 << rd_shift;
1009 /* CPU/BIOS can write BIOS */
1010 fmba->flmstr1 |= 0x2 << wr_shift;
1011 /* TXE can read descriptor, BIOS and Device Expansion */
1012 fmba->flmstr2 |= 0x23 << rd_shift;
1013 /* TXE can only write Device Expansion */
1014 fmba->flmstr2 |= 0x20 << wr_shift;
1015 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001016 case PLATFORM_CNL:
1017 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001018 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001019 case PLATFORM_TGL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001020 /* CPU/BIOS can read descriptor and BIOS. */
1021 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1022 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1023 /* CPU/BIOS can write BIOS. */
1024 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1025 /* ME can read descriptor and ME. */
1026 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1027 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001028 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001029 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1030 if (check_region(frba, REGION_GBE)) {
1031 /* BIOS can read/write GbE. */
1032 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1033 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1034 /* ME can read GbE. */
1035 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1036 /* GbE can read descriptor and read/write GbE.. */
1037 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1038 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1039 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1040 }
1041 if (check_region(frba, REGION_PDR)) {
1042 /* BIOS can read/write PDR. */
1043 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1044 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1045 }
1046 if (check_region(frba, REGION_EC)) {
1047 /* BIOS can read EC. */
1048 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1049 /* EC can read descriptor and read/write EC. */
1050 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1051 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1052 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1053 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001054 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001055 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001056 /* CPU/BIOS can read descriptor and BIOS. */
1057 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1058 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1059 /* CPU/BIOS can write BIOS. */
1060 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1061 /* ME can read descriptor and ME. */
1062 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1063 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1064 /* ME can write ME. */
1065 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1066 if (check_region(frba, REGION_GBE)) {
1067 /* BIOS can read GbE. */
1068 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1069 /* BIOS can write GbE. */
1070 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1071 /* ME can read GbE. */
1072 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1073 /* ME can write GbE. */
1074 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1075 /* GbE can write GbE. */
1076 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1077 /* GbE can read GbE. */
1078 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1079 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001080 break;
1081 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001082
1083 write_image(filename, image, size);
1084}
1085
Bill XIEfa5f9942017-09-12 11:22:29 +08001086static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001087{
Bill XIE612ec0e2017-08-30 16:10:27 +08001088 fmba_t *fmba = find_fmba(image, size);
1089 if (!fmba)
1090 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001091
1092 if (ifd_version >= IFD_VERSION_2) {
1093 /* Access bits for each region are read: 19:8 write: 31:20 */
1094 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1095 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1096 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001097 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001098 } else {
1099 fmba->flmstr1 = 0xffff0000;
1100 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001101 /* Keep chipset specific Requester ID */
1102 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001103 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001104
1105 write_image(filename, image, size);
1106}
1107
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001108static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1109 const unsigned int value)
1110{
1111 if (!fpsba || !fdb) {
1112 fprintf(stderr, "Internal error\n");
1113 exit(EXIT_FAILURE);
1114 }
1115
1116 /* SoC Strap Length, aka PSL, aka ISL */
1117 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1118 if (strap >= SSL) {
1119 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1120 exit(EXIT_FAILURE);
1121 }
1122 fpsba->pchstrp[strap] = value;
1123}
1124
Bill XIEb3e15a22017-09-07 18:34:50 +08001125/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001126static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001127{
1128 if (ifd_version >= IFD_VERSION_2) {
1129 printf("%sting the HAP bit to %s Intel ME...\n",
1130 altmedisable?"Set":"Unset",
1131 altmedisable?"disable":"enable");
1132 if (altmedisable)
1133 fpsba->pchstrp[0] |= (1 << 16);
1134 else
1135 fpsba->pchstrp[0] &= ~(1 << 16);
1136 } else {
1137 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1138 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1139 "and MCH_AltMeDisable to %s Intel ME...\n",
1140 altmedisable?"Set":"Unset",
1141 altmedisable?"disable":"enable");
1142 if (altmedisable) {
1143 /* MCH_MeDisable */
1144 fmsba->data[0] |= 1;
1145 /* MCH_AltMeDisable */
1146 fmsba->data[0] |= (1 << 7);
1147 /* ICH_MeDisable */
1148 fpsba->pchstrp[0] |= 1;
1149 } else {
1150 fmsba->data[0] &= ~1;
1151 fmsba->data[0] &= ~(1 << 7);
1152 fpsba->pchstrp[0] &= ~1;
1153 }
1154 } else {
1155 printf("%sting the AltMeDisable to %s Intel ME...\n",
1156 altmedisable?"Set":"Unset",
1157 altmedisable?"disable":"enable");
1158 if (altmedisable)
1159 fpsba->pchstrp[10] |= (1 << 7);
1160 else
1161 fpsba->pchstrp[10] &= ~(1 << 7);
1162 }
1163 }
1164}
1165
Jacob Garber595d9262019-06-27 17:33:10 -06001166static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001167 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001168{
Bill XIE612ec0e2017-08-30 16:10:27 +08001169 frba_t *frba = find_frba(image, size);
1170 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001171 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001172
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001173 region_t region = get_region(frba, region_type);
1174 if (region.size <= 0xfff) {
1175 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1176 region_name(region_type));
1177 exit(EXIT_FAILURE);
1178 }
1179
Scott Duplichanf2c98372014-12-12 21:03:06 -06001180 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001181 if (region_fd == -1) {
1182 perror("Could not open file");
1183 exit(EXIT_FAILURE);
1184 }
1185 struct stat buf;
1186 if (fstat(region_fd, &buf) == -1) {
1187 perror("Could not stat file");
1188 exit(EXIT_FAILURE);
1189 }
1190 int region_size = buf.st_size;
1191
1192 printf("File %s is %d bytes\n", region_fname, region_size);
1193
1194 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001195 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001196 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1197 " bytes. Not injecting.\n",
1198 region_name(region_type), region.size,
1199 region.size, region_size, region_size);
1200 exit(EXIT_FAILURE);
1201 }
1202
1203 int offset = 0;
1204 if ((region_type == 1) && (region_size < region.size)) {
1205 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1206 " bytes. Padding before injecting.\n",
1207 region_name(region_type), region.size,
1208 region.size, region_size, region_size);
1209 offset = region.size - region_size;
1210 memset(image + region.base, 0xff, offset);
1211 }
1212
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001213 if (size < region.base + offset + region_size) {
1214 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1215 size, region.base + offset + region_size);
1216 exit(EXIT_FAILURE);
1217 }
1218
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001219 if (read(region_fd, image + region.base + offset, region_size)
1220 != region_size) {
1221 perror("Could not read file");
1222 exit(EXIT_FAILURE);
1223 }
1224
1225 close(region_fd);
1226
1227 printf("Adding %s as the %s section of %s\n",
1228 region_fname, region_name(region_type), filename);
1229 write_image(filename, image, size);
1230}
1231
Jacob Garber595d9262019-06-27 17:33:10 -06001232static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001233{
1234 unsigned int y = 1;
1235 if (x == 0)
1236 return 0;
1237 while (y <= x)
1238 y = y << 1;
1239
1240 return y;
1241}
1242
1243/**
1244 * Determine if two memory regions overlap.
1245 *
1246 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001247 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001248 * @return 1 if the two regions overlap
1249 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001250static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001251{
Bill XIEfa5f9942017-09-12 11:22:29 +08001252 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001253 return 0;
1254
Nico Huber844eda02019-01-05 00:06:19 +01001255 /* r1 should be either completely below or completely above r2 */
1256 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001257}
1258
Jacob Garber595d9262019-06-27 17:33:10 -06001259static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001260 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001261{
1262 FILE *romlayout;
1263 char tempstr[256];
1264 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001265 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001266 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001267 region_t current_regions[MAX_REGIONS];
1268 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001269 int new_extent = 0;
1270 char *new_image;
1271
1272 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001273 frba_t *frba = find_frba(image, size);
1274 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001275 exit(EXIT_FAILURE);
1276
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001277 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001278 current_regions[i] = get_region(frba, i);
1279 new_regions[i] = get_region(frba, i);
1280 }
1281
1282 /* read new layout */
1283 romlayout = fopen(layout_fname, "r");
1284
1285 if (!romlayout) {
1286 perror("Could not read layout file.\n");
1287 exit(EXIT_FAILURE);
1288 }
1289
1290 while (!feof(romlayout)) {
1291 char *tstr1, *tstr2;
1292
Patrick Georgi802ad522014-08-09 17:12:23 +02001293 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001294 layout_region_name))
1295 continue;
1296
1297 region_number = region_num(layout_region_name);
1298 if (region_number < 0)
1299 continue;
1300
1301 tstr1 = strtok(tempstr, ":");
1302 tstr2 = strtok(NULL, ":");
1303 if (!tstr1 || !tstr2) {
1304 fprintf(stderr, "Could not parse layout file.\n");
1305 exit(EXIT_FAILURE);
1306 }
1307 new_regions[region_number].base = strtol(tstr1,
1308 (char **)NULL, 16);
1309 new_regions[region_number].limit = strtol(tstr2,
1310 (char **)NULL, 16);
1311 new_regions[region_number].size =
1312 new_regions[region_number].limit -
1313 new_regions[region_number].base + 1;
1314
1315 if (new_regions[region_number].size < 0)
1316 new_regions[region_number].size = 0;
1317 }
1318 fclose(romlayout);
1319
1320 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001321 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001322 if (new_regions[i].size == 0)
1323 continue;
1324
1325 if (new_regions[i].size < current_regions[i].size) {
1326 printf("DANGER: Region %s is shrinking.\n",
1327 region_name(i));
1328 printf(" The region will be truncated to fit.\n");
1329 printf(" This may result in an unusable image.\n");
1330 }
1331
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001332 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001333 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001334 fprintf(stderr, "Regions would overlap.\n");
1335 exit(EXIT_FAILURE);
1336 }
1337 }
1338
1339 /* detect if the image size should grow */
1340 if (new_extent < new_regions[i].limit)
1341 new_extent = new_regions[i].limit;
1342 }
1343
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001344 /* check if the image is actually a Flash Descriptor region */
1345 if (size == new_regions[0].size) {
1346 printf("The image is a single Flash Descriptor:\n");
1347 printf(" Only the descriptor will be modified\n");
1348 new_extent = size;
1349 } else {
1350 new_extent = next_pow2(new_extent - 1);
1351 if (new_extent != size) {
1352 printf("The image has changed in size.\n");
1353 printf("The old image is %d bytes.\n", size);
1354 printf("The new image is %d bytes.\n", new_extent);
1355 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001356 }
1357
1358 /* copy regions to a new image */
1359 new_image = malloc(new_extent);
1360 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001361 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001362 int copy_size = new_regions[i].size;
1363 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001364 const region_t *current = &current_regions[i];
1365 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001366
Bill XIEfa5f9942017-09-12 11:22:29 +08001367 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001368 continue;
1369
Bill XIEfa5f9942017-09-12 11:22:29 +08001370 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001371 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001372 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001373 if (i == REGION_BIOS)
1374 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001375 }
1376
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001377 if ((i == REGION_BIOS) && (new->size < current->size)) {
1378 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001379 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001380 }
1381
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001382 if (size < current->base + offset_current + copy_size) {
1383 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1384 region_name(i));
1385 continue;
1386 };
1387
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001388 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1389 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001390 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1391 offset_current, current->limit, current->size);
1392 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1393 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001394
Bill XIEfa5f9942017-09-12 11:22:29 +08001395 memcpy(new_image + new->base + offset_new,
1396 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001397 copy_size);
1398 }
1399
1400 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001401 frba = find_frba(new_image, new_extent);
1402 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001403 exit(EXIT_FAILURE);
1404
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001405 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001406 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001407 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001408
1409 write_image(filename, new_image, new_extent);
1410 free(new_image);
1411}
1412
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001413static void print_version(void)
1414{
1415 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1416 printf("Copyright (C) 2011 Google Inc.\n\n");
1417 printf
1418 ("This program is free software: you can redistribute it and/or modify\n"
1419 "it under the terms of the GNU General Public License as published by\n"
1420 "the Free Software Foundation, version 2 of the License.\n\n"
1421 "This program is distributed in the hope that it will be useful,\n"
1422 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1423 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001424 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001425}
1426
1427static void print_usage(const char *name)
1428{
1429 printf("usage: %s [-vhdix?] <filename>\n", name);
1430 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001431 " -d | --dump: dump intel firmware descriptor\n"
1432 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1433 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1434 " -x | --extract: extract intel fd modules\n"
1435 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1436 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001437 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001438 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1439 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1440 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1441 " can only be used once per run:\n"
1442 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1443 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1444 " Dual Output Fast Read Support\n"
1445 " -l | --lock Lock firmware descriptor and ME region\n"
1446 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001447 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1448 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001449 " -p | --platform Add platform-specific quirks\n"
1450 " aplk - Apollo Lake\n"
1451 " cnl - Cannon Lake\n"
1452 " glk - Gemini Lake\n"
1453 " sklkbl - Skylake/Kaby Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001454 " -S | --setpchstrap Write a PCH strap\n"
1455 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001456 " -v | --version: print the version\n"
1457 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001458 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1459 "\n");
1460}
1461
1462int main(int argc, char *argv[])
1463{
1464 int opt, option_index = 0;
1465 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001466 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001467 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001468 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001469 char *region_type_string = NULL, *region_fname = NULL;
1470 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001471 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001472 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001473 unsigned int value = 0;
1474 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001475 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001476 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1477
Bill XIEfa5f9942017-09-12 11:22:29 +08001478 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001479 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001480 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001481 {"extract", 0, NULL, 'x'},
1482 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001483 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001484 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001485 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001486 {"density", 1, NULL, 'D'},
1487 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001488 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001489 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001490 {"lock", 0, NULL, 'l'},
1491 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001492 {"version", 0, NULL, 'v'},
1493 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001494 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001495 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001496 {"setpchstrap", 1, NULL, 'S'},
1497 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001498 {0, 0, 0, 0}
1499 };
1500
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001501 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 -07001502 long_options, &option_index)) != EOF) {
1503 switch (opt) {
1504 case 'd':
1505 mode_dump = 1;
1506 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001507 case 'S':
1508 mode_setstrap = 1;
1509 pchstrap = strtoul(optarg, NULL, 0);
1510 break;
1511 case 'V':
1512 value = strtoul(optarg, NULL, 0);
1513 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001514 case 'f':
1515 mode_layout = 1;
1516 layout_fname = strdup(optarg);
1517 if (!layout_fname) {
1518 fprintf(stderr, "No layout file specified\n");
1519 print_usage(argv[0]);
1520 exit(EXIT_FAILURE);
1521 }
1522 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001523 case 'x':
1524 mode_extract = 1;
1525 break;
1526 case 'i':
1527 // separate type and file name
1528 region_type_string = strdup(optarg);
1529 region_fname = strchr(region_type_string, ':');
1530 if (!region_fname) {
1531 print_usage(argv[0]);
1532 exit(EXIT_FAILURE);
1533 }
1534 region_fname[0] = '\0';
1535 region_fname++;
1536 // Descriptor, BIOS, ME, GbE, Platform
1537 // valid type?
1538 if (!strcasecmp("Descriptor", region_type_string))
1539 region_type = 0;
1540 else if (!strcasecmp("BIOS", region_type_string))
1541 region_type = 1;
1542 else if (!strcasecmp("ME", region_type_string))
1543 region_type = 2;
1544 else if (!strcasecmp("GbE", region_type_string))
1545 region_type = 3;
1546 else if (!strcasecmp("Platform", region_type_string))
1547 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001548 else if (!strcasecmp("EC", region_type_string))
1549 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001550 if (region_type == -1) {
1551 fprintf(stderr, "No such region type: '%s'\n\n",
1552 region_type_string);
1553 print_usage(argv[0]);
1554 exit(EXIT_FAILURE);
1555 }
1556 mode_inject = 1;
1557 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001558 case 'n':
1559 mode_newlayout = 1;
1560 layout_fname = strdup(optarg);
1561 if (!layout_fname) {
1562 fprintf(stderr, "No layout file specified\n");
1563 print_usage(argv[0]);
1564 exit(EXIT_FAILURE);
1565 }
1566 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001567 case 'O':
1568 new_filename = strdup(optarg);
1569 if (!new_filename) {
1570 fprintf(stderr, "No output filename specified\n");
1571 print_usage(argv[0]);
1572 exit(EXIT_FAILURE);
1573 }
1574 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001575 case 'D':
1576 mode_density = 1;
1577 new_density = strtoul(optarg, NULL, 0);
1578 switch (new_density) {
1579 case 512:
1580 new_density = COMPONENT_DENSITY_512KB;
1581 break;
1582 case 1:
1583 new_density = COMPONENT_DENSITY_1MB;
1584 break;
1585 case 2:
1586 new_density = COMPONENT_DENSITY_2MB;
1587 break;
1588 case 4:
1589 new_density = COMPONENT_DENSITY_4MB;
1590 break;
1591 case 8:
1592 new_density = COMPONENT_DENSITY_8MB;
1593 break;
1594 case 16:
1595 new_density = COMPONENT_DENSITY_16MB;
1596 break;
1597 case 32:
1598 new_density = COMPONENT_DENSITY_32MB;
1599 break;
1600 case 64:
1601 new_density = COMPONENT_DENSITY_64MB;
1602 break;
1603 case 0:
1604 new_density = COMPONENT_DENSITY_UNUSED;
1605 break;
1606 default:
1607 printf("error: Unknown density\n");
1608 print_usage(argv[0]);
1609 exit(EXIT_FAILURE);
1610 }
1611 break;
1612 case 'C':
1613 selected_chip = strtol(optarg, NULL, 0);
1614 if (selected_chip > 2) {
1615 fprintf(stderr, "error: Invalid chip selection\n");
1616 print_usage(argv[0]);
1617 exit(EXIT_FAILURE);
1618 }
1619 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001620 case 'M':
1621 mode_altmedisable = 1;
1622 altmedisable = strtol(optarg, NULL, 0);
1623 if (altmedisable > 1) {
1624 fprintf(stderr, "error: Illegal value\n");
1625 print_usage(argv[0]);
1626 exit(EXIT_FAILURE);
1627 }
1628 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001629 case 's':
1630 // Parse the requested SPI frequency
1631 inputfreq = strtol(optarg, NULL, 0);
1632 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001633 case 17:
1634 spifreq = SPI_FREQUENCY_17MHZ;
1635 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001636 case 20:
1637 spifreq = SPI_FREQUENCY_20MHZ;
1638 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001639 case 30:
1640 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1641 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001642 case 33:
1643 spifreq = SPI_FREQUENCY_33MHZ;
1644 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001645 case 48:
1646 spifreq = SPI_FREQUENCY_48MHZ;
1647 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001648 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001649 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001650 break;
1651 default:
1652 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1653 inputfreq);
1654 print_usage(argv[0]);
1655 exit(EXIT_FAILURE);
1656 }
1657 mode_spifreq = 1;
1658 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001659 case 'e':
1660 mode_em100 = 1;
1661 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001662 case 'l':
1663 mode_locked = 1;
1664 if (mode_unlocked == 1) {
1665 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1666 exit(EXIT_FAILURE);
1667 }
1668 break;
1669 case 'u':
1670 mode_unlocked = 1;
1671 if (mode_locked == 1) {
1672 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1673 exit(EXIT_FAILURE);
1674 }
1675 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001676 case 'p':
1677 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001678 platform = PLATFORM_APL;
1679 } else if (!strcmp(optarg, "cnl")) {
1680 platform = PLATFORM_CNL;
1681 } else if (!strcmp(optarg, "glk")) {
1682 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301683 } else if (!strcmp(optarg, "icl")) {
1684 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301685 } else if (!strcmp(optarg, "jsl")) {
1686 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001687 } else if (!strcmp(optarg, "sklkbl")) {
1688 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001689 } else if (!strcmp(optarg, "tgl")) {
1690 platform = PLATFORM_TGL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001691 } else {
1692 fprintf(stderr, "Unknown platform: %s\n", optarg);
1693 exit(EXIT_FAILURE);
1694 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001695 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001696 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001697 case 't':
1698 mode_validate = 1;
1699 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001700 case 'v':
1701 print_version();
1702 exit(EXIT_SUCCESS);
1703 break;
1704 case 'h':
1705 case '?':
1706 default:
1707 print_usage(argv[0]);
1708 exit(EXIT_SUCCESS);
1709 break;
1710 }
1711 }
1712
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001713 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001714 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001715 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001716 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001717 print_usage(argv[0]);
1718 exit(EXIT_FAILURE);
1719 }
1720
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001721 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001722 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001723 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001724 fprintf(stderr, "You need to specify a mode.\n\n");
1725 print_usage(argv[0]);
1726 exit(EXIT_FAILURE);
1727 }
1728
1729 if (optind + 1 != argc) {
1730 fprintf(stderr, "You need to specify a file.\n\n");
1731 print_usage(argv[0]);
1732 exit(EXIT_FAILURE);
1733 }
1734
1735 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001736 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001737 if (bios_fd == -1) {
1738 perror("Could not open file");
1739 exit(EXIT_FAILURE);
1740 }
1741 struct stat buf;
1742 if (fstat(bios_fd, &buf) == -1) {
1743 perror("Could not stat file");
1744 exit(EXIT_FAILURE);
1745 }
1746 int size = buf.st_size;
1747
1748 printf("File %s is %d bytes\n", filename, size);
1749
1750 char *image = malloc(size);
1751 if (!image) {
1752 printf("Out of memory.\n");
1753 exit(EXIT_FAILURE);
1754 }
1755
1756 if (read(bios_fd, image, size) != size) {
1757 perror("Could not read file");
1758 exit(EXIT_FAILURE);
1759 }
1760
1761 close(bios_fd);
1762
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001763 // generate new filename
1764 if (new_filename == NULL) {
1765 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1766 if (!new_filename) {
1767 printf("Out of memory.\n");
1768 exit(EXIT_FAILURE);
1769 }
1770 // - 5: leave room for ".new\0"
1771 strcpy(new_filename, filename);
1772 strcat(new_filename, ".new");
1773 }
1774
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001775 check_ifd_version(image, size);
1776
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001777 if (mode_dump)
1778 dump_fd(image, size);
1779
Chris Douglass03ce0142014-02-26 13:30:13 -05001780 if (mode_layout)
1781 dump_layout(image, size, layout_fname);
1782
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001783 if (mode_extract)
1784 write_regions(image, size);
1785
Mathew Kingc7ddc992019-08-08 14:59:25 -06001786 if (mode_validate)
1787 validate_layout(image, size);
1788
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001789 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001790 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001791 region_fname);
1792
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001793 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001794 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001795
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001796 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001797 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001798
Jan Tatjefa317512016-03-11 00:52:07 +01001799 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001800 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001801
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001802 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001803 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001804
Alexander Couzensd12ea112016-09-10 13:33:05 +02001805 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001806 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001807
1808 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001809 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001810
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001811 if (mode_setstrap) {
1812 fpsba_t *fpsba = find_fpsba(image, size);
1813 const fdbar_t *fdb = find_fd(image, size);
1814 set_pchstrap(fpsba, fdb, pchstrap, value);
1815 write_image(new_filename, image, size);
1816 }
1817
Bill XIEb3e15a22017-09-07 18:34:50 +08001818 if (mode_altmedisable) {
1819 fpsba_t *fpsba = find_fpsba(image, size);
1820 fmsba_t *fmsba = find_fmsba(image, size);
1821 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001822 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001823 }
1824
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001825 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001826 free(image);
1827
1828 return 0;
1829}