blob: f64dc7eb8230eb29ac7741807fd7b36408aaec3c [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:
Subrata Banika717e2f2020-07-30 11:22:53 +05301020 case PLATFORM_JSL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001021 /* CPU/BIOS can read descriptor and BIOS. */
1022 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1023 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1024 /* CPU/BIOS can write BIOS. */
1025 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1026 /* ME can read descriptor and ME. */
1027 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1028 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001029 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001030 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1031 if (check_region(frba, REGION_GBE)) {
1032 /* BIOS can read/write GbE. */
1033 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1034 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1035 /* ME can read GbE. */
1036 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1037 /* GbE can read descriptor and read/write GbE.. */
1038 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1039 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1040 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1041 }
1042 if (check_region(frba, REGION_PDR)) {
1043 /* BIOS can read/write PDR. */
1044 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1045 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1046 }
1047 if (check_region(frba, REGION_EC)) {
1048 /* BIOS can read EC. */
1049 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1050 /* EC can read descriptor and read/write EC. */
1051 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1052 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1053 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1054 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001055 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001056 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001057 /* CPU/BIOS can read descriptor and BIOS. */
1058 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1059 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1060 /* CPU/BIOS can write BIOS. */
1061 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1062 /* ME can read descriptor and ME. */
1063 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1064 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1065 /* ME can write ME. */
1066 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1067 if (check_region(frba, REGION_GBE)) {
1068 /* BIOS can read GbE. */
1069 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1070 /* BIOS can write GbE. */
1071 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1072 /* ME can read GbE. */
1073 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1074 /* ME can write GbE. */
1075 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1076 /* GbE can write GbE. */
1077 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1078 /* GbE can read GbE. */
1079 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1080 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001081 break;
1082 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001083
1084 write_image(filename, image, size);
1085}
1086
Bill XIEfa5f9942017-09-12 11:22:29 +08001087static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001088{
Bill XIE612ec0e2017-08-30 16:10:27 +08001089 fmba_t *fmba = find_fmba(image, size);
1090 if (!fmba)
1091 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001092
1093 if (ifd_version >= IFD_VERSION_2) {
1094 /* Access bits for each region are read: 19:8 write: 31:20 */
1095 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1096 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1097 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001098 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001099 } else {
1100 fmba->flmstr1 = 0xffff0000;
1101 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001102 /* Keep chipset specific Requester ID */
1103 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001104 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001105
1106 write_image(filename, image, size);
1107}
1108
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001109static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1110 const unsigned int value)
1111{
1112 if (!fpsba || !fdb) {
1113 fprintf(stderr, "Internal error\n");
1114 exit(EXIT_FAILURE);
1115 }
1116
1117 /* SoC Strap Length, aka PSL, aka ISL */
1118 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1119 if (strap >= SSL) {
1120 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1121 exit(EXIT_FAILURE);
1122 }
1123 fpsba->pchstrp[strap] = value;
1124}
1125
Bill XIEb3e15a22017-09-07 18:34:50 +08001126/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001127static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001128{
1129 if (ifd_version >= IFD_VERSION_2) {
1130 printf("%sting the HAP bit to %s Intel ME...\n",
1131 altmedisable?"Set":"Unset",
1132 altmedisable?"disable":"enable");
1133 if (altmedisable)
1134 fpsba->pchstrp[0] |= (1 << 16);
1135 else
1136 fpsba->pchstrp[0] &= ~(1 << 16);
1137 } else {
1138 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1139 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1140 "and MCH_AltMeDisable to %s Intel ME...\n",
1141 altmedisable?"Set":"Unset",
1142 altmedisable?"disable":"enable");
1143 if (altmedisable) {
1144 /* MCH_MeDisable */
1145 fmsba->data[0] |= 1;
1146 /* MCH_AltMeDisable */
1147 fmsba->data[0] |= (1 << 7);
1148 /* ICH_MeDisable */
1149 fpsba->pchstrp[0] |= 1;
1150 } else {
1151 fmsba->data[0] &= ~1;
1152 fmsba->data[0] &= ~(1 << 7);
1153 fpsba->pchstrp[0] &= ~1;
1154 }
1155 } else {
1156 printf("%sting the AltMeDisable to %s Intel ME...\n",
1157 altmedisable?"Set":"Unset",
1158 altmedisable?"disable":"enable");
1159 if (altmedisable)
1160 fpsba->pchstrp[10] |= (1 << 7);
1161 else
1162 fpsba->pchstrp[10] &= ~(1 << 7);
1163 }
1164 }
1165}
1166
Jacob Garber595d9262019-06-27 17:33:10 -06001167static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001168 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001169{
Bill XIE612ec0e2017-08-30 16:10:27 +08001170 frba_t *frba = find_frba(image, size);
1171 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001172 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001173
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001174 region_t region = get_region(frba, region_type);
1175 if (region.size <= 0xfff) {
1176 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1177 region_name(region_type));
1178 exit(EXIT_FAILURE);
1179 }
1180
Scott Duplichanf2c98372014-12-12 21:03:06 -06001181 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001182 if (region_fd == -1) {
1183 perror("Could not open file");
1184 exit(EXIT_FAILURE);
1185 }
1186 struct stat buf;
1187 if (fstat(region_fd, &buf) == -1) {
1188 perror("Could not stat file");
1189 exit(EXIT_FAILURE);
1190 }
1191 int region_size = buf.st_size;
1192
1193 printf("File %s is %d bytes\n", region_fname, region_size);
1194
1195 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001196 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001197 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1198 " bytes. Not injecting.\n",
1199 region_name(region_type), region.size,
1200 region.size, region_size, region_size);
1201 exit(EXIT_FAILURE);
1202 }
1203
1204 int offset = 0;
1205 if ((region_type == 1) && (region_size < region.size)) {
1206 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1207 " bytes. Padding before injecting.\n",
1208 region_name(region_type), region.size,
1209 region.size, region_size, region_size);
1210 offset = region.size - region_size;
1211 memset(image + region.base, 0xff, offset);
1212 }
1213
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001214 if (size < region.base + offset + region_size) {
1215 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1216 size, region.base + offset + region_size);
1217 exit(EXIT_FAILURE);
1218 }
1219
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001220 if (read(region_fd, image + region.base + offset, region_size)
1221 != region_size) {
1222 perror("Could not read file");
1223 exit(EXIT_FAILURE);
1224 }
1225
1226 close(region_fd);
1227
1228 printf("Adding %s as the %s section of %s\n",
1229 region_fname, region_name(region_type), filename);
1230 write_image(filename, image, size);
1231}
1232
Jacob Garber595d9262019-06-27 17:33:10 -06001233static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001234{
1235 unsigned int y = 1;
1236 if (x == 0)
1237 return 0;
1238 while (y <= x)
1239 y = y << 1;
1240
1241 return y;
1242}
1243
1244/**
1245 * Determine if two memory regions overlap.
1246 *
1247 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001248 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001249 * @return 1 if the two regions overlap
1250 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001251static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001252{
Bill XIEfa5f9942017-09-12 11:22:29 +08001253 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001254 return 0;
1255
Nico Huber844eda02019-01-05 00:06:19 +01001256 /* r1 should be either completely below or completely above r2 */
1257 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001258}
1259
Jacob Garber595d9262019-06-27 17:33:10 -06001260static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001261 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001262{
1263 FILE *romlayout;
1264 char tempstr[256];
1265 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001266 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001267 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001268 region_t current_regions[MAX_REGIONS];
1269 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001270 int new_extent = 0;
1271 char *new_image;
1272
1273 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001274 frba_t *frba = find_frba(image, size);
1275 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001276 exit(EXIT_FAILURE);
1277
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001278 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001279 current_regions[i] = get_region(frba, i);
1280 new_regions[i] = get_region(frba, i);
1281 }
1282
1283 /* read new layout */
1284 romlayout = fopen(layout_fname, "r");
1285
1286 if (!romlayout) {
1287 perror("Could not read layout file.\n");
1288 exit(EXIT_FAILURE);
1289 }
1290
1291 while (!feof(romlayout)) {
1292 char *tstr1, *tstr2;
1293
Patrick Georgi802ad522014-08-09 17:12:23 +02001294 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001295 layout_region_name))
1296 continue;
1297
1298 region_number = region_num(layout_region_name);
1299 if (region_number < 0)
1300 continue;
1301
1302 tstr1 = strtok(tempstr, ":");
1303 tstr2 = strtok(NULL, ":");
1304 if (!tstr1 || !tstr2) {
1305 fprintf(stderr, "Could not parse layout file.\n");
1306 exit(EXIT_FAILURE);
1307 }
1308 new_regions[region_number].base = strtol(tstr1,
1309 (char **)NULL, 16);
1310 new_regions[region_number].limit = strtol(tstr2,
1311 (char **)NULL, 16);
1312 new_regions[region_number].size =
1313 new_regions[region_number].limit -
1314 new_regions[region_number].base + 1;
1315
1316 if (new_regions[region_number].size < 0)
1317 new_regions[region_number].size = 0;
1318 }
1319 fclose(romlayout);
1320
1321 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001322 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001323 if (new_regions[i].size == 0)
1324 continue;
1325
1326 if (new_regions[i].size < current_regions[i].size) {
1327 printf("DANGER: Region %s is shrinking.\n",
1328 region_name(i));
1329 printf(" The region will be truncated to fit.\n");
1330 printf(" This may result in an unusable image.\n");
1331 }
1332
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001333 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001334 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001335 fprintf(stderr, "Regions would overlap.\n");
1336 exit(EXIT_FAILURE);
1337 }
1338 }
1339
1340 /* detect if the image size should grow */
1341 if (new_extent < new_regions[i].limit)
1342 new_extent = new_regions[i].limit;
1343 }
1344
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001345 /* check if the image is actually a Flash Descriptor region */
1346 if (size == new_regions[0].size) {
1347 printf("The image is a single Flash Descriptor:\n");
1348 printf(" Only the descriptor will be modified\n");
1349 new_extent = size;
1350 } else {
1351 new_extent = next_pow2(new_extent - 1);
1352 if (new_extent != size) {
1353 printf("The image has changed in size.\n");
1354 printf("The old image is %d bytes.\n", size);
1355 printf("The new image is %d bytes.\n", new_extent);
1356 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001357 }
1358
1359 /* copy regions to a new image */
1360 new_image = malloc(new_extent);
1361 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001362 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001363 int copy_size = new_regions[i].size;
1364 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001365 const region_t *current = &current_regions[i];
1366 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001367
Bill XIEfa5f9942017-09-12 11:22:29 +08001368 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001369 continue;
1370
Bill XIEfa5f9942017-09-12 11:22:29 +08001371 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001372 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001373 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001374 if (i == REGION_BIOS)
1375 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001376 }
1377
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001378 if ((i == REGION_BIOS) && (new->size < current->size)) {
1379 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001380 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001381 }
1382
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001383 if (size < current->base + offset_current + copy_size) {
1384 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1385 region_name(i));
1386 continue;
1387 };
1388
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001389 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1390 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001391 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1392 offset_current, current->limit, current->size);
1393 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1394 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001395
Bill XIEfa5f9942017-09-12 11:22:29 +08001396 memcpy(new_image + new->base + offset_new,
1397 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001398 copy_size);
1399 }
1400
1401 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001402 frba = find_frba(new_image, new_extent);
1403 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001404 exit(EXIT_FAILURE);
1405
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001406 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001407 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001408 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001409
1410 write_image(filename, new_image, new_extent);
1411 free(new_image);
1412}
1413
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001414static void print_version(void)
1415{
1416 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1417 printf("Copyright (C) 2011 Google Inc.\n\n");
1418 printf
1419 ("This program is free software: you can redistribute it and/or modify\n"
1420 "it under the terms of the GNU General Public License as published by\n"
1421 "the Free Software Foundation, version 2 of the License.\n\n"
1422 "This program is distributed in the hope that it will be useful,\n"
1423 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1424 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001425 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001426}
1427
1428static void print_usage(const char *name)
1429{
1430 printf("usage: %s [-vhdix?] <filename>\n", name);
1431 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001432 " -d | --dump: dump intel firmware descriptor\n"
1433 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1434 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1435 " -x | --extract: extract intel fd modules\n"
1436 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1437 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001438 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001439 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1440 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1441 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1442 " can only be used once per run:\n"
1443 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1444 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1445 " Dual Output Fast Read Support\n"
1446 " -l | --lock Lock firmware descriptor and ME region\n"
1447 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001448 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1449 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001450 " -p | --platform Add platform-specific quirks\n"
1451 " aplk - Apollo Lake\n"
1452 " cnl - Cannon Lake\n"
1453 " glk - Gemini Lake\n"
1454 " sklkbl - Skylake/Kaby Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001455 " -S | --setpchstrap Write a PCH strap\n"
1456 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001457 " -v | --version: print the version\n"
1458 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001459 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1460 "\n");
1461}
1462
1463int main(int argc, char *argv[])
1464{
1465 int opt, option_index = 0;
1466 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001467 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001468 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001469 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001470 char *region_type_string = NULL, *region_fname = NULL;
1471 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001472 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001473 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001474 unsigned int value = 0;
1475 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001476 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001477 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1478
Bill XIEfa5f9942017-09-12 11:22:29 +08001479 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001480 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001481 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001482 {"extract", 0, NULL, 'x'},
1483 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001484 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001485 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001486 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001487 {"density", 1, NULL, 'D'},
1488 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001489 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001490 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001491 {"lock", 0, NULL, 'l'},
1492 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001493 {"version", 0, NULL, 'v'},
1494 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001495 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001496 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001497 {"setpchstrap", 1, NULL, 'S'},
1498 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001499 {0, 0, 0, 0}
1500 };
1501
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001502 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 -07001503 long_options, &option_index)) != EOF) {
1504 switch (opt) {
1505 case 'd':
1506 mode_dump = 1;
1507 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001508 case 'S':
1509 mode_setstrap = 1;
1510 pchstrap = strtoul(optarg, NULL, 0);
1511 break;
1512 case 'V':
1513 value = strtoul(optarg, NULL, 0);
1514 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001515 case 'f':
1516 mode_layout = 1;
1517 layout_fname = strdup(optarg);
1518 if (!layout_fname) {
1519 fprintf(stderr, "No layout file specified\n");
1520 print_usage(argv[0]);
1521 exit(EXIT_FAILURE);
1522 }
1523 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001524 case 'x':
1525 mode_extract = 1;
1526 break;
1527 case 'i':
1528 // separate type and file name
1529 region_type_string = strdup(optarg);
1530 region_fname = strchr(region_type_string, ':');
1531 if (!region_fname) {
1532 print_usage(argv[0]);
1533 exit(EXIT_FAILURE);
1534 }
1535 region_fname[0] = '\0';
1536 region_fname++;
1537 // Descriptor, BIOS, ME, GbE, Platform
1538 // valid type?
1539 if (!strcasecmp("Descriptor", region_type_string))
1540 region_type = 0;
1541 else if (!strcasecmp("BIOS", region_type_string))
1542 region_type = 1;
1543 else if (!strcasecmp("ME", region_type_string))
1544 region_type = 2;
1545 else if (!strcasecmp("GbE", region_type_string))
1546 region_type = 3;
1547 else if (!strcasecmp("Platform", region_type_string))
1548 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001549 else if (!strcasecmp("EC", region_type_string))
1550 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001551 if (region_type == -1) {
1552 fprintf(stderr, "No such region type: '%s'\n\n",
1553 region_type_string);
1554 print_usage(argv[0]);
1555 exit(EXIT_FAILURE);
1556 }
1557 mode_inject = 1;
1558 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001559 case 'n':
1560 mode_newlayout = 1;
1561 layout_fname = strdup(optarg);
1562 if (!layout_fname) {
1563 fprintf(stderr, "No layout file specified\n");
1564 print_usage(argv[0]);
1565 exit(EXIT_FAILURE);
1566 }
1567 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001568 case 'O':
1569 new_filename = strdup(optarg);
1570 if (!new_filename) {
1571 fprintf(stderr, "No output filename specified\n");
1572 print_usage(argv[0]);
1573 exit(EXIT_FAILURE);
1574 }
1575 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001576 case 'D':
1577 mode_density = 1;
1578 new_density = strtoul(optarg, NULL, 0);
1579 switch (new_density) {
1580 case 512:
1581 new_density = COMPONENT_DENSITY_512KB;
1582 break;
1583 case 1:
1584 new_density = COMPONENT_DENSITY_1MB;
1585 break;
1586 case 2:
1587 new_density = COMPONENT_DENSITY_2MB;
1588 break;
1589 case 4:
1590 new_density = COMPONENT_DENSITY_4MB;
1591 break;
1592 case 8:
1593 new_density = COMPONENT_DENSITY_8MB;
1594 break;
1595 case 16:
1596 new_density = COMPONENT_DENSITY_16MB;
1597 break;
1598 case 32:
1599 new_density = COMPONENT_DENSITY_32MB;
1600 break;
1601 case 64:
1602 new_density = COMPONENT_DENSITY_64MB;
1603 break;
1604 case 0:
1605 new_density = COMPONENT_DENSITY_UNUSED;
1606 break;
1607 default:
1608 printf("error: Unknown density\n");
1609 print_usage(argv[0]);
1610 exit(EXIT_FAILURE);
1611 }
1612 break;
1613 case 'C':
1614 selected_chip = strtol(optarg, NULL, 0);
1615 if (selected_chip > 2) {
1616 fprintf(stderr, "error: Invalid chip selection\n");
1617 print_usage(argv[0]);
1618 exit(EXIT_FAILURE);
1619 }
1620 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001621 case 'M':
1622 mode_altmedisable = 1;
1623 altmedisable = strtol(optarg, NULL, 0);
1624 if (altmedisable > 1) {
1625 fprintf(stderr, "error: Illegal value\n");
1626 print_usage(argv[0]);
1627 exit(EXIT_FAILURE);
1628 }
1629 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001630 case 's':
1631 // Parse the requested SPI frequency
1632 inputfreq = strtol(optarg, NULL, 0);
1633 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001634 case 17:
1635 spifreq = SPI_FREQUENCY_17MHZ;
1636 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001637 case 20:
1638 spifreq = SPI_FREQUENCY_20MHZ;
1639 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001640 case 30:
1641 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1642 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001643 case 33:
1644 spifreq = SPI_FREQUENCY_33MHZ;
1645 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001646 case 48:
1647 spifreq = SPI_FREQUENCY_48MHZ;
1648 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001649 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001650 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001651 break;
1652 default:
1653 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1654 inputfreq);
1655 print_usage(argv[0]);
1656 exit(EXIT_FAILURE);
1657 }
1658 mode_spifreq = 1;
1659 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001660 case 'e':
1661 mode_em100 = 1;
1662 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001663 case 'l':
1664 mode_locked = 1;
1665 if (mode_unlocked == 1) {
1666 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1667 exit(EXIT_FAILURE);
1668 }
1669 break;
1670 case 'u':
1671 mode_unlocked = 1;
1672 if (mode_locked == 1) {
1673 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1674 exit(EXIT_FAILURE);
1675 }
1676 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001677 case 'p':
1678 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001679 platform = PLATFORM_APL;
1680 } else if (!strcmp(optarg, "cnl")) {
1681 platform = PLATFORM_CNL;
1682 } else if (!strcmp(optarg, "glk")) {
1683 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301684 } else if (!strcmp(optarg, "icl")) {
1685 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301686 } else if (!strcmp(optarg, "jsl")) {
1687 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001688 } else if (!strcmp(optarg, "sklkbl")) {
1689 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001690 } else if (!strcmp(optarg, "tgl")) {
1691 platform = PLATFORM_TGL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001692 } else {
1693 fprintf(stderr, "Unknown platform: %s\n", optarg);
1694 exit(EXIT_FAILURE);
1695 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001696 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001697 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001698 case 't':
1699 mode_validate = 1;
1700 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001701 case 'v':
1702 print_version();
1703 exit(EXIT_SUCCESS);
1704 break;
1705 case 'h':
1706 case '?':
1707 default:
1708 print_usage(argv[0]);
1709 exit(EXIT_SUCCESS);
1710 break;
1711 }
1712 }
1713
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001714 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001715 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001716 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001717 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001718 print_usage(argv[0]);
1719 exit(EXIT_FAILURE);
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_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001724 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001725 fprintf(stderr, "You need to specify a mode.\n\n");
1726 print_usage(argv[0]);
1727 exit(EXIT_FAILURE);
1728 }
1729
1730 if (optind + 1 != argc) {
1731 fprintf(stderr, "You need to specify a file.\n\n");
1732 print_usage(argv[0]);
1733 exit(EXIT_FAILURE);
1734 }
1735
1736 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001737 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001738 if (bios_fd == -1) {
1739 perror("Could not open file");
1740 exit(EXIT_FAILURE);
1741 }
1742 struct stat buf;
1743 if (fstat(bios_fd, &buf) == -1) {
1744 perror("Could not stat file");
1745 exit(EXIT_FAILURE);
1746 }
1747 int size = buf.st_size;
1748
1749 printf("File %s is %d bytes\n", filename, size);
1750
1751 char *image = malloc(size);
1752 if (!image) {
1753 printf("Out of memory.\n");
1754 exit(EXIT_FAILURE);
1755 }
1756
1757 if (read(bios_fd, image, size) != size) {
1758 perror("Could not read file");
1759 exit(EXIT_FAILURE);
1760 }
1761
1762 close(bios_fd);
1763
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001764 // generate new filename
1765 if (new_filename == NULL) {
1766 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1767 if (!new_filename) {
1768 printf("Out of memory.\n");
1769 exit(EXIT_FAILURE);
1770 }
1771 // - 5: leave room for ".new\0"
1772 strcpy(new_filename, filename);
1773 strcat(new_filename, ".new");
1774 }
1775
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001776 check_ifd_version(image, size);
1777
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001778 if (mode_dump)
1779 dump_fd(image, size);
1780
Chris Douglass03ce0142014-02-26 13:30:13 -05001781 if (mode_layout)
1782 dump_layout(image, size, layout_fname);
1783
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001784 if (mode_extract)
1785 write_regions(image, size);
1786
Mathew Kingc7ddc992019-08-08 14:59:25 -06001787 if (mode_validate)
1788 validate_layout(image, size);
1789
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001790 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001791 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001792 region_fname);
1793
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001794 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001795 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001796
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001797 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001798 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001799
Jan Tatjefa317512016-03-11 00:52:07 +01001800 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001801 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001802
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001803 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001804 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001805
Alexander Couzensd12ea112016-09-10 13:33:05 +02001806 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001807 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001808
1809 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001810 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001811
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001812 if (mode_setstrap) {
1813 fpsba_t *fpsba = find_fpsba(image, size);
1814 const fdbar_t *fdb = find_fd(image, size);
1815 set_pchstrap(fpsba, fdb, pchstrap, value);
1816 write_image(new_filename, image, size);
1817 }
1818
Bill XIEb3e15a22017-09-07 18:34:50 +08001819 if (mode_altmedisable) {
1820 fpsba_t *fpsba = find_fpsba(image, size);
1821 fmsba_t *fmsba = find_fmsba(image, size);
1822 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001823 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001824 }
1825
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001826 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001827 free(image);
1828
1829 return 0;
1830}