blob: 68e5b7bbd53bcb0f5c501dba41df46bad623432b [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003
4#include <unistd.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <getopt.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080012#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060013#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014#include "ifdtool.h"
15
Scott Duplichanf2c98372014-12-12 21:03:06 -060016#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
Bill XIE612ec0e2017-08-30 16:10:27 +080020/**
21 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
22 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
23 * @param base: base address represented with char* type.
24 * @param limit: upper limit of the legal address.
25 *
26 */
27#define PTR_IN_RANGE(ptr, base, limit) \
28 ((const char *)(ptr) >= (base) && \
29 (const char *)&(ptr)[1] <= (base) + (limit))
30
Duncan Laurie1f7fd722015-06-22 11:14:48 -070031static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080032static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080033static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010034static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070035static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050036
Duncan Laurie1f7fd722015-06-22 11:14:48 -070037static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060038 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
39 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
40 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
41 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
42 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
43 { "Reserved", "res1", "flashregion_5_reserved.bin", NULL },
44 { "Reserved", "res2", "flashregion_6_reserved.bin", NULL },
45 { "Reserved", "res3", "flashregion_7_reserved.bin", NULL },
46 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Chris Douglass03ce0142014-02-26 13:30:13 -050047};
48
Bill XIEb3e15a22017-09-07 18:34:50 +080049/* port from flashrom */
50static const char *const ich_chipset_names[] = {
51 "Unknown ICH",
52 "ICH",
53 "ICH2345",
54 "ICH6",
55 "SCH U",
56 "Atom E6xx",
57 "Atom S1220 S1240 S1260",
58 "ICH7",
59 "ICH8",
60 "ICH9",
61 "ICH10",
62 "5 series Ibex Peak",
63 "6 series Cougar Point",
64 "7 series Panther Point",
65 "8 series Lynx Point",
66 "Baytrail",
67 "8 series Lynx Point LP",
68 "8 series Wellsburg",
69 "9 series Wildcat Point",
70 "9 series Wildcat Point LP",
71 "100 series Sunrise Point",
72 "C620 series Lewisburg",
73 NULL
74};
75
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070076static fdbar_t *find_fd(char *image, int size)
77{
78 int i, found = 0;
79
80 /* Scan for FD signature */
81 for (i = 0; i < (size - 4); i += 4) {
82 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
83 found = 1;
84 break; // signature found.
85 }
86 }
87
88 if (!found) {
89 printf("No Flash Descriptor found in this image\n");
90 return NULL;
91 }
92
Bill XIE612ec0e2017-08-30 16:10:27 +080093 fdbar_t *fdb = (fdbar_t *) (image + i);
94 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
95}
96
Stefan Tauner0d226142018-08-05 18:56:53 +020097static char *find_flumap(char *image, int size)
98{
99 /* The upper map is located in the word before the 256B-long OEM section
100 * at the end of the 4kB-long flash descriptor. In the official
101 * documentation this is defined as FDBAR + 0xEFC. However, starting
102 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
103 * has moved 16 bytes back to offset 0x10 of the image. Although
104 * official documentation still maintains the offset relative to FDBAR
105 * this is wrong and a simple fixed offset from the start of the image
106 * works.
107 */
108 char *flumap = image + 4096 - 256 - 4;
109 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
110}
111
Bill XIE612ec0e2017-08-30 16:10:27 +0800112static fcba_t *find_fcba(char *image, int size)
113{
114 fdbar_t *fdb = find_fd(image, size);
115 if (!fdb)
116 return NULL;
117 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
118 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
119
120}
121
122static fmba_t *find_fmba(char *image, int size)
123{
124 fdbar_t *fdb = find_fd(image, size);
125 if (!fdb)
126 return NULL;
127 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
128 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
129}
130
131static frba_t *find_frba(char *image, int size)
132{
133 fdbar_t *fdb = find_fd(image, size);
134 if (!fdb)
135 return NULL;
136 frba_t *frba =
137 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
138 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
139}
140
141static fpsba_t *find_fpsba(char *image, int size)
142{
143 fdbar_t *fdb = find_fd(image, size);
144 if (!fdb)
145 return NULL;
146 fpsba_t *fpsba =
147 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200148
149 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
150 if ((((char *)fpsba) + SSL) >= (image + size))
151 return NULL;
152 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800153}
154
155static fmsba_t *find_fmsba(char *image, int size)
156{
157 fdbar_t *fdb = find_fd(image, size);
158 if (!fdb)
159 return NULL;
160 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
161 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700162}
163
Bill XIEb3e15a22017-09-07 18:34:50 +0800164/* port from flashrom */
165static enum ich_chipset guess_ich_chipset(const fdbar_t *fdb)
166{
167 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
168 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
169 uint32_t isl = (fdb->flmap1 >> 24);
170 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
171
172 if (iccriba == 0x00) {
173 if (msl == 0 && isl <= 2)
174 return CHIPSET_ICH8;
175 else if (isl <= 2)
176 return CHIPSET_ICH9;
177 else if (isl <= 10)
178 return CHIPSET_ICH10;
179 else if (isl <= 16)
180 return CHIPSET_5_SERIES_IBEX_PEAK;
181 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
182 return CHIPSET_5_SERIES_IBEX_PEAK;
183 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
184 if (msl == 0 && isl <= 17)
185 return CHIPSET_BAYTRAIL;
186 else if (msl <= 1 && isl <= 18)
187 return CHIPSET_6_SERIES_COUGAR_POINT;
188 else if (msl <= 1 && isl <= 21)
189 return CHIPSET_8_SERIES_LYNX_POINT;
190 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
191 return CHIPSET_9_SERIES_WILDCAT_POINT;
192 } else if (nm == 6) {
193 return CHIPSET_C620_SERIES_LEWISBURG;
194 } else {
195 return CHIPSET_100_SERIES_SUNRISE_POINT;
196 }
197}
198
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700199/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700200 * Some newer platforms have re-defined the FCBA field that was used to
201 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
202 * have the required FCBA field, but are IFD v2 and return true if current
203 * platform is one of them.
204 */
205static int is_platform_ifd_2(void)
206{
207 static const int ifd_2_platforms[] = {
208 PLATFORM_GLK,
209 PLATFORM_CNL,
Aamir Bohra1018be22018-06-29 15:08:50 +0530210 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700211 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530212 PLATFORM_JSL,
Subrata Banik46f80732020-03-14 15:01:42 +0530213 PLATFORM_ADL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700214 };
215 unsigned int i;
216
217 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
218 if (platform == ifd_2_platforms[i])
219 return 1;
220 }
221
222 return 0;
223}
224
225/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700226 * There is no version field in the descriptor so to determine
227 * if this is a new descriptor format we check the hardcoded SPI
228 * read frequency to see if it is fixed at 20MHz or 17MHz.
229 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700230static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700231{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700232 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800233 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800234 const fdbar_t *fdb = find_fd(image, size);
Jacob Garber9bb04612019-05-08 13:40:45 -0600235 if (!fcba || !fdb)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700236 exit(EXIT_FAILURE);
237
Bill XIEb3e15a22017-09-07 18:34:50 +0800238 chipset = guess_ich_chipset(fdb);
239 /* TODO: port ifd_version and max_regions
240 * against guess_ich_chipset()
241 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700242 read_freq = (fcba->flcomp >> 17) & 7;
243
244 switch (read_freq) {
245 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700246 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700247 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700248 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700249 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700250 default:
251 fprintf(stderr, "Unknown descriptor version: %d\n",
252 read_freq);
253 exit(EXIT_FAILURE);
254 }
255}
256
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700257static void check_ifd_version(char *image, int size)
258{
259 if (is_platform_ifd_2())
260 ifd_version = IFD_VERSION_2;
261 else
262 ifd_version = get_ifd_version_from_fcba(image, size);
263
264 if (ifd_version == IFD_VERSION_1)
265 max_regions = MAX_REGIONS_OLD;
266 else
267 max_regions = MAX_REGIONS;
268}
269
Bill XIEfa5f9942017-09-12 11:22:29 +0800270static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700271{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500272 int base_mask;
273 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700274 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700275 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500276
277 if (ifd_version >= IFD_VERSION_2)
278 base_mask = 0x7fff;
279 else
280 base_mask = 0xfff;
281
282 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700283
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400284 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800285 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700286 exit (EXIT_FAILURE);
287 }
288
Bill XIE4651d452017-09-12 11:54:48 +0800289 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700290 region.base = (flreg & base_mask) << 12;
291 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700292 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500293
Chris Douglass03ce0142014-02-26 13:30:13 -0500294 if (region.size < 0)
295 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700296
297 return region;
298}
299
Bill XIEfa5f9942017-09-12 11:22:29 +0800300static void set_region(frba_t *frba, unsigned int region_type,
301 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500302{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400303 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800304 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500305 exit (EXIT_FAILURE);
306 }
Bill XIE4651d452017-09-12 11:54:48 +0800307
308 frba->flreg[region_type] =
309 (((region->limit >> 12) & 0x7fff) << 16) |
310 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500311}
312
Bill XIEfa5f9942017-09-12 11:22:29 +0800313static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700314{
Bill XIEfa5f9942017-09-12 11:22:29 +0800315 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316 fprintf(stderr, "Invalid region type.\n");
317 exit (EXIT_FAILURE);
318 }
319
Chris Douglass03ce0142014-02-26 13:30:13 -0500320 return region_names[region_type].pretty;
321}
322
Bill XIEfa5f9942017-09-12 11:22:29 +0800323static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500324{
Bill XIEfa5f9942017-09-12 11:22:29 +0800325 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500326 fprintf(stderr, "Invalid region type.\n");
327 exit (EXIT_FAILURE);
328 }
329
330 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700331}
332
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500333static int region_num(const char *name)
334{
Bill XIEfa5f9942017-09-12 11:22:29 +0800335 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500336
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200337 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500338 if (strcasecmp(name, region_names[i].pretty) == 0)
339 return i;
340 if (strcasecmp(name, region_names[i].terse) == 0)
341 return i;
342 }
343
344 return -1;
345}
346
Bill XIEfa5f9942017-09-12 11:22:29 +0800347static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700348{
Bill XIEfa5f9942017-09-12 11:22:29 +0800349 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700350 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700351 exit (EXIT_FAILURE);
352 }
353
Bill XIE1bf65062017-09-12 11:31:37 +0800354 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355}
356
Bill XIEfa5f9942017-09-12 11:22:29 +0800357static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700358{
359 region_t region = get_region(frba, num);
360 printf(" Flash Region %d (%s): %08x - %08x %s\n",
361 num, region_name(num), region.base, region.limit,
362 region.size < 1 ? "(unused)" : "");
363}
364
Bill XIEfa5f9942017-09-12 11:22:29 +0800365static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
366 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500367{
368 region_t region = get_region(frba, num);
369 snprintf(buf, bufsize, "%08x:%08x %s\n",
370 region.base, region.limit, region_name_short(num));
371}
372
Bill XIEfa5f9942017-09-12 11:22:29 +0800373static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700374{
Bill XIE4651d452017-09-12 11:54:48 +0800375 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530376 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700377 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800378 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530379 region = get_region(frba, i);
380 /* Skip unused & reserved Flash Region */
381 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
382 continue;
383
Bill XIE4651d452017-09-12 11:54:48 +0800384 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
385 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700386 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700387}
388
Bill XIEfa5f9942017-09-12 11:22:29 +0800389static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500390{
391 char buf[LAYOUT_LINELEN];
392 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800393 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500394
395 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
396 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
397 if (layout_fd == -1) {
398 perror("Could not open file");
399 exit(EXIT_FAILURE);
400 }
401
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200402 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200403 region_t region = get_region(frba, i);
404 /* is region invalid? */
405 if (region.size < 1)
406 continue;
407
Chris Douglass03ce0142014-02-26 13:30:13 -0500408 dump_region_layout(buf, bufsize, i, frba);
409 if (write(layout_fd, buf, strlen(buf)) < 0) {
410 perror("Could not write to file");
411 exit(EXIT_FAILURE);
412 }
413 }
414 close(layout_fd);
415 printf("Wrote layout to %s\n", layout_fname);
416}
417
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700418static void decode_spi_frequency(unsigned int freq)
419{
420 switch (freq) {
421 case SPI_FREQUENCY_20MHZ:
422 printf("20MHz");
423 break;
424 case SPI_FREQUENCY_33MHZ:
425 printf("33MHz");
426 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700427 case SPI_FREQUENCY_48MHZ:
428 printf("48MHz");
429 break;
430 case SPI_FREQUENCY_50MHZ_30MHZ:
431 switch (ifd_version) {
432 case IFD_VERSION_1:
433 printf("50MHz");
434 break;
435 case IFD_VERSION_2:
436 printf("30MHz");
437 break;
438 }
439 break;
440 case SPI_FREQUENCY_17MHZ:
441 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700442 break;
443 default:
444 printf("unknown<%x>MHz", freq);
445 }
446}
447
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700448static void decode_component_density(unsigned int density)
449{
450 switch (density) {
451 case COMPONENT_DENSITY_512KB:
452 printf("512KB");
453 break;
454 case COMPONENT_DENSITY_1MB:
455 printf("1MB");
456 break;
457 case COMPONENT_DENSITY_2MB:
458 printf("2MB");
459 break;
460 case COMPONENT_DENSITY_4MB:
461 printf("4MB");
462 break;
463 case COMPONENT_DENSITY_8MB:
464 printf("8MB");
465 break;
466 case COMPONENT_DENSITY_16MB:
467 printf("16MB");
468 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700469 case COMPONENT_DENSITY_32MB:
470 printf("32MB");
471 break;
472 case COMPONENT_DENSITY_64MB:
473 printf("64MB");
474 break;
475 case COMPONENT_DENSITY_UNUSED:
476 printf("UNUSED");
477 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700478 default:
479 printf("unknown<%x>MB", density);
480 }
481}
482
Bill XIEfa5f9942017-09-12 11:22:29 +0800483static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700484{
485 printf("\nFound Component Section\n");
486 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700487 printf(" Dual Output Fast Read Support: %ssupported\n",
488 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700489 printf(" Read ID/Read Status Clock Frequency: ");
490 decode_spi_frequency((fcba->flcomp >> 27) & 7);
491 printf("\n Write/Erase Clock Frequency: ");
492 decode_spi_frequency((fcba->flcomp >> 24) & 7);
493 printf("\n Fast Read Clock Frequency: ");
494 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700495 printf("\n Fast Read Support: %ssupported",
496 (fcba->flcomp & (1 << 20))?"":"not ");
497 printf("\n Read Clock Frequency: ");
498 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700499
500 switch (ifd_version) {
501 case IFD_VERSION_1:
502 printf("\n Component 2 Density: ");
503 decode_component_density((fcba->flcomp >> 3) & 7);
504 printf("\n Component 1 Density: ");
505 decode_component_density(fcba->flcomp & 7);
506 break;
507 case IFD_VERSION_2:
508 printf("\n Component 2 Density: ");
509 decode_component_density((fcba->flcomp >> 4) & 0xf);
510 printf("\n Component 1 Density: ");
511 decode_component_density(fcba->flcomp & 0xf);
512 break;
513 }
514
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700515 printf("\n");
516 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700517 printf(" Invalid Instruction 3: 0x%02x\n",
518 (fcba->flill >> 24) & 0xff);
519 printf(" Invalid Instruction 2: 0x%02x\n",
520 (fcba->flill >> 16) & 0xff);
521 printf(" Invalid Instruction 1: 0x%02x\n",
522 (fcba->flill >> 8) & 0xff);
523 printf(" Invalid Instruction 0: 0x%02x\n",
524 fcba->flill & 0xff);
525 printf("FLPB 0x%08x\n", fcba->flpb);
526 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
527 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700528}
529
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200530static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700531{
Bill XIE4651d452017-09-12 11:54:48 +0800532 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200533 /* SoC Strap Length, aka PSL, aka ISL */
534 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
535
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700536 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200537 for (i = 0; i < SSL; i++)
538 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800539
540 if (ifd_version >= IFD_VERSION_2) {
541 printf("HAP bit is %sset\n",
542 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
543 } else if (chipset >= CHIPSET_ICH8
544 && chipset <= CHIPSET_ICH10) {
545 printf("ICH_MeDisable bit is %sset\n",
546 fpsba->pchstrp[0] & 1 ? "" : "not ");
547 } else {
548 printf("AltMeDisable bit is %sset\n",
549 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
550 }
551
Bill XIE4651d452017-09-12 11:54:48 +0800552 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700553}
554
555static void decode_flmstr(uint32_t flmstr)
556{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700557 int wr_shift, rd_shift;
558 if (ifd_version >= IFD_VERSION_2) {
559 wr_shift = FLMSTR_WR_SHIFT_V2;
560 rd_shift = FLMSTR_RD_SHIFT_V2;
561 } else {
562 wr_shift = FLMSTR_WR_SHIFT_V1;
563 rd_shift = FLMSTR_RD_SHIFT_V1;
564 }
565
566 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700567 if (ifd_version >= IFD_VERSION_2)
568 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700569 (flmstr & (1 << (wr_shift + 8))) ?
570 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700571 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700572 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700573 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700574 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700575 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700576 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700577 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700578 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700579 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700580 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700581
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700582 if (ifd_version >= IFD_VERSION_2)
583 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700584 (flmstr & (1 << (rd_shift + 8))) ?
585 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700586 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700587 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700588 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700589 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700590 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700591 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700592 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700593 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700594 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700595 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700596
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700597 /* Requestor ID doesn't exist for ifd 2 */
598 if (ifd_version < IFD_VERSION_2)
599 printf(" Requester ID: 0x%04x\n\n",
600 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700601}
602
Bill XIEfa5f9942017-09-12 11:22:29 +0800603static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700604{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700605 printf("Found Master Section\n");
606 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
607 decode_flmstr(fmba->flmstr1);
608 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
609 decode_flmstr(fmba->flmstr2);
610 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
611 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700612 if (ifd_version >= IFD_VERSION_2) {
613 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
614 decode_flmstr(fmba->flmstr5);
615 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700616}
617
Bill XIEfa5f9942017-09-12 11:22:29 +0800618static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700619{
Bill XIE612ec0e2017-08-30 16:10:27 +0800620 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700621 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800622 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
623 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800624
625 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
626 printf("MCH_MeDisable bit is %sset\n",
627 fmsba->data[0] & 1 ? "" : "not ");
628 printf("MCH_AltMeDisable bit is %sset\n",
629 fmsba->data[0] & (1 << 7) ? "" : "not ");
630 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700631}
632
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700633static void dump_jid(uint32_t jid)
634{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100635 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700636 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100637 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200638 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100639 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200640 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700641}
642
643static void dump_vscc(uint32_t vscc)
644{
645 printf(" Lower Erase Opcode: 0x%02x\n",
646 vscc >> 24);
647 printf(" Lower Write Enable on Write Status: 0x%02x\n",
648 vscc & (1 << 20) ? 0x06 : 0x50);
649 printf(" Lower Write Status Required: %s\n",
650 vscc & (1 << 19) ? "Yes" : "No");
651 printf(" Lower Write Granularity: %d bytes\n",
652 vscc & (1 << 18) ? 64 : 1);
653 printf(" Lower Block / Sector Erase Size: ");
654 switch ((vscc >> 16) & 0x3) {
655 case 0:
656 printf("256 Byte\n");
657 break;
658 case 1:
659 printf("4KB\n");
660 break;
661 case 2:
662 printf("8KB\n");
663 break;
664 case 3:
665 printf("64KB\n");
666 break;
667 }
668
669 printf(" Upper Erase Opcode: 0x%02x\n",
670 (vscc >> 8) & 0xff);
671 printf(" Upper Write Enable on Write Status: 0x%02x\n",
672 vscc & (1 << 4) ? 0x06 : 0x50);
673 printf(" Upper Write Status Required: %s\n",
674 vscc & (1 << 3) ? "Yes" : "No");
675 printf(" Upper Write Granularity: %d bytes\n",
676 vscc & (1 << 2) ? 64 : 1);
677 printf(" Upper Block / Sector Erase Size: ");
678 switch (vscc & 0x3) {
679 case 0:
680 printf("256 Byte\n");
681 break;
682 case 1:
683 printf("4KB\n");
684 break;
685 case 2:
686 printf("8KB\n");
687 break;
688 case 3:
689 printf("64KB\n");
690 break;
691 }
692}
693
Bill XIEfa5f9942017-09-12 11:22:29 +0800694static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700695{
696 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200697 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
698 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700699
700 printf("ME VSCC table:\n");
701 for (i = 0; i < num; i++) {
702 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
703 dump_jid(vtba->entry[i].jid);
704 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
705 dump_vscc(vtba->entry[i].vscc);
706 }
707 printf("\n");
708}
709
Bill XIEfa5f9942017-09-12 11:22:29 +0800710static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700711{
712 int i, j;
713 printf("OEM Section:\n");
714 for (i = 0; i < 4; i++) {
715 printf("%02x:", i << 4);
716 for (j = 0; j < 16; j++)
717 printf(" %02x", oem[(i<<4)+j]);
718 printf ("\n");
719 }
720 printf ("\n");
721}
722
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700723static void dump_fd(char *image, int size)
724{
Bill XIE612ec0e2017-08-30 16:10:27 +0800725 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700726 if (!fdb)
727 exit(EXIT_FAILURE);
728
Bill XIEb3e15a22017-09-07 18:34:50 +0800729 printf("ICH Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700730 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
731 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
732 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
733 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
734 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
735
736 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
737 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
738 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
739 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
740 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
741
742 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
743 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
744 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
745
Stefan Tauner0d226142018-08-05 18:56:53 +0200746 char *flumap = find_flumap(image, size);
747 uint32_t flumap1 = *(uint32_t *)flumap;
748 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700749 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200750 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700751 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200752 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700753 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200754 (image + ((flumap1 & 0xff) << 4)),
755 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800756 dump_oem((const uint8_t *)image + 0xf00);
757
758 const frba_t *frba = find_frba(image, size);
759 const fcba_t *fcba = find_fcba(image, size);
760 const fpsba_t *fpsba = find_fpsba(image, size);
761 const fmba_t *fmba = find_fmba(image, size);
762 const fmsba_t *fmsba = find_fmsba(image, size);
763
764 if (frba && fcba && fpsba && fmba && fmsba) {
765 dump_frba(frba);
766 dump_fcba(fcba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200767 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800768 dump_fmba(fmba);
769 dump_fmsba(fmsba);
770 } else {
771 printf("FD is corrupted!\n");
772 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700773}
774
Bill XIEfa5f9942017-09-12 11:22:29 +0800775static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500776{
Bill XIE612ec0e2017-08-30 16:10:27 +0800777 const frba_t *frba = find_frba(image, size);
778 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500779 exit(EXIT_FAILURE);
780
Bill XIE612ec0e2017-08-30 16:10:27 +0800781 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500782}
783
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700784static void write_regions(char *image, int size)
785{
Bill XIEfa5f9942017-09-12 11:22:29 +0800786 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800787 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700788
Bill XIE612ec0e2017-08-30 16:10:27 +0800789 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700790 exit(EXIT_FAILURE);
791
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700792 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700793 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700794 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700795 if (region.size > 0) {
796 int region_fd;
797 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600798 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700799 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200800 if (region_fd < 0) {
801 perror("Error while trying to open file");
802 exit(EXIT_FAILURE);
803 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700804 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700805 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700806 close(region_fd);
807 }
808 }
809}
810
Mathew Kingc7ddc992019-08-08 14:59:25 -0600811static void validate_layout(char *image, int size)
812{
813 uint i, errors = 0;
814 struct fmap *fmap;
815 long int fmap_loc = fmap_find((uint8_t *)image, size);
816 const frba_t *frba = find_frba(image, size);
817
818 if (fmap_loc < 0 || !frba)
819 exit(EXIT_FAILURE);
820
821 fmap = (struct fmap *)(image + fmap_loc);
822
823 for (i = 0; i < max_regions; i++) {
824 if (region_names[i].fmapname == NULL)
825 continue;
826
827 region_t region = get_region(frba, i);
828
829 if (region.size == 0)
830 continue;
831
832 const struct fmap_area *area =
833 fmap_find_area(fmap, region_names[i].fmapname);
834
835 if (!area)
836 continue;
837
838 if ((uint)region.base != area->offset ||
839 (uint)region.size != area->size) {
840 printf("Region mismatch between %s and %s\n",
841 region_names[i].terse, area->name);
842 printf(" Descriptor region %s:\n", region_names[i].terse);
843 printf(" offset: 0x%08x\n", region.base);
844 printf(" length: 0x%08x\n", region.size);
845 printf(" FMAP area %s:\n", area->name);
846 printf(" offset: 0x%08x\n", area->offset);
847 printf(" length: 0x%08x\n", area->size);
848 errors++;
849 }
850 }
851
852 if (errors > 0)
853 exit(EXIT_FAILURE);
854}
855
Bill XIEfa5f9942017-09-12 11:22:29 +0800856static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700857{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700858 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100859 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700860
861 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100862 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600863 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700864 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200865 if (new_fd < 0) {
866 perror("Error while trying to open file");
867 exit(EXIT_FAILURE);
868 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700869 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700870 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700871 close(new_fd);
872}
873
Bill XIEfa5f9942017-09-12 11:22:29 +0800874static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700875 enum spi_frequency freq)
876{
Bill XIE612ec0e2017-08-30 16:10:27 +0800877 fcba_t *fcba = find_fcba(image, size);
878 if (!fcba)
879 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700880
881 /* clear bits 21-29 */
882 fcba->flcomp &= ~0x3fe00000;
883 /* Read ID and Read Status Clock Frequency */
884 fcba->flcomp |= freq << 27;
885 /* Write and Erase Clock Frequency */
886 fcba->flcomp |= freq << 24;
887 /* Fast Read Clock Frequency */
888 fcba->flcomp |= freq << 21;
889
890 write_image(filename, image, size);
891}
892
Bill XIEfa5f9942017-09-12 11:22:29 +0800893static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700894{
Bill XIE612ec0e2017-08-30 16:10:27 +0800895 fcba_t *fcba = find_fcba(image, size);
896 if (!fcba)
897 exit(EXIT_FAILURE);
898
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700899 int freq;
900
901 switch (ifd_version) {
902 case IFD_VERSION_1:
903 freq = SPI_FREQUENCY_20MHZ;
904 break;
905 case IFD_VERSION_2:
906 freq = SPI_FREQUENCY_17MHZ;
907 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700908 default:
909 freq = SPI_FREQUENCY_17MHZ;
910 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700911 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700912
913 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700914 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700915}
916
Bill XIEfa5f9942017-09-12 11:22:29 +0800917static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100918 unsigned int density)
919{
Bill XIE612ec0e2017-08-30 16:10:27 +0800920 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200921 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800922 if (!fcba)
923 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100924
925 printf("Setting chip density to ");
926 decode_component_density(density);
927 printf("\n");
928
929 switch (ifd_version) {
930 case IFD_VERSION_1:
931 /* fail if selected density is not supported by this version */
932 if ( (density == COMPONENT_DENSITY_32MB) ||
933 (density == COMPONENT_DENSITY_64MB) ||
934 (density == COMPONENT_DENSITY_UNUSED) ) {
935 printf("error: Selected density not supported in IFD version 1.\n");
936 exit(EXIT_FAILURE);
937 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200938 mask = 0x7;
939 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100940 break;
941 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200942 mask = 0xf;
943 chip2_offset = 4;
944 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100945 default:
946 printf("error: Unknown IFD version\n");
947 exit(EXIT_FAILURE);
948 break;
949 }
950
951 /* clear chip density for corresponding chip */
952 switch (selected_chip) {
953 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200954 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100955 break;
956 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200957 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100958 break;
959 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200960 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +0100961 break;
962 }
963
964 /* set the new density */
965 if (selected_chip == 1 || selected_chip == 0)
966 fcba->flcomp |= (density); /* first chip */
967 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200968 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +0100969
970 write_image(filename, image, size);
971}
972
Duncan Laurie7775d672019-06-06 13:39:26 -0700973static int check_region(const frba_t *frba, unsigned int region_type)
974{
975 region_t region;
976
977 if (!frba)
978 return 0;
979
980 region = get_region(frba, region_type);
981 return !!((region.base < region.limit) && (region.size > 0));
982}
983
Bill XIEfa5f9942017-09-12 11:22:29 +0800984static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700985{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700986 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800987 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -0700988 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800989 if (!fmba)
990 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700991
992 if (ifd_version >= IFD_VERSION_2) {
993 wr_shift = FLMSTR_WR_SHIFT_V2;
994 rd_shift = FLMSTR_RD_SHIFT_V2;
995
996 /* Clear non-reserved bits */
997 fmba->flmstr1 &= 0xff;
998 fmba->flmstr2 &= 0xff;
999 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001000 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001001 } else {
1002 wr_shift = FLMSTR_WR_SHIFT_V1;
1003 rd_shift = FLMSTR_RD_SHIFT_V1;
1004
1005 fmba->flmstr1 = 0;
1006 fmba->flmstr2 = 0;
1007 /* Requestor ID */
1008 fmba->flmstr3 = 0x118;
1009 }
1010
Andrey Petrov96ecb772016-10-31 19:31:54 -07001011 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001012 case PLATFORM_APL:
1013 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001014 /* CPU/BIOS can read descriptor and BIOS */
1015 fmba->flmstr1 |= 0x3 << rd_shift;
1016 /* CPU/BIOS can write BIOS */
1017 fmba->flmstr1 |= 0x2 << wr_shift;
1018 /* TXE can read descriptor, BIOS and Device Expansion */
1019 fmba->flmstr2 |= 0x23 << rd_shift;
1020 /* TXE can only write Device Expansion */
1021 fmba->flmstr2 |= 0x20 << wr_shift;
1022 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001023 case PLATFORM_CNL:
1024 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001025 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001026 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301027 case PLATFORM_JSL:
Subrata Banik46f80732020-03-14 15:01:42 +05301028 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001029 /* CPU/BIOS can read descriptor and BIOS. */
1030 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1031 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1032 /* CPU/BIOS can write BIOS. */
1033 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1034 /* ME can read descriptor and ME. */
1035 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1036 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001037 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001038 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1039 if (check_region(frba, REGION_GBE)) {
1040 /* BIOS can read/write GbE. */
1041 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1042 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1043 /* ME can read GbE. */
1044 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1045 /* GbE can read descriptor and read/write GbE.. */
1046 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1047 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1048 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1049 }
1050 if (check_region(frba, REGION_PDR)) {
1051 /* BIOS can read/write PDR. */
1052 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1053 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1054 }
1055 if (check_region(frba, REGION_EC)) {
1056 /* BIOS can read EC. */
1057 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1058 /* EC can read descriptor and read/write EC. */
1059 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1060 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1061 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1062 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001063 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001064 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001065 /* CPU/BIOS can read descriptor and BIOS. */
1066 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1067 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1068 /* CPU/BIOS can write BIOS. */
1069 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1070 /* ME can read descriptor and ME. */
1071 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1072 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1073 /* ME can write ME. */
1074 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1075 if (check_region(frba, REGION_GBE)) {
1076 /* BIOS can read GbE. */
1077 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1078 /* BIOS can write GbE. */
1079 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1080 /* ME can read GbE. */
1081 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1082 /* ME can write GbE. */
1083 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1084 /* GbE can write GbE. */
1085 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1086 /* GbE can read GbE. */
1087 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1088 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001089 break;
1090 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001091
1092 write_image(filename, image, size);
1093}
1094
Bill XIEfa5f9942017-09-12 11:22:29 +08001095static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001096{
Bill XIE612ec0e2017-08-30 16:10:27 +08001097 fmba_t *fmba = find_fmba(image, size);
1098 if (!fmba)
1099 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001100
1101 if (ifd_version >= IFD_VERSION_2) {
1102 /* Access bits for each region are read: 19:8 write: 31:20 */
1103 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1104 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1105 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001106 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001107 } else {
1108 fmba->flmstr1 = 0xffff0000;
1109 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001110 /* Keep chipset specific Requester ID */
1111 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001112 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001113
1114 write_image(filename, image, size);
1115}
1116
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001117static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1118 const unsigned int value)
1119{
1120 if (!fpsba || !fdb) {
1121 fprintf(stderr, "Internal error\n");
1122 exit(EXIT_FAILURE);
1123 }
1124
1125 /* SoC Strap Length, aka PSL, aka ISL */
1126 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1127 if (strap >= SSL) {
1128 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1129 exit(EXIT_FAILURE);
1130 }
1131 fpsba->pchstrp[strap] = value;
1132}
1133
Bill XIEb3e15a22017-09-07 18:34:50 +08001134/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001135static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001136{
1137 if (ifd_version >= IFD_VERSION_2) {
1138 printf("%sting the HAP bit to %s Intel ME...\n",
1139 altmedisable?"Set":"Unset",
1140 altmedisable?"disable":"enable");
1141 if (altmedisable)
1142 fpsba->pchstrp[0] |= (1 << 16);
1143 else
1144 fpsba->pchstrp[0] &= ~(1 << 16);
1145 } else {
1146 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1147 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1148 "and MCH_AltMeDisable to %s Intel ME...\n",
1149 altmedisable?"Set":"Unset",
1150 altmedisable?"disable":"enable");
1151 if (altmedisable) {
1152 /* MCH_MeDisable */
1153 fmsba->data[0] |= 1;
1154 /* MCH_AltMeDisable */
1155 fmsba->data[0] |= (1 << 7);
1156 /* ICH_MeDisable */
1157 fpsba->pchstrp[0] |= 1;
1158 } else {
1159 fmsba->data[0] &= ~1;
1160 fmsba->data[0] &= ~(1 << 7);
1161 fpsba->pchstrp[0] &= ~1;
1162 }
1163 } else {
1164 printf("%sting the AltMeDisable to %s Intel ME...\n",
1165 altmedisable?"Set":"Unset",
1166 altmedisable?"disable":"enable");
1167 if (altmedisable)
1168 fpsba->pchstrp[10] |= (1 << 7);
1169 else
1170 fpsba->pchstrp[10] &= ~(1 << 7);
1171 }
1172 }
1173}
1174
Jacob Garber595d9262019-06-27 17:33:10 -06001175static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001176 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001177{
Bill XIE612ec0e2017-08-30 16:10:27 +08001178 frba_t *frba = find_frba(image, size);
1179 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001180 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001181
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001182 region_t region = get_region(frba, region_type);
1183 if (region.size <= 0xfff) {
1184 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1185 region_name(region_type));
1186 exit(EXIT_FAILURE);
1187 }
1188
Scott Duplichanf2c98372014-12-12 21:03:06 -06001189 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001190 if (region_fd == -1) {
1191 perror("Could not open file");
1192 exit(EXIT_FAILURE);
1193 }
1194 struct stat buf;
1195 if (fstat(region_fd, &buf) == -1) {
1196 perror("Could not stat file");
1197 exit(EXIT_FAILURE);
1198 }
1199 int region_size = buf.st_size;
1200
1201 printf("File %s is %d bytes\n", region_fname, region_size);
1202
1203 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001204 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001205 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1206 " bytes. Not injecting.\n",
1207 region_name(region_type), region.size,
1208 region.size, region_size, region_size);
1209 exit(EXIT_FAILURE);
1210 }
1211
1212 int offset = 0;
1213 if ((region_type == 1) && (region_size < region.size)) {
1214 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1215 " bytes. Padding before injecting.\n",
1216 region_name(region_type), region.size,
1217 region.size, region_size, region_size);
1218 offset = region.size - region_size;
1219 memset(image + region.base, 0xff, offset);
1220 }
1221
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001222 if (size < region.base + offset + region_size) {
1223 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1224 size, region.base + offset + region_size);
1225 exit(EXIT_FAILURE);
1226 }
1227
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001228 if (read(region_fd, image + region.base + offset, region_size)
1229 != region_size) {
1230 perror("Could not read file");
1231 exit(EXIT_FAILURE);
1232 }
1233
1234 close(region_fd);
1235
1236 printf("Adding %s as the %s section of %s\n",
1237 region_fname, region_name(region_type), filename);
1238 write_image(filename, image, size);
1239}
1240
Jacob Garber595d9262019-06-27 17:33:10 -06001241static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001242{
1243 unsigned int y = 1;
1244 if (x == 0)
1245 return 0;
1246 while (y <= x)
1247 y = y << 1;
1248
1249 return y;
1250}
1251
1252/**
1253 * Determine if two memory regions overlap.
1254 *
1255 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001256 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001257 * @return 1 if the two regions overlap
1258 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001259static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001260{
Bill XIEfa5f9942017-09-12 11:22:29 +08001261 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001262 return 0;
1263
Nico Huber844eda02019-01-05 00:06:19 +01001264 /* r1 should be either completely below or completely above r2 */
1265 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001266}
1267
Jacob Garber595d9262019-06-27 17:33:10 -06001268static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001269 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001270{
1271 FILE *romlayout;
1272 char tempstr[256];
1273 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001274 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001275 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001276 region_t current_regions[MAX_REGIONS];
1277 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001278 int new_extent = 0;
1279 char *new_image;
1280
1281 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001282 frba_t *frba = find_frba(image, size);
1283 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001284 exit(EXIT_FAILURE);
1285
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001286 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001287 current_regions[i] = get_region(frba, i);
1288 new_regions[i] = get_region(frba, i);
1289 }
1290
1291 /* read new layout */
1292 romlayout = fopen(layout_fname, "r");
1293
1294 if (!romlayout) {
1295 perror("Could not read layout file.\n");
1296 exit(EXIT_FAILURE);
1297 }
1298
1299 while (!feof(romlayout)) {
1300 char *tstr1, *tstr2;
1301
Patrick Georgi802ad522014-08-09 17:12:23 +02001302 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001303 layout_region_name))
1304 continue;
1305
1306 region_number = region_num(layout_region_name);
1307 if (region_number < 0)
1308 continue;
1309
1310 tstr1 = strtok(tempstr, ":");
1311 tstr2 = strtok(NULL, ":");
1312 if (!tstr1 || !tstr2) {
1313 fprintf(stderr, "Could not parse layout file.\n");
1314 exit(EXIT_FAILURE);
1315 }
1316 new_regions[region_number].base = strtol(tstr1,
1317 (char **)NULL, 16);
1318 new_regions[region_number].limit = strtol(tstr2,
1319 (char **)NULL, 16);
1320 new_regions[region_number].size =
1321 new_regions[region_number].limit -
1322 new_regions[region_number].base + 1;
1323
1324 if (new_regions[region_number].size < 0)
1325 new_regions[region_number].size = 0;
1326 }
1327 fclose(romlayout);
1328
1329 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001330 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001331 if (new_regions[i].size == 0)
1332 continue;
1333
1334 if (new_regions[i].size < current_regions[i].size) {
1335 printf("DANGER: Region %s is shrinking.\n",
1336 region_name(i));
1337 printf(" The region will be truncated to fit.\n");
1338 printf(" This may result in an unusable image.\n");
1339 }
1340
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001341 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001342 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001343 fprintf(stderr, "Regions would overlap.\n");
1344 exit(EXIT_FAILURE);
1345 }
1346 }
1347
1348 /* detect if the image size should grow */
1349 if (new_extent < new_regions[i].limit)
1350 new_extent = new_regions[i].limit;
1351 }
1352
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001353 /* check if the image is actually a Flash Descriptor region */
1354 if (size == new_regions[0].size) {
1355 printf("The image is a single Flash Descriptor:\n");
1356 printf(" Only the descriptor will be modified\n");
1357 new_extent = size;
1358 } else {
1359 new_extent = next_pow2(new_extent - 1);
1360 if (new_extent != size) {
1361 printf("The image has changed in size.\n");
1362 printf("The old image is %d bytes.\n", size);
1363 printf("The new image is %d bytes.\n", new_extent);
1364 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001365 }
1366
1367 /* copy regions to a new image */
1368 new_image = malloc(new_extent);
1369 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001370 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001371 int copy_size = new_regions[i].size;
1372 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001373 const region_t *current = &current_regions[i];
1374 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001375
Bill XIEfa5f9942017-09-12 11:22:29 +08001376 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001377 continue;
1378
Bill XIEfa5f9942017-09-12 11:22:29 +08001379 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001380 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001381 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001382 if (i == REGION_BIOS)
1383 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001384 }
1385
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001386 if ((i == REGION_BIOS) && (new->size < current->size)) {
1387 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001388 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001389 }
1390
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001391 if (size < current->base + offset_current + copy_size) {
1392 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1393 region_name(i));
1394 continue;
1395 };
1396
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001397 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1398 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001399 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1400 offset_current, current->limit, current->size);
1401 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1402 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001403
Bill XIEfa5f9942017-09-12 11:22:29 +08001404 memcpy(new_image + new->base + offset_new,
1405 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001406 copy_size);
1407 }
1408
1409 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001410 frba = find_frba(new_image, new_extent);
1411 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001412 exit(EXIT_FAILURE);
1413
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001414 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001415 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001416 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001417
1418 write_image(filename, new_image, new_extent);
1419 free(new_image);
1420}
1421
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001422static void print_version(void)
1423{
1424 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1425 printf("Copyright (C) 2011 Google Inc.\n\n");
1426 printf
1427 ("This program is free software: you can redistribute it and/or modify\n"
1428 "it under the terms of the GNU General Public License as published by\n"
1429 "the Free Software Foundation, version 2 of the License.\n\n"
1430 "This program is distributed in the hope that it will be useful,\n"
1431 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1432 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001433 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001434}
1435
1436static void print_usage(const char *name)
1437{
1438 printf("usage: %s [-vhdix?] <filename>\n", name);
1439 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001440 " -d | --dump: dump intel firmware descriptor\n"
1441 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1442 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1443 " -x | --extract: extract intel fd modules\n"
1444 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1445 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001446 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001447 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1448 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1449 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1450 " can only be used once per run:\n"
1451 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1452 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1453 " Dual Output Fast Read Support\n"
1454 " -l | --lock Lock firmware descriptor and ME region\n"
1455 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001456 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1457 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001458 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301459 " adl - Alder Lake\n"
1460 " aplk - Apollo Lake\n"
1461 " cnl - Cannon Lake\n"
1462 " glk - Gemini Lake\n"
1463 " icl - Ice Lake\n"
1464 " jsl - Jasper Lake\n"
1465 " sklkbl - Sky Lake/Kaby Lake\n"
1466 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001467 " -S | --setpchstrap Write a PCH strap\n"
1468 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001469 " -v | --version: print the version\n"
1470 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001471 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1472 "\n");
1473}
1474
1475int main(int argc, char *argv[])
1476{
1477 int opt, option_index = 0;
1478 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001479 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001480 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001481 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001482 char *region_type_string = NULL, *region_fname = NULL;
1483 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001484 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001485 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001486 unsigned int value = 0;
1487 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001488 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001489 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1490
Bill XIEfa5f9942017-09-12 11:22:29 +08001491 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001492 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001493 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001494 {"extract", 0, NULL, 'x'},
1495 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001496 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001497 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001498 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001499 {"density", 1, NULL, 'D'},
1500 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001501 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001502 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001503 {"lock", 0, NULL, 'l'},
1504 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001505 {"version", 0, NULL, 'v'},
1506 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001507 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001508 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001509 {"setpchstrap", 1, NULL, 'S'},
1510 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001511 {0, 0, 0, 0}
1512 };
1513
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001514 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 -07001515 long_options, &option_index)) != EOF) {
1516 switch (opt) {
1517 case 'd':
1518 mode_dump = 1;
1519 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001520 case 'S':
1521 mode_setstrap = 1;
1522 pchstrap = strtoul(optarg, NULL, 0);
1523 break;
1524 case 'V':
1525 value = strtoul(optarg, NULL, 0);
1526 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001527 case 'f':
1528 mode_layout = 1;
1529 layout_fname = strdup(optarg);
1530 if (!layout_fname) {
1531 fprintf(stderr, "No layout file specified\n");
1532 print_usage(argv[0]);
1533 exit(EXIT_FAILURE);
1534 }
1535 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001536 case 'x':
1537 mode_extract = 1;
1538 break;
1539 case 'i':
1540 // separate type and file name
1541 region_type_string = strdup(optarg);
1542 region_fname = strchr(region_type_string, ':');
1543 if (!region_fname) {
1544 print_usage(argv[0]);
1545 exit(EXIT_FAILURE);
1546 }
1547 region_fname[0] = '\0';
1548 region_fname++;
1549 // Descriptor, BIOS, ME, GbE, Platform
1550 // valid type?
1551 if (!strcasecmp("Descriptor", region_type_string))
1552 region_type = 0;
1553 else if (!strcasecmp("BIOS", region_type_string))
1554 region_type = 1;
1555 else if (!strcasecmp("ME", region_type_string))
1556 region_type = 2;
1557 else if (!strcasecmp("GbE", region_type_string))
1558 region_type = 3;
1559 else if (!strcasecmp("Platform", region_type_string))
1560 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001561 else if (!strcasecmp("EC", region_type_string))
1562 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001563 if (region_type == -1) {
1564 fprintf(stderr, "No such region type: '%s'\n\n",
1565 region_type_string);
1566 print_usage(argv[0]);
1567 exit(EXIT_FAILURE);
1568 }
1569 mode_inject = 1;
1570 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001571 case 'n':
1572 mode_newlayout = 1;
1573 layout_fname = strdup(optarg);
1574 if (!layout_fname) {
1575 fprintf(stderr, "No layout file specified\n");
1576 print_usage(argv[0]);
1577 exit(EXIT_FAILURE);
1578 }
1579 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001580 case 'O':
1581 new_filename = strdup(optarg);
1582 if (!new_filename) {
1583 fprintf(stderr, "No output filename specified\n");
1584 print_usage(argv[0]);
1585 exit(EXIT_FAILURE);
1586 }
1587 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001588 case 'D':
1589 mode_density = 1;
1590 new_density = strtoul(optarg, NULL, 0);
1591 switch (new_density) {
1592 case 512:
1593 new_density = COMPONENT_DENSITY_512KB;
1594 break;
1595 case 1:
1596 new_density = COMPONENT_DENSITY_1MB;
1597 break;
1598 case 2:
1599 new_density = COMPONENT_DENSITY_2MB;
1600 break;
1601 case 4:
1602 new_density = COMPONENT_DENSITY_4MB;
1603 break;
1604 case 8:
1605 new_density = COMPONENT_DENSITY_8MB;
1606 break;
1607 case 16:
1608 new_density = COMPONENT_DENSITY_16MB;
1609 break;
1610 case 32:
1611 new_density = COMPONENT_DENSITY_32MB;
1612 break;
1613 case 64:
1614 new_density = COMPONENT_DENSITY_64MB;
1615 break;
1616 case 0:
1617 new_density = COMPONENT_DENSITY_UNUSED;
1618 break;
1619 default:
1620 printf("error: Unknown density\n");
1621 print_usage(argv[0]);
1622 exit(EXIT_FAILURE);
1623 }
1624 break;
1625 case 'C':
1626 selected_chip = strtol(optarg, NULL, 0);
1627 if (selected_chip > 2) {
1628 fprintf(stderr, "error: Invalid chip selection\n");
1629 print_usage(argv[0]);
1630 exit(EXIT_FAILURE);
1631 }
1632 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001633 case 'M':
1634 mode_altmedisable = 1;
1635 altmedisable = strtol(optarg, NULL, 0);
1636 if (altmedisable > 1) {
1637 fprintf(stderr, "error: Illegal value\n");
1638 print_usage(argv[0]);
1639 exit(EXIT_FAILURE);
1640 }
1641 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001642 case 's':
1643 // Parse the requested SPI frequency
1644 inputfreq = strtol(optarg, NULL, 0);
1645 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001646 case 17:
1647 spifreq = SPI_FREQUENCY_17MHZ;
1648 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001649 case 20:
1650 spifreq = SPI_FREQUENCY_20MHZ;
1651 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001652 case 30:
1653 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1654 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001655 case 33:
1656 spifreq = SPI_FREQUENCY_33MHZ;
1657 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001658 case 48:
1659 spifreq = SPI_FREQUENCY_48MHZ;
1660 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001661 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001662 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001663 break;
1664 default:
1665 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1666 inputfreq);
1667 print_usage(argv[0]);
1668 exit(EXIT_FAILURE);
1669 }
1670 mode_spifreq = 1;
1671 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001672 case 'e':
1673 mode_em100 = 1;
1674 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001675 case 'l':
1676 mode_locked = 1;
1677 if (mode_unlocked == 1) {
1678 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1679 exit(EXIT_FAILURE);
1680 }
1681 break;
1682 case 'u':
1683 mode_unlocked = 1;
1684 if (mode_locked == 1) {
1685 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1686 exit(EXIT_FAILURE);
1687 }
1688 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001689 case 'p':
1690 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001691 platform = PLATFORM_APL;
1692 } else if (!strcmp(optarg, "cnl")) {
1693 platform = PLATFORM_CNL;
1694 } else if (!strcmp(optarg, "glk")) {
1695 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301696 } else if (!strcmp(optarg, "icl")) {
1697 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301698 } else if (!strcmp(optarg, "jsl")) {
1699 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001700 } else if (!strcmp(optarg, "sklkbl")) {
1701 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001702 } else if (!strcmp(optarg, "tgl")) {
1703 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301704 } else if (!strcmp(optarg, "adl")) {
1705 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001706 } else {
1707 fprintf(stderr, "Unknown platform: %s\n", optarg);
1708 exit(EXIT_FAILURE);
1709 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001710 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001711 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001712 case 't':
1713 mode_validate = 1;
1714 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001715 case 'v':
1716 print_version();
1717 exit(EXIT_SUCCESS);
1718 break;
1719 case 'h':
1720 case '?':
1721 default:
1722 print_usage(argv[0]);
1723 exit(EXIT_SUCCESS);
1724 break;
1725 }
1726 }
1727
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001728 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001729 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001730 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001731 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001732 print_usage(argv[0]);
1733 exit(EXIT_FAILURE);
1734 }
1735
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001736 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001737 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001738 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001739 fprintf(stderr, "You need to specify a mode.\n\n");
1740 print_usage(argv[0]);
1741 exit(EXIT_FAILURE);
1742 }
1743
1744 if (optind + 1 != argc) {
1745 fprintf(stderr, "You need to specify a file.\n\n");
1746 print_usage(argv[0]);
1747 exit(EXIT_FAILURE);
1748 }
1749
1750 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001751 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001752 if (bios_fd == -1) {
1753 perror("Could not open file");
1754 exit(EXIT_FAILURE);
1755 }
1756 struct stat buf;
1757 if (fstat(bios_fd, &buf) == -1) {
1758 perror("Could not stat file");
1759 exit(EXIT_FAILURE);
1760 }
1761 int size = buf.st_size;
1762
1763 printf("File %s is %d bytes\n", filename, size);
1764
1765 char *image = malloc(size);
1766 if (!image) {
1767 printf("Out of memory.\n");
1768 exit(EXIT_FAILURE);
1769 }
1770
1771 if (read(bios_fd, image, size) != size) {
1772 perror("Could not read file");
1773 exit(EXIT_FAILURE);
1774 }
1775
1776 close(bios_fd);
1777
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001778 // generate new filename
1779 if (new_filename == NULL) {
1780 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1781 if (!new_filename) {
1782 printf("Out of memory.\n");
1783 exit(EXIT_FAILURE);
1784 }
1785 // - 5: leave room for ".new\0"
1786 strcpy(new_filename, filename);
1787 strcat(new_filename, ".new");
1788 }
1789
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001790 check_ifd_version(image, size);
1791
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001792 if (mode_dump)
1793 dump_fd(image, size);
1794
Chris Douglass03ce0142014-02-26 13:30:13 -05001795 if (mode_layout)
1796 dump_layout(image, size, layout_fname);
1797
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001798 if (mode_extract)
1799 write_regions(image, size);
1800
Mathew Kingc7ddc992019-08-08 14:59:25 -06001801 if (mode_validate)
1802 validate_layout(image, size);
1803
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001804 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001805 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001806 region_fname);
1807
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001808 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001809 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001810
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001811 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001812 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001813
Jan Tatjefa317512016-03-11 00:52:07 +01001814 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001815 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001816
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001817 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001818 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001819
Alexander Couzensd12ea112016-09-10 13:33:05 +02001820 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001821 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001822
1823 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001824 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001825
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001826 if (mode_setstrap) {
1827 fpsba_t *fpsba = find_fpsba(image, size);
1828 const fdbar_t *fdb = find_fd(image, size);
1829 set_pchstrap(fpsba, fdb, pchstrap, value);
1830 write_image(new_filename, image, size);
1831 }
1832
Bill XIEb3e15a22017-09-07 18:34:50 +08001833 if (mode_altmedisable) {
1834 fpsba_t *fpsba = find_fpsba(image, size);
1835 fmsba_t *fmsba = find_fmsba(image, size);
1836 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001837 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001838 }
1839
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001840 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001841 free(image);
1842
1843 return 0;
1844}