blob: 2388ebca7e9b80860271f84e956abae1df64df0f [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",
Subrata Banik89db2252020-08-26 14:49:17 +053062 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080063 "5 series Ibex Peak",
64 "6 series Cougar Point",
65 "7 series Panther Point",
66 "8 series Lynx Point",
67 "Baytrail",
68 "8 series Lynx Point LP",
69 "8 series Wellsburg",
70 "9 series Wildcat Point",
71 "9 series Wildcat Point LP",
Subrata Banik89db2252020-08-26 14:49:17 +053072 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
73 "100/200 series Sunrise Point",
74 "300 series Cannon Point/ 400 series Ice Point",
75 "500 series Tiger Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080076 "C620 series Lewisburg",
77 NULL
78};
79
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070080static fdbar_t *find_fd(char *image, int size)
81{
82 int i, found = 0;
83
84 /* Scan for FD signature */
85 for (i = 0; i < (size - 4); i += 4) {
86 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
87 found = 1;
88 break; // signature found.
89 }
90 }
91
92 if (!found) {
93 printf("No Flash Descriptor found in this image\n");
94 return NULL;
95 }
96
Bill XIE612ec0e2017-08-30 16:10:27 +080097 fdbar_t *fdb = (fdbar_t *) (image + i);
98 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
99}
100
Stefan Tauner0d226142018-08-05 18:56:53 +0200101static char *find_flumap(char *image, int size)
102{
103 /* The upper map is located in the word before the 256B-long OEM section
104 * at the end of the 4kB-long flash descriptor. In the official
105 * documentation this is defined as FDBAR + 0xEFC. However, starting
106 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
107 * has moved 16 bytes back to offset 0x10 of the image. Although
108 * official documentation still maintains the offset relative to FDBAR
109 * this is wrong and a simple fixed offset from the start of the image
110 * works.
111 */
112 char *flumap = image + 4096 - 256 - 4;
113 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
114}
115
Bill XIE612ec0e2017-08-30 16:10:27 +0800116static fcba_t *find_fcba(char *image, int size)
117{
118 fdbar_t *fdb = find_fd(image, size);
119 if (!fdb)
120 return NULL;
121 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
122 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
123
124}
125
126static fmba_t *find_fmba(char *image, int size)
127{
128 fdbar_t *fdb = find_fd(image, size);
129 if (!fdb)
130 return NULL;
131 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
132 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
133}
134
135static frba_t *find_frba(char *image, int size)
136{
137 fdbar_t *fdb = find_fd(image, size);
138 if (!fdb)
139 return NULL;
140 frba_t *frba =
141 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
142 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
143}
144
145static fpsba_t *find_fpsba(char *image, int size)
146{
147 fdbar_t *fdb = find_fd(image, size);
148 if (!fdb)
149 return NULL;
150 fpsba_t *fpsba =
151 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200152
153 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
154 if ((((char *)fpsba) + SSL) >= (image + size))
155 return NULL;
156 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800157}
158
159static fmsba_t *find_fmsba(char *image, int size)
160{
161 fdbar_t *fdb = find_fd(image, size);
162 if (!fdb)
163 return NULL;
164 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
165 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700166}
167
Subrata Banik89db2252020-08-26 14:49:17 +0530168static enum ich_chipset guess_ifd_2_chipset(const fpsba_t *fpsba)
169{
170 uint32_t pchstrp_22 = fpsba->pchstrp[22];
171 uint32_t pchstrp_23 = fpsba->pchstrp[23];
172
173 /* Offset 0x5B is the last PCH descriptor record */
174 if (pchstrp_23 == 0xFFFFFFFF)
175 return CHIPSET_N_J_SERIES;
176
177 /* Offset 0x58 is PCH descriptor record is reserved */
178 if (pchstrp_22 == 0x0)
179 return CHIPSET_300_400_SERIES_CANNON_ICE_POINT;
180
181 /* Offset 0x58 bit [2:0] is reserved 0x4 and 0x5a bit [7:0] is reserved 0x58 */
182 if (((pchstrp_22 & 0x07) == 0x4) &&
183 ((pchstrp_22 & 0xFF0000) >> 16 == 0x58))
184 return CHIPSET_500_SERIES_TIGER_POINT;
185
186 return CHIPSET_PCH_UNKNOWN;
187}
188
Bill XIEb3e15a22017-09-07 18:34:50 +0800189/* port from flashrom */
Subrata Banik89db2252020-08-26 14:49:17 +0530190static enum ich_chipset guess_ich_chipset(const fdbar_t *fdb, const fpsba_t *fpsba)
Bill XIEb3e15a22017-09-07 18:34:50 +0800191{
192 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
193 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
194 uint32_t isl = (fdb->flmap1 >> 24);
195 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
Subrata Banik89db2252020-08-26 14:49:17 +0530196 int temp_chipset;
Bill XIEb3e15a22017-09-07 18:34:50 +0800197
Subrata Banik89db2252020-08-26 14:49:17 +0530198 /* Check for IFD2 chipset type */
199 temp_chipset = guess_ifd_2_chipset(fpsba);
200 if (temp_chipset != CHIPSET_PCH_UNKNOWN)
201 return temp_chipset;
202
203 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800204 if (iccriba == 0x00) {
205 if (msl == 0 && isl <= 2)
206 return CHIPSET_ICH8;
207 else if (isl <= 2)
208 return CHIPSET_ICH9;
209 else if (isl <= 10)
210 return CHIPSET_ICH10;
211 else if (isl <= 16)
212 return CHIPSET_5_SERIES_IBEX_PEAK;
213 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
214 return CHIPSET_5_SERIES_IBEX_PEAK;
215 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
216 if (msl == 0 && isl <= 17)
217 return CHIPSET_BAYTRAIL;
218 else if (msl <= 1 && isl <= 18)
219 return CHIPSET_6_SERIES_COUGAR_POINT;
220 else if (msl <= 1 && isl <= 21)
221 return CHIPSET_8_SERIES_LYNX_POINT;
222 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
223 return CHIPSET_9_SERIES_WILDCAT_POINT;
224 } else if (nm == 6) {
225 return CHIPSET_C620_SERIES_LEWISBURG;
226 } else {
Subrata Banik89db2252020-08-26 14:49:17 +0530227 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800228 }
229}
230
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700231/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700232 * Some newer platforms have re-defined the FCBA field that was used to
233 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
234 * have the required FCBA field, but are IFD v2 and return true if current
235 * platform is one of them.
236 */
237static int is_platform_ifd_2(void)
238{
239 static const int ifd_2_platforms[] = {
240 PLATFORM_GLK,
241 PLATFORM_CNL,
Aamir Bohra1018be22018-06-29 15:08:50 +0530242 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700243 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530244 PLATFORM_JSL,
Subrata Banik46f80732020-03-14 15:01:42 +0530245 PLATFORM_ADL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700246 };
247 unsigned int i;
248
249 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
250 if (platform == ifd_2_platforms[i])
251 return 1;
252 }
253
254 return 0;
255}
256
257/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700258 * There is no version field in the descriptor so to determine
259 * if this is a new descriptor format we check the hardcoded SPI
260 * read frequency to see if it is fixed at 20MHz or 17MHz.
261 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700262static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700263{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700264 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800265 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800266 const fdbar_t *fdb = find_fd(image, size);
Subrata Banik89db2252020-08-26 14:49:17 +0530267 const fpsba_t *fpsba = find_fpsba(image, size);
Jacob Garber9bb04612019-05-08 13:40:45 -0600268 if (!fcba || !fdb)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700269 exit(EXIT_FAILURE);
270
Subrata Banik89db2252020-08-26 14:49:17 +0530271 chipset = guess_ich_chipset(fdb, fpsba);
Bill XIEb3e15a22017-09-07 18:34:50 +0800272 /* TODO: port ifd_version and max_regions
273 * against guess_ich_chipset()
274 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700275 read_freq = (fcba->flcomp >> 17) & 7;
276
277 switch (read_freq) {
278 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700279 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700280 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700281 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700282 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700283 default:
284 fprintf(stderr, "Unknown descriptor version: %d\n",
285 read_freq);
286 exit(EXIT_FAILURE);
287 }
288}
289
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700290static void check_ifd_version(char *image, int size)
291{
292 if (is_platform_ifd_2())
293 ifd_version = IFD_VERSION_2;
294 else
295 ifd_version = get_ifd_version_from_fcba(image, size);
296
297 if (ifd_version == IFD_VERSION_1)
298 max_regions = MAX_REGIONS_OLD;
299 else
300 max_regions = MAX_REGIONS;
301}
302
Bill XIEfa5f9942017-09-12 11:22:29 +0800303static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700304{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500305 int base_mask;
306 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700307 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700308 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500309
310 if (ifd_version >= IFD_VERSION_2)
311 base_mask = 0x7fff;
312 else
313 base_mask = 0xfff;
314
315 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400317 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800318 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700319 exit (EXIT_FAILURE);
320 }
321
Bill XIE4651d452017-09-12 11:54:48 +0800322 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700323 region.base = (flreg & base_mask) << 12;
324 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700325 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500326
Chris Douglass03ce0142014-02-26 13:30:13 -0500327 if (region.size < 0)
328 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700329
330 return region;
331}
332
Bill XIEfa5f9942017-09-12 11:22:29 +0800333static void set_region(frba_t *frba, unsigned int region_type,
334 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500335{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400336 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800337 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500338 exit (EXIT_FAILURE);
339 }
Bill XIE4651d452017-09-12 11:54:48 +0800340
341 frba->flreg[region_type] =
342 (((region->limit >> 12) & 0x7fff) << 16) |
343 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500344}
345
Bill XIEfa5f9942017-09-12 11:22:29 +0800346static const char *region_name(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) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700349 fprintf(stderr, "Invalid region type.\n");
350 exit (EXIT_FAILURE);
351 }
352
Chris Douglass03ce0142014-02-26 13:30:13 -0500353 return region_names[region_type].pretty;
354}
355
Bill XIEfa5f9942017-09-12 11:22:29 +0800356static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500357{
Bill XIEfa5f9942017-09-12 11:22:29 +0800358 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500359 fprintf(stderr, "Invalid region type.\n");
360 exit (EXIT_FAILURE);
361 }
362
363 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700364}
365
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500366static int region_num(const char *name)
367{
Bill XIEfa5f9942017-09-12 11:22:29 +0800368 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500369
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200370 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500371 if (strcasecmp(name, region_names[i].pretty) == 0)
372 return i;
373 if (strcasecmp(name, region_names[i].terse) == 0)
374 return i;
375 }
376
377 return -1;
378}
379
Bill XIEfa5f9942017-09-12 11:22:29 +0800380static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700381{
Bill XIEfa5f9942017-09-12 11:22:29 +0800382 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700383 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700384 exit (EXIT_FAILURE);
385 }
386
Bill XIE1bf65062017-09-12 11:31:37 +0800387 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700388}
389
Bill XIEfa5f9942017-09-12 11:22:29 +0800390static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700391{
392 region_t region = get_region(frba, num);
393 printf(" Flash Region %d (%s): %08x - %08x %s\n",
394 num, region_name(num), region.base, region.limit,
395 region.size < 1 ? "(unused)" : "");
396}
397
Bill XIEfa5f9942017-09-12 11:22:29 +0800398static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
399 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500400{
401 region_t region = get_region(frba, num);
402 snprintf(buf, bufsize, "%08x:%08x %s\n",
403 region.base, region.limit, region_name_short(num));
404}
405
Bill XIEfa5f9942017-09-12 11:22:29 +0800406static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700407{
Bill XIE4651d452017-09-12 11:54:48 +0800408 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530409 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700410 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800411 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530412 region = get_region(frba, i);
413 /* Skip unused & reserved Flash Region */
414 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
415 continue;
416
Bill XIE4651d452017-09-12 11:54:48 +0800417 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
418 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700419 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700420}
421
Bill XIEfa5f9942017-09-12 11:22:29 +0800422static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500423{
424 char buf[LAYOUT_LINELEN];
425 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800426 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500427
428 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
429 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
430 if (layout_fd == -1) {
431 perror("Could not open file");
432 exit(EXIT_FAILURE);
433 }
434
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200435 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200436 region_t region = get_region(frba, i);
437 /* is region invalid? */
438 if (region.size < 1)
439 continue;
440
Chris Douglass03ce0142014-02-26 13:30:13 -0500441 dump_region_layout(buf, bufsize, i, frba);
442 if (write(layout_fd, buf, strlen(buf)) < 0) {
443 perror("Could not write to file");
444 exit(EXIT_FAILURE);
445 }
446 }
447 close(layout_fd);
448 printf("Wrote layout to %s\n", layout_fname);
449}
450
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700451static void decode_spi_frequency(unsigned int freq)
452{
453 switch (freq) {
454 case SPI_FREQUENCY_20MHZ:
455 printf("20MHz");
456 break;
457 case SPI_FREQUENCY_33MHZ:
458 printf("33MHz");
459 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700460 case SPI_FREQUENCY_48MHZ:
461 printf("48MHz");
462 break;
463 case SPI_FREQUENCY_50MHZ_30MHZ:
464 switch (ifd_version) {
465 case IFD_VERSION_1:
466 printf("50MHz");
467 break;
468 case IFD_VERSION_2:
469 printf("30MHz");
470 break;
471 }
472 break;
473 case SPI_FREQUENCY_17MHZ:
474 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700475 break;
476 default:
477 printf("unknown<%x>MHz", freq);
478 }
479}
480
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700481static void decode_component_density(unsigned int density)
482{
483 switch (density) {
484 case COMPONENT_DENSITY_512KB:
485 printf("512KB");
486 break;
487 case COMPONENT_DENSITY_1MB:
488 printf("1MB");
489 break;
490 case COMPONENT_DENSITY_2MB:
491 printf("2MB");
492 break;
493 case COMPONENT_DENSITY_4MB:
494 printf("4MB");
495 break;
496 case COMPONENT_DENSITY_8MB:
497 printf("8MB");
498 break;
499 case COMPONENT_DENSITY_16MB:
500 printf("16MB");
501 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700502 case COMPONENT_DENSITY_32MB:
503 printf("32MB");
504 break;
505 case COMPONENT_DENSITY_64MB:
506 printf("64MB");
507 break;
508 case COMPONENT_DENSITY_UNUSED:
509 printf("UNUSED");
510 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700511 default:
512 printf("unknown<%x>MB", density);
513 }
514}
515
Bill XIEfa5f9942017-09-12 11:22:29 +0800516static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700517{
518 printf("\nFound Component Section\n");
519 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700520 printf(" Dual Output Fast Read Support: %ssupported\n",
521 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700522 printf(" Read ID/Read Status Clock Frequency: ");
523 decode_spi_frequency((fcba->flcomp >> 27) & 7);
524 printf("\n Write/Erase Clock Frequency: ");
525 decode_spi_frequency((fcba->flcomp >> 24) & 7);
526 printf("\n Fast Read Clock Frequency: ");
527 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700528 printf("\n Fast Read Support: %ssupported",
529 (fcba->flcomp & (1 << 20))?"":"not ");
530 printf("\n Read Clock Frequency: ");
531 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700532
533 switch (ifd_version) {
534 case IFD_VERSION_1:
535 printf("\n Component 2 Density: ");
536 decode_component_density((fcba->flcomp >> 3) & 7);
537 printf("\n Component 1 Density: ");
538 decode_component_density(fcba->flcomp & 7);
539 break;
540 case IFD_VERSION_2:
541 printf("\n Component 2 Density: ");
542 decode_component_density((fcba->flcomp >> 4) & 0xf);
543 printf("\n Component 1 Density: ");
544 decode_component_density(fcba->flcomp & 0xf);
545 break;
546 }
547
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700548 printf("\n");
549 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700550 printf(" Invalid Instruction 3: 0x%02x\n",
551 (fcba->flill >> 24) & 0xff);
552 printf(" Invalid Instruction 2: 0x%02x\n",
553 (fcba->flill >> 16) & 0xff);
554 printf(" Invalid Instruction 1: 0x%02x\n",
555 (fcba->flill >> 8) & 0xff);
556 printf(" Invalid Instruction 0: 0x%02x\n",
557 fcba->flill & 0xff);
558 printf("FLPB 0x%08x\n", fcba->flpb);
559 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
560 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700561}
562
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200563static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700564{
Bill XIE4651d452017-09-12 11:54:48 +0800565 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200566 /* SoC Strap Length, aka PSL, aka ISL */
567 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
568
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700569 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200570 for (i = 0; i < SSL; i++)
571 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800572
573 if (ifd_version >= IFD_VERSION_2) {
574 printf("HAP bit is %sset\n",
575 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
576 } else if (chipset >= CHIPSET_ICH8
577 && chipset <= CHIPSET_ICH10) {
578 printf("ICH_MeDisable bit is %sset\n",
579 fpsba->pchstrp[0] & 1 ? "" : "not ");
580 } else {
581 printf("AltMeDisable bit is %sset\n",
582 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
583 }
584
Bill XIE4651d452017-09-12 11:54:48 +0800585 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700586}
587
588static void decode_flmstr(uint32_t flmstr)
589{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700590 int wr_shift, rd_shift;
591 if (ifd_version >= IFD_VERSION_2) {
592 wr_shift = FLMSTR_WR_SHIFT_V2;
593 rd_shift = FLMSTR_RD_SHIFT_V2;
594 } else {
595 wr_shift = FLMSTR_WR_SHIFT_V1;
596 rd_shift = FLMSTR_RD_SHIFT_V1;
597 }
598
599 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700600 if (ifd_version >= IFD_VERSION_2)
601 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700602 (flmstr & (1 << (wr_shift + 8))) ?
603 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700604 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700605 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700606 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700607 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700608 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700609 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700610 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700611 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700612 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700613 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700614
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700615 if (ifd_version >= IFD_VERSION_2)
616 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700617 (flmstr & (1 << (rd_shift + 8))) ?
618 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700619 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700620 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700621 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700622 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700623 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700624 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700625 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700626 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700627 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700628 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700629
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700630 /* Requestor ID doesn't exist for ifd 2 */
631 if (ifd_version < IFD_VERSION_2)
632 printf(" Requester ID: 0x%04x\n\n",
633 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700634}
635
Bill XIEfa5f9942017-09-12 11:22:29 +0800636static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700637{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700638 printf("Found Master Section\n");
639 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
640 decode_flmstr(fmba->flmstr1);
641 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
642 decode_flmstr(fmba->flmstr2);
643 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
644 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700645 if (ifd_version >= IFD_VERSION_2) {
646 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
647 decode_flmstr(fmba->flmstr5);
648 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700649}
650
Bill XIEfa5f9942017-09-12 11:22:29 +0800651static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700652{
Bill XIE612ec0e2017-08-30 16:10:27 +0800653 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700654 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800655 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
656 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800657
658 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
659 printf("MCH_MeDisable bit is %sset\n",
660 fmsba->data[0] & 1 ? "" : "not ");
661 printf("MCH_AltMeDisable bit is %sset\n",
662 fmsba->data[0] & (1 << 7) ? "" : "not ");
663 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700664}
665
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700666static void dump_jid(uint32_t jid)
667{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100668 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700669 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100670 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200671 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100672 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200673 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700674}
675
676static void dump_vscc(uint32_t vscc)
677{
678 printf(" Lower Erase Opcode: 0x%02x\n",
679 vscc >> 24);
680 printf(" Lower Write Enable on Write Status: 0x%02x\n",
681 vscc & (1 << 20) ? 0x06 : 0x50);
682 printf(" Lower Write Status Required: %s\n",
683 vscc & (1 << 19) ? "Yes" : "No");
684 printf(" Lower Write Granularity: %d bytes\n",
685 vscc & (1 << 18) ? 64 : 1);
686 printf(" Lower Block / Sector Erase Size: ");
687 switch ((vscc >> 16) & 0x3) {
688 case 0:
689 printf("256 Byte\n");
690 break;
691 case 1:
692 printf("4KB\n");
693 break;
694 case 2:
695 printf("8KB\n");
696 break;
697 case 3:
698 printf("64KB\n");
699 break;
700 }
701
702 printf(" Upper Erase Opcode: 0x%02x\n",
703 (vscc >> 8) & 0xff);
704 printf(" Upper Write Enable on Write Status: 0x%02x\n",
705 vscc & (1 << 4) ? 0x06 : 0x50);
706 printf(" Upper Write Status Required: %s\n",
707 vscc & (1 << 3) ? "Yes" : "No");
708 printf(" Upper Write Granularity: %d bytes\n",
709 vscc & (1 << 2) ? 64 : 1);
710 printf(" Upper Block / Sector Erase Size: ");
711 switch (vscc & 0x3) {
712 case 0:
713 printf("256 Byte\n");
714 break;
715 case 1:
716 printf("4KB\n");
717 break;
718 case 2:
719 printf("8KB\n");
720 break;
721 case 3:
722 printf("64KB\n");
723 break;
724 }
725}
726
Bill XIEfa5f9942017-09-12 11:22:29 +0800727static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700728{
729 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200730 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
731 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700732
733 printf("ME VSCC table:\n");
734 for (i = 0; i < num; i++) {
735 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
736 dump_jid(vtba->entry[i].jid);
737 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
738 dump_vscc(vtba->entry[i].vscc);
739 }
740 printf("\n");
741}
742
Bill XIEfa5f9942017-09-12 11:22:29 +0800743static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700744{
745 int i, j;
746 printf("OEM Section:\n");
747 for (i = 0; i < 4; i++) {
748 printf("%02x:", i << 4);
749 for (j = 0; j < 16; j++)
750 printf(" %02x", oem[(i<<4)+j]);
751 printf ("\n");
752 }
753 printf ("\n");
754}
755
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700756static void dump_fd(char *image, int size)
757{
Bill XIE612ec0e2017-08-30 16:10:27 +0800758 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700759 if (!fdb)
760 exit(EXIT_FAILURE);
761
Bill XIEb3e15a22017-09-07 18:34:50 +0800762 printf("ICH Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700763 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
764 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
765 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
766 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
767 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
768
769 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
770 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
771 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
772 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
773 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
774
775 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
776 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
777 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
778
Stefan Tauner0d226142018-08-05 18:56:53 +0200779 char *flumap = find_flumap(image, size);
780 uint32_t flumap1 = *(uint32_t *)flumap;
781 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700782 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200783 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700784 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200785 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700786 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200787 (image + ((flumap1 & 0xff) << 4)),
788 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800789 dump_oem((const uint8_t *)image + 0xf00);
790
791 const frba_t *frba = find_frba(image, size);
792 const fcba_t *fcba = find_fcba(image, size);
793 const fpsba_t *fpsba = find_fpsba(image, size);
794 const fmba_t *fmba = find_fmba(image, size);
795 const fmsba_t *fmsba = find_fmsba(image, size);
796
797 if (frba && fcba && fpsba && fmba && fmsba) {
798 dump_frba(frba);
799 dump_fcba(fcba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200800 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800801 dump_fmba(fmba);
802 dump_fmsba(fmsba);
803 } else {
804 printf("FD is corrupted!\n");
805 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700806}
807
Bill XIEfa5f9942017-09-12 11:22:29 +0800808static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500809{
Bill XIE612ec0e2017-08-30 16:10:27 +0800810 const frba_t *frba = find_frba(image, size);
811 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500812 exit(EXIT_FAILURE);
813
Bill XIE612ec0e2017-08-30 16:10:27 +0800814 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500815}
816
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700817static void write_regions(char *image, int size)
818{
Bill XIEfa5f9942017-09-12 11:22:29 +0800819 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800820 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700821
Bill XIE612ec0e2017-08-30 16:10:27 +0800822 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700823 exit(EXIT_FAILURE);
824
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700825 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700826 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700827 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700828 if (region.size > 0) {
829 int region_fd;
830 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600831 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700832 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200833 if (region_fd < 0) {
834 perror("Error while trying to open file");
835 exit(EXIT_FAILURE);
836 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700837 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700838 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700839 close(region_fd);
840 }
841 }
842}
843
Mathew Kingc7ddc992019-08-08 14:59:25 -0600844static void validate_layout(char *image, int size)
845{
846 uint i, errors = 0;
847 struct fmap *fmap;
848 long int fmap_loc = fmap_find((uint8_t *)image, size);
849 const frba_t *frba = find_frba(image, size);
850
851 if (fmap_loc < 0 || !frba)
852 exit(EXIT_FAILURE);
853
854 fmap = (struct fmap *)(image + fmap_loc);
855
856 for (i = 0; i < max_regions; i++) {
857 if (region_names[i].fmapname == NULL)
858 continue;
859
860 region_t region = get_region(frba, i);
861
862 if (region.size == 0)
863 continue;
864
865 const struct fmap_area *area =
866 fmap_find_area(fmap, region_names[i].fmapname);
867
868 if (!area)
869 continue;
870
871 if ((uint)region.base != area->offset ||
872 (uint)region.size != area->size) {
873 printf("Region mismatch between %s and %s\n",
874 region_names[i].terse, area->name);
875 printf(" Descriptor region %s:\n", region_names[i].terse);
876 printf(" offset: 0x%08x\n", region.base);
877 printf(" length: 0x%08x\n", region.size);
878 printf(" FMAP area %s:\n", area->name);
879 printf(" offset: 0x%08x\n", area->offset);
880 printf(" length: 0x%08x\n", area->size);
881 errors++;
882 }
883 }
884
885 if (errors > 0)
886 exit(EXIT_FAILURE);
887}
888
Bill XIEfa5f9942017-09-12 11:22:29 +0800889static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700890{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700891 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100892 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700893
894 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100895 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600896 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700897 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200898 if (new_fd < 0) {
899 perror("Error while trying to open file");
900 exit(EXIT_FAILURE);
901 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700902 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700903 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700904 close(new_fd);
905}
906
Bill XIEfa5f9942017-09-12 11:22:29 +0800907static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700908 enum spi_frequency freq)
909{
Bill XIE612ec0e2017-08-30 16:10:27 +0800910 fcba_t *fcba = find_fcba(image, size);
911 if (!fcba)
912 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700913
914 /* clear bits 21-29 */
915 fcba->flcomp &= ~0x3fe00000;
916 /* Read ID and Read Status Clock Frequency */
917 fcba->flcomp |= freq << 27;
918 /* Write and Erase Clock Frequency */
919 fcba->flcomp |= freq << 24;
920 /* Fast Read Clock Frequency */
921 fcba->flcomp |= freq << 21;
922
923 write_image(filename, image, size);
924}
925
Bill XIEfa5f9942017-09-12 11:22:29 +0800926static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700927{
Bill XIE612ec0e2017-08-30 16:10:27 +0800928 fcba_t *fcba = find_fcba(image, size);
929 if (!fcba)
930 exit(EXIT_FAILURE);
931
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700932 int freq;
933
934 switch (ifd_version) {
935 case IFD_VERSION_1:
936 freq = SPI_FREQUENCY_20MHZ;
937 break;
938 case IFD_VERSION_2:
939 freq = SPI_FREQUENCY_17MHZ;
940 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700941 default:
942 freq = SPI_FREQUENCY_17MHZ;
943 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700944 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700945
946 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700947 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700948}
949
Bill XIEfa5f9942017-09-12 11:22:29 +0800950static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100951 unsigned int density)
952{
Bill XIE612ec0e2017-08-30 16:10:27 +0800953 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200954 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800955 if (!fcba)
956 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100957
958 printf("Setting chip density to ");
959 decode_component_density(density);
960 printf("\n");
961
962 switch (ifd_version) {
963 case IFD_VERSION_1:
964 /* fail if selected density is not supported by this version */
965 if ( (density == COMPONENT_DENSITY_32MB) ||
966 (density == COMPONENT_DENSITY_64MB) ||
967 (density == COMPONENT_DENSITY_UNUSED) ) {
968 printf("error: Selected density not supported in IFD version 1.\n");
969 exit(EXIT_FAILURE);
970 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200971 mask = 0x7;
972 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100973 break;
974 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200975 mask = 0xf;
976 chip2_offset = 4;
977 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100978 default:
979 printf("error: Unknown IFD version\n");
980 exit(EXIT_FAILURE);
981 break;
982 }
983
984 /* clear chip density for corresponding chip */
985 switch (selected_chip) {
986 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200987 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100988 break;
989 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200990 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100991 break;
992 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200993 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +0100994 break;
995 }
996
997 /* set the new density */
998 if (selected_chip == 1 || selected_chip == 0)
999 fcba->flcomp |= (density); /* first chip */
1000 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001001 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001002
1003 write_image(filename, image, size);
1004}
1005
Duncan Laurie7775d672019-06-06 13:39:26 -07001006static int check_region(const frba_t *frba, unsigned int region_type)
1007{
1008 region_t region;
1009
1010 if (!frba)
1011 return 0;
1012
1013 region = get_region(frba, region_type);
1014 return !!((region.base < region.limit) && (region.size > 0));
1015}
1016
Bill XIEfa5f9942017-09-12 11:22:29 +08001017static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001018{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001019 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001020 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001021 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001022 if (!fmba)
1023 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001024
1025 if (ifd_version >= IFD_VERSION_2) {
1026 wr_shift = FLMSTR_WR_SHIFT_V2;
1027 rd_shift = FLMSTR_RD_SHIFT_V2;
1028
1029 /* Clear non-reserved bits */
1030 fmba->flmstr1 &= 0xff;
1031 fmba->flmstr2 &= 0xff;
1032 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001033 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001034 } else {
1035 wr_shift = FLMSTR_WR_SHIFT_V1;
1036 rd_shift = FLMSTR_RD_SHIFT_V1;
1037
1038 fmba->flmstr1 = 0;
1039 fmba->flmstr2 = 0;
1040 /* Requestor ID */
1041 fmba->flmstr3 = 0x118;
1042 }
1043
Andrey Petrov96ecb772016-10-31 19:31:54 -07001044 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001045 case PLATFORM_APL:
1046 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001047 /* CPU/BIOS can read descriptor and BIOS */
1048 fmba->flmstr1 |= 0x3 << rd_shift;
1049 /* CPU/BIOS can write BIOS */
1050 fmba->flmstr1 |= 0x2 << wr_shift;
1051 /* TXE can read descriptor, BIOS and Device Expansion */
1052 fmba->flmstr2 |= 0x23 << rd_shift;
1053 /* TXE can only write Device Expansion */
1054 fmba->flmstr2 |= 0x20 << wr_shift;
1055 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001056 case PLATFORM_CNL:
1057 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001058 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001059 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301060 case PLATFORM_JSL:
Subrata Banik46f80732020-03-14 15:01:42 +05301061 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001062 /* CPU/BIOS can read descriptor and BIOS. */
1063 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1064 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1065 /* CPU/BIOS can write BIOS. */
1066 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1067 /* ME can read descriptor and ME. */
1068 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1069 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001070 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001071 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1072 if (check_region(frba, REGION_GBE)) {
1073 /* BIOS can read/write GbE. */
1074 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1075 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1076 /* ME can read GbE. */
1077 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1078 /* GbE can read descriptor and read/write GbE.. */
1079 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1080 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1081 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1082 }
1083 if (check_region(frba, REGION_PDR)) {
1084 /* BIOS can read/write PDR. */
1085 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1086 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1087 }
1088 if (check_region(frba, REGION_EC)) {
1089 /* BIOS can read EC. */
1090 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1091 /* EC can read descriptor and read/write EC. */
1092 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1093 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1094 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1095 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001096 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001097 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001098 /* CPU/BIOS can read descriptor and BIOS. */
1099 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1100 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1101 /* CPU/BIOS can write BIOS. */
1102 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1103 /* ME can read descriptor and ME. */
1104 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1105 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1106 /* ME can write ME. */
1107 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1108 if (check_region(frba, REGION_GBE)) {
1109 /* BIOS can read GbE. */
1110 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1111 /* BIOS can write GbE. */
1112 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1113 /* ME can read GbE. */
1114 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1115 /* ME can write GbE. */
1116 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1117 /* GbE can write GbE. */
1118 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1119 /* GbE can read GbE. */
1120 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1121 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001122 break;
1123 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001124
1125 write_image(filename, image, size);
1126}
1127
Bill XIEfa5f9942017-09-12 11:22:29 +08001128static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001129{
Bill XIE612ec0e2017-08-30 16:10:27 +08001130 fmba_t *fmba = find_fmba(image, size);
1131 if (!fmba)
1132 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001133
1134 if (ifd_version >= IFD_VERSION_2) {
1135 /* Access bits for each region are read: 19:8 write: 31:20 */
1136 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1137 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1138 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001139 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001140 } else {
1141 fmba->flmstr1 = 0xffff0000;
1142 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001143 /* Keep chipset specific Requester ID */
1144 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001145 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001146
1147 write_image(filename, image, size);
1148}
1149
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001150static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1151 const unsigned int value)
1152{
1153 if (!fpsba || !fdb) {
1154 fprintf(stderr, "Internal error\n");
1155 exit(EXIT_FAILURE);
1156 }
1157
1158 /* SoC Strap Length, aka PSL, aka ISL */
1159 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1160 if (strap >= SSL) {
1161 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1162 exit(EXIT_FAILURE);
1163 }
1164 fpsba->pchstrp[strap] = value;
1165}
1166
Bill XIEb3e15a22017-09-07 18:34:50 +08001167/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001168static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001169{
1170 if (ifd_version >= IFD_VERSION_2) {
1171 printf("%sting the HAP bit to %s Intel ME...\n",
1172 altmedisable?"Set":"Unset",
1173 altmedisable?"disable":"enable");
1174 if (altmedisable)
1175 fpsba->pchstrp[0] |= (1 << 16);
1176 else
1177 fpsba->pchstrp[0] &= ~(1 << 16);
1178 } else {
1179 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1180 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1181 "and MCH_AltMeDisable to %s Intel ME...\n",
1182 altmedisable?"Set":"Unset",
1183 altmedisable?"disable":"enable");
1184 if (altmedisable) {
1185 /* MCH_MeDisable */
1186 fmsba->data[0] |= 1;
1187 /* MCH_AltMeDisable */
1188 fmsba->data[0] |= (1 << 7);
1189 /* ICH_MeDisable */
1190 fpsba->pchstrp[0] |= 1;
1191 } else {
1192 fmsba->data[0] &= ~1;
1193 fmsba->data[0] &= ~(1 << 7);
1194 fpsba->pchstrp[0] &= ~1;
1195 }
1196 } else {
1197 printf("%sting the AltMeDisable to %s Intel ME...\n",
1198 altmedisable?"Set":"Unset",
1199 altmedisable?"disable":"enable");
1200 if (altmedisable)
1201 fpsba->pchstrp[10] |= (1 << 7);
1202 else
1203 fpsba->pchstrp[10] &= ~(1 << 7);
1204 }
1205 }
1206}
1207
Jacob Garber595d9262019-06-27 17:33:10 -06001208static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001209 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001210{
Bill XIE612ec0e2017-08-30 16:10:27 +08001211 frba_t *frba = find_frba(image, size);
1212 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001213 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001214
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001215 region_t region = get_region(frba, region_type);
1216 if (region.size <= 0xfff) {
1217 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1218 region_name(region_type));
1219 exit(EXIT_FAILURE);
1220 }
1221
Scott Duplichanf2c98372014-12-12 21:03:06 -06001222 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001223 if (region_fd == -1) {
1224 perror("Could not open file");
1225 exit(EXIT_FAILURE);
1226 }
1227 struct stat buf;
1228 if (fstat(region_fd, &buf) == -1) {
1229 perror("Could not stat file");
1230 exit(EXIT_FAILURE);
1231 }
1232 int region_size = buf.st_size;
1233
1234 printf("File %s is %d bytes\n", region_fname, region_size);
1235
1236 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001237 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001238 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1239 " bytes. Not injecting.\n",
1240 region_name(region_type), region.size,
1241 region.size, region_size, region_size);
1242 exit(EXIT_FAILURE);
1243 }
1244
1245 int offset = 0;
1246 if ((region_type == 1) && (region_size < region.size)) {
1247 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1248 " bytes. Padding before injecting.\n",
1249 region_name(region_type), region.size,
1250 region.size, region_size, region_size);
1251 offset = region.size - region_size;
1252 memset(image + region.base, 0xff, offset);
1253 }
1254
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001255 if (size < region.base + offset + region_size) {
1256 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1257 size, region.base + offset + region_size);
1258 exit(EXIT_FAILURE);
1259 }
1260
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001261 if (read(region_fd, image + region.base + offset, region_size)
1262 != region_size) {
1263 perror("Could not read file");
1264 exit(EXIT_FAILURE);
1265 }
1266
1267 close(region_fd);
1268
1269 printf("Adding %s as the %s section of %s\n",
1270 region_fname, region_name(region_type), filename);
1271 write_image(filename, image, size);
1272}
1273
Jacob Garber595d9262019-06-27 17:33:10 -06001274static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001275{
1276 unsigned int y = 1;
1277 if (x == 0)
1278 return 0;
1279 while (y <= x)
1280 y = y << 1;
1281
1282 return y;
1283}
1284
1285/**
1286 * Determine if two memory regions overlap.
1287 *
1288 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001289 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001290 * @return 1 if the two regions overlap
1291 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001292static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001293{
Bill XIEfa5f9942017-09-12 11:22:29 +08001294 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001295 return 0;
1296
Nico Huber844eda02019-01-05 00:06:19 +01001297 /* r1 should be either completely below or completely above r2 */
1298 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001299}
1300
Jacob Garber595d9262019-06-27 17:33:10 -06001301static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001302 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001303{
1304 FILE *romlayout;
1305 char tempstr[256];
1306 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001307 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001308 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001309 region_t current_regions[MAX_REGIONS];
1310 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001311 int new_extent = 0;
1312 char *new_image;
1313
1314 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001315 frba_t *frba = find_frba(image, size);
1316 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001317 exit(EXIT_FAILURE);
1318
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001319 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001320 current_regions[i] = get_region(frba, i);
1321 new_regions[i] = get_region(frba, i);
1322 }
1323
1324 /* read new layout */
1325 romlayout = fopen(layout_fname, "r");
1326
1327 if (!romlayout) {
1328 perror("Could not read layout file.\n");
1329 exit(EXIT_FAILURE);
1330 }
1331
1332 while (!feof(romlayout)) {
1333 char *tstr1, *tstr2;
1334
Patrick Georgi802ad522014-08-09 17:12:23 +02001335 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001336 layout_region_name))
1337 continue;
1338
1339 region_number = region_num(layout_region_name);
1340 if (region_number < 0)
1341 continue;
1342
1343 tstr1 = strtok(tempstr, ":");
1344 tstr2 = strtok(NULL, ":");
1345 if (!tstr1 || !tstr2) {
1346 fprintf(stderr, "Could not parse layout file.\n");
1347 exit(EXIT_FAILURE);
1348 }
1349 new_regions[region_number].base = strtol(tstr1,
1350 (char **)NULL, 16);
1351 new_regions[region_number].limit = strtol(tstr2,
1352 (char **)NULL, 16);
1353 new_regions[region_number].size =
1354 new_regions[region_number].limit -
1355 new_regions[region_number].base + 1;
1356
1357 if (new_regions[region_number].size < 0)
1358 new_regions[region_number].size = 0;
1359 }
1360 fclose(romlayout);
1361
1362 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001363 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001364 if (new_regions[i].size == 0)
1365 continue;
1366
1367 if (new_regions[i].size < current_regions[i].size) {
1368 printf("DANGER: Region %s is shrinking.\n",
1369 region_name(i));
1370 printf(" The region will be truncated to fit.\n");
1371 printf(" This may result in an unusable image.\n");
1372 }
1373
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001374 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001375 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001376 fprintf(stderr, "Regions would overlap.\n");
1377 exit(EXIT_FAILURE);
1378 }
1379 }
1380
1381 /* detect if the image size should grow */
1382 if (new_extent < new_regions[i].limit)
1383 new_extent = new_regions[i].limit;
1384 }
1385
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001386 /* check if the image is actually a Flash Descriptor region */
1387 if (size == new_regions[0].size) {
1388 printf("The image is a single Flash Descriptor:\n");
1389 printf(" Only the descriptor will be modified\n");
1390 new_extent = size;
1391 } else {
1392 new_extent = next_pow2(new_extent - 1);
1393 if (new_extent != size) {
1394 printf("The image has changed in size.\n");
1395 printf("The old image is %d bytes.\n", size);
1396 printf("The new image is %d bytes.\n", new_extent);
1397 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001398 }
1399
1400 /* copy regions to a new image */
1401 new_image = malloc(new_extent);
1402 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001403 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001404 int copy_size = new_regions[i].size;
1405 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001406 const region_t *current = &current_regions[i];
1407 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001408
Bill XIEfa5f9942017-09-12 11:22:29 +08001409 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001410 continue;
1411
Bill XIEfa5f9942017-09-12 11:22:29 +08001412 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001413 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001414 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001415 if (i == REGION_BIOS)
1416 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001417 }
1418
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001419 if ((i == REGION_BIOS) && (new->size < current->size)) {
1420 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001421 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001422 }
1423
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001424 if (size < current->base + offset_current + copy_size) {
1425 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1426 region_name(i));
1427 continue;
1428 };
1429
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001430 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1431 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001432 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1433 offset_current, current->limit, current->size);
1434 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1435 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001436
Bill XIEfa5f9942017-09-12 11:22:29 +08001437 memcpy(new_image + new->base + offset_new,
1438 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001439 copy_size);
1440 }
1441
1442 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001443 frba = find_frba(new_image, new_extent);
1444 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001445 exit(EXIT_FAILURE);
1446
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001447 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001448 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001449 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001450
1451 write_image(filename, new_image, new_extent);
1452 free(new_image);
1453}
1454
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001455static void print_version(void)
1456{
1457 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1458 printf("Copyright (C) 2011 Google Inc.\n\n");
1459 printf
1460 ("This program is free software: you can redistribute it and/or modify\n"
1461 "it under the terms of the GNU General Public License as published by\n"
1462 "the Free Software Foundation, version 2 of the License.\n\n"
1463 "This program is distributed in the hope that it will be useful,\n"
1464 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1465 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001466 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001467}
1468
1469static void print_usage(const char *name)
1470{
1471 printf("usage: %s [-vhdix?] <filename>\n", name);
1472 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001473 " -d | --dump: dump intel firmware descriptor\n"
1474 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1475 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1476 " -x | --extract: extract intel fd modules\n"
1477 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1478 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001479 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001480 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1481 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1482 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1483 " can only be used once per run:\n"
1484 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1485 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1486 " Dual Output Fast Read Support\n"
1487 " -l | --lock Lock firmware descriptor and ME region\n"
1488 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001489 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1490 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001491 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301492 " adl - Alder Lake\n"
1493 " aplk - Apollo Lake\n"
1494 " cnl - Cannon Lake\n"
1495 " glk - Gemini Lake\n"
1496 " icl - Ice Lake\n"
1497 " jsl - Jasper Lake\n"
1498 " sklkbl - Sky Lake/Kaby Lake\n"
1499 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001500 " -S | --setpchstrap Write a PCH strap\n"
1501 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001502 " -v | --version: print the version\n"
1503 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001504 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1505 "\n");
1506}
1507
1508int main(int argc, char *argv[])
1509{
1510 int opt, option_index = 0;
1511 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001512 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001513 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001514 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001515 char *region_type_string = NULL, *region_fname = NULL;
1516 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001517 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001518 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001519 unsigned int value = 0;
1520 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001521 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001522 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1523
Bill XIEfa5f9942017-09-12 11:22:29 +08001524 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001525 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001526 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001527 {"extract", 0, NULL, 'x'},
1528 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001529 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001530 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001531 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001532 {"density", 1, NULL, 'D'},
1533 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001534 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001535 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001536 {"lock", 0, NULL, 'l'},
1537 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001538 {"version", 0, NULL, 'v'},
1539 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001540 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001541 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001542 {"setpchstrap", 1, NULL, 'S'},
1543 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001544 {0, 0, 0, 0}
1545 };
1546
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001547 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 -07001548 long_options, &option_index)) != EOF) {
1549 switch (opt) {
1550 case 'd':
1551 mode_dump = 1;
1552 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001553 case 'S':
1554 mode_setstrap = 1;
1555 pchstrap = strtoul(optarg, NULL, 0);
1556 break;
1557 case 'V':
1558 value = strtoul(optarg, NULL, 0);
1559 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001560 case 'f':
1561 mode_layout = 1;
1562 layout_fname = strdup(optarg);
1563 if (!layout_fname) {
1564 fprintf(stderr, "No layout file specified\n");
1565 print_usage(argv[0]);
1566 exit(EXIT_FAILURE);
1567 }
1568 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001569 case 'x':
1570 mode_extract = 1;
1571 break;
1572 case 'i':
1573 // separate type and file name
1574 region_type_string = strdup(optarg);
1575 region_fname = strchr(region_type_string, ':');
1576 if (!region_fname) {
1577 print_usage(argv[0]);
1578 exit(EXIT_FAILURE);
1579 }
1580 region_fname[0] = '\0';
1581 region_fname++;
1582 // Descriptor, BIOS, ME, GbE, Platform
1583 // valid type?
1584 if (!strcasecmp("Descriptor", region_type_string))
1585 region_type = 0;
1586 else if (!strcasecmp("BIOS", region_type_string))
1587 region_type = 1;
1588 else if (!strcasecmp("ME", region_type_string))
1589 region_type = 2;
1590 else if (!strcasecmp("GbE", region_type_string))
1591 region_type = 3;
1592 else if (!strcasecmp("Platform", region_type_string))
1593 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001594 else if (!strcasecmp("EC", region_type_string))
1595 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001596 if (region_type == -1) {
1597 fprintf(stderr, "No such region type: '%s'\n\n",
1598 region_type_string);
1599 print_usage(argv[0]);
1600 exit(EXIT_FAILURE);
1601 }
1602 mode_inject = 1;
1603 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001604 case 'n':
1605 mode_newlayout = 1;
1606 layout_fname = strdup(optarg);
1607 if (!layout_fname) {
1608 fprintf(stderr, "No layout file specified\n");
1609 print_usage(argv[0]);
1610 exit(EXIT_FAILURE);
1611 }
1612 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001613 case 'O':
1614 new_filename = strdup(optarg);
1615 if (!new_filename) {
1616 fprintf(stderr, "No output filename specified\n");
1617 print_usage(argv[0]);
1618 exit(EXIT_FAILURE);
1619 }
1620 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001621 case 'D':
1622 mode_density = 1;
1623 new_density = strtoul(optarg, NULL, 0);
1624 switch (new_density) {
1625 case 512:
1626 new_density = COMPONENT_DENSITY_512KB;
1627 break;
1628 case 1:
1629 new_density = COMPONENT_DENSITY_1MB;
1630 break;
1631 case 2:
1632 new_density = COMPONENT_DENSITY_2MB;
1633 break;
1634 case 4:
1635 new_density = COMPONENT_DENSITY_4MB;
1636 break;
1637 case 8:
1638 new_density = COMPONENT_DENSITY_8MB;
1639 break;
1640 case 16:
1641 new_density = COMPONENT_DENSITY_16MB;
1642 break;
1643 case 32:
1644 new_density = COMPONENT_DENSITY_32MB;
1645 break;
1646 case 64:
1647 new_density = COMPONENT_DENSITY_64MB;
1648 break;
1649 case 0:
1650 new_density = COMPONENT_DENSITY_UNUSED;
1651 break;
1652 default:
1653 printf("error: Unknown density\n");
1654 print_usage(argv[0]);
1655 exit(EXIT_FAILURE);
1656 }
1657 break;
1658 case 'C':
1659 selected_chip = strtol(optarg, NULL, 0);
1660 if (selected_chip > 2) {
1661 fprintf(stderr, "error: Invalid chip selection\n");
1662 print_usage(argv[0]);
1663 exit(EXIT_FAILURE);
1664 }
1665 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001666 case 'M':
1667 mode_altmedisable = 1;
1668 altmedisable = strtol(optarg, NULL, 0);
1669 if (altmedisable > 1) {
1670 fprintf(stderr, "error: Illegal value\n");
1671 print_usage(argv[0]);
1672 exit(EXIT_FAILURE);
1673 }
1674 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001675 case 's':
1676 // Parse the requested SPI frequency
1677 inputfreq = strtol(optarg, NULL, 0);
1678 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001679 case 17:
1680 spifreq = SPI_FREQUENCY_17MHZ;
1681 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001682 case 20:
1683 spifreq = SPI_FREQUENCY_20MHZ;
1684 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001685 case 30:
1686 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1687 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001688 case 33:
1689 spifreq = SPI_FREQUENCY_33MHZ;
1690 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001691 case 48:
1692 spifreq = SPI_FREQUENCY_48MHZ;
1693 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001694 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001695 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001696 break;
1697 default:
1698 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1699 inputfreq);
1700 print_usage(argv[0]);
1701 exit(EXIT_FAILURE);
1702 }
1703 mode_spifreq = 1;
1704 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001705 case 'e':
1706 mode_em100 = 1;
1707 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001708 case 'l':
1709 mode_locked = 1;
1710 if (mode_unlocked == 1) {
1711 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1712 exit(EXIT_FAILURE);
1713 }
1714 break;
1715 case 'u':
1716 mode_unlocked = 1;
1717 if (mode_locked == 1) {
1718 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1719 exit(EXIT_FAILURE);
1720 }
1721 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001722 case 'p':
1723 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001724 platform = PLATFORM_APL;
1725 } else if (!strcmp(optarg, "cnl")) {
1726 platform = PLATFORM_CNL;
1727 } else if (!strcmp(optarg, "glk")) {
1728 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301729 } else if (!strcmp(optarg, "icl")) {
1730 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301731 } else if (!strcmp(optarg, "jsl")) {
1732 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001733 } else if (!strcmp(optarg, "sklkbl")) {
1734 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001735 } else if (!strcmp(optarg, "tgl")) {
1736 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301737 } else if (!strcmp(optarg, "adl")) {
1738 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001739 } else {
1740 fprintf(stderr, "Unknown platform: %s\n", optarg);
1741 exit(EXIT_FAILURE);
1742 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001743 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001744 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001745 case 't':
1746 mode_validate = 1;
1747 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001748 case 'v':
1749 print_version();
1750 exit(EXIT_SUCCESS);
1751 break;
1752 case 'h':
1753 case '?':
1754 default:
1755 print_usage(argv[0]);
1756 exit(EXIT_SUCCESS);
1757 break;
1758 }
1759 }
1760
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001761 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001762 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001763 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001764 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001765 print_usage(argv[0]);
1766 exit(EXIT_FAILURE);
1767 }
1768
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001769 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001770 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001771 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001772 fprintf(stderr, "You need to specify a mode.\n\n");
1773 print_usage(argv[0]);
1774 exit(EXIT_FAILURE);
1775 }
1776
1777 if (optind + 1 != argc) {
1778 fprintf(stderr, "You need to specify a file.\n\n");
1779 print_usage(argv[0]);
1780 exit(EXIT_FAILURE);
1781 }
1782
1783 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001784 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001785 if (bios_fd == -1) {
1786 perror("Could not open file");
1787 exit(EXIT_FAILURE);
1788 }
1789 struct stat buf;
1790 if (fstat(bios_fd, &buf) == -1) {
1791 perror("Could not stat file");
1792 exit(EXIT_FAILURE);
1793 }
1794 int size = buf.st_size;
1795
1796 printf("File %s is %d bytes\n", filename, size);
1797
1798 char *image = malloc(size);
1799 if (!image) {
1800 printf("Out of memory.\n");
1801 exit(EXIT_FAILURE);
1802 }
1803
1804 if (read(bios_fd, image, size) != size) {
1805 perror("Could not read file");
1806 exit(EXIT_FAILURE);
1807 }
1808
1809 close(bios_fd);
1810
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001811 // generate new filename
1812 if (new_filename == NULL) {
1813 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1814 if (!new_filename) {
1815 printf("Out of memory.\n");
1816 exit(EXIT_FAILURE);
1817 }
1818 // - 5: leave room for ".new\0"
1819 strcpy(new_filename, filename);
1820 strcat(new_filename, ".new");
1821 }
1822
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001823 check_ifd_version(image, size);
1824
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001825 if (mode_dump)
1826 dump_fd(image, size);
1827
Chris Douglass03ce0142014-02-26 13:30:13 -05001828 if (mode_layout)
1829 dump_layout(image, size, layout_fname);
1830
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001831 if (mode_extract)
1832 write_regions(image, size);
1833
Mathew Kingc7ddc992019-08-08 14:59:25 -06001834 if (mode_validate)
1835 validate_layout(image, size);
1836
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001837 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001838 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001839 region_fname);
1840
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001841 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001842 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001843
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001844 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001845 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001846
Jan Tatjefa317512016-03-11 00:52:07 +01001847 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001848 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001849
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001850 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001851 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001852
Alexander Couzensd12ea112016-09-10 13:33:05 +02001853 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001854 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001855
1856 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001857 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001858
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001859 if (mode_setstrap) {
1860 fpsba_t *fpsba = find_fpsba(image, size);
1861 const fdbar_t *fdb = find_fd(image, size);
1862 set_pchstrap(fpsba, fdb, pchstrap, value);
1863 write_image(new_filename, image, size);
1864 }
1865
Bill XIEb3e15a22017-09-07 18:34:50 +08001866 if (mode_altmedisable) {
1867 fpsba_t *fpsba = find_fpsba(image, size);
1868 fmsba_t *fmsba = find_fmsba(image, size);
1869 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001870 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001871 }
1872
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001873 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001874 free(image);
1875
1876 return 0;
1877}