blob: 56e05fe21bc254b8255f940d78ac16bc815dbdd1 [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
Subrata Banik26058dc2020-08-26 15:12:16 +0530516static int is_platform_with_pch(void)
517{
518 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
519 return 1;
520
521 return 0;
522}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530523
524/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
525static int is_platform_with_100x_series_pch(void)
526{
527 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
528 chipset <= CHIPSET_500_SERIES_TIGER_POINT)
529 return 1;
530
531 return 0;
532}
533
Bill XIEfa5f9942017-09-12 11:22:29 +0800534static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700535{
536 printf("\nFound Component Section\n");
537 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700538 printf(" Dual Output Fast Read Support: %ssupported\n",
539 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700540 printf(" Read ID/Read Status Clock Frequency: ");
541 decode_spi_frequency((fcba->flcomp >> 27) & 7);
542 printf("\n Write/Erase Clock Frequency: ");
543 decode_spi_frequency((fcba->flcomp >> 24) & 7);
544 printf("\n Fast Read Clock Frequency: ");
545 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700546 printf("\n Fast Read Support: %ssupported",
547 (fcba->flcomp & (1 << 20))?"":"not ");
548 printf("\n Read Clock Frequency: ");
549 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700550
551 switch (ifd_version) {
552 case IFD_VERSION_1:
553 printf("\n Component 2 Density: ");
554 decode_component_density((fcba->flcomp >> 3) & 7);
555 printf("\n Component 1 Density: ");
556 decode_component_density(fcba->flcomp & 7);
557 break;
558 case IFD_VERSION_2:
559 printf("\n Component 2 Density: ");
560 decode_component_density((fcba->flcomp >> 4) & 0xf);
561 printf("\n Component 1 Density: ");
562 decode_component_density(fcba->flcomp & 0xf);
563 break;
564 }
565
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700566 printf("\n");
567 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700568 printf(" Invalid Instruction 3: 0x%02x\n",
569 (fcba->flill >> 24) & 0xff);
570 printf(" Invalid Instruction 2: 0x%02x\n",
571 (fcba->flill >> 16) & 0xff);
572 printf(" Invalid Instruction 1: 0x%02x\n",
573 (fcba->flill >> 8) & 0xff);
574 printf(" Invalid Instruction 0: 0x%02x\n",
575 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530576 if (is_platform_with_100x_series_pch()) {
577 printf("FLILL1 0x%08x\n", fcba->flpb);
578 printf(" Invalid Instruction 7: 0x%02x\n",
579 (fcba->flpb >> 24) & 0xff);
580 printf(" Invalid Instruction 6: 0x%02x\n",
581 (fcba->flpb >> 16) & 0xff);
582 printf(" Invalid Instruction 5: 0x%02x\n",
583 (fcba->flpb >> 8) & 0xff);
584 printf(" Invalid Instruction 4: 0x%02x\n",
585 fcba->flpb & 0xff);
586 } else {
587 printf("FLPB 0x%08x\n", fcba->flpb);
588 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
589 (fcba->flpb & 0xfff) << 12);
590 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700591}
592
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200593static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700594{
Bill XIE4651d452017-09-12 11:54:48 +0800595 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200596 /* SoC Strap Length, aka PSL, aka ISL */
597 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
598
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700599 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200600 for (i = 0; i < SSL; i++)
601 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800602
603 if (ifd_version >= IFD_VERSION_2) {
604 printf("HAP bit is %sset\n",
605 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
606 } else if (chipset >= CHIPSET_ICH8
607 && chipset <= CHIPSET_ICH10) {
608 printf("ICH_MeDisable bit is %sset\n",
609 fpsba->pchstrp[0] & 1 ? "" : "not ");
610 } else {
611 printf("AltMeDisable bit is %sset\n",
612 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
613 }
614
Bill XIE4651d452017-09-12 11:54:48 +0800615 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700616}
617
618static void decode_flmstr(uint32_t flmstr)
619{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700620 int wr_shift, rd_shift;
621 if (ifd_version >= IFD_VERSION_2) {
622 wr_shift = FLMSTR_WR_SHIFT_V2;
623 rd_shift = FLMSTR_RD_SHIFT_V2;
624 } else {
625 wr_shift = FLMSTR_WR_SHIFT_V1;
626 rd_shift = FLMSTR_RD_SHIFT_V1;
627 }
628
629 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700630 if (ifd_version >= IFD_VERSION_2)
631 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700632 (flmstr & (1 << (wr_shift + 8))) ?
633 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700634 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700635 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700636 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700637 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700638 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700639 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700640 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700641 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700642 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700643 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700644
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700645 if (ifd_version >= IFD_VERSION_2)
646 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700647 (flmstr & (1 << (rd_shift + 8))) ?
648 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700649 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700650 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700651 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700652 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700653 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700654 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700655 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700656 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700657 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700658 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700659
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700660 /* Requestor ID doesn't exist for ifd 2 */
661 if (ifd_version < IFD_VERSION_2)
662 printf(" Requester ID: 0x%04x\n\n",
663 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700664}
665
Bill XIEfa5f9942017-09-12 11:22:29 +0800666static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700667{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700668 printf("Found Master Section\n");
669 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
670 decode_flmstr(fmba->flmstr1);
671 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
672 decode_flmstr(fmba->flmstr2);
673 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
674 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700675 if (ifd_version >= IFD_VERSION_2) {
676 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
677 decode_flmstr(fmba->flmstr5);
678 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700679}
680
Bill XIEfa5f9942017-09-12 11:22:29 +0800681static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700682{
Bill XIE612ec0e2017-08-30 16:10:27 +0800683 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700684 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800685 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
686 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800687
688 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
689 printf("MCH_MeDisable bit is %sset\n",
690 fmsba->data[0] & 1 ? "" : "not ");
691 printf("MCH_AltMeDisable bit is %sset\n",
692 fmsba->data[0] & (1 << 7) ? "" : "not ");
693 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700694}
695
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700696static void dump_jid(uint32_t jid)
697{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100698 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700699 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100700 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200701 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100702 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200703 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700704}
705
706static void dump_vscc(uint32_t vscc)
707{
708 printf(" Lower Erase Opcode: 0x%02x\n",
709 vscc >> 24);
710 printf(" Lower Write Enable on Write Status: 0x%02x\n",
711 vscc & (1 << 20) ? 0x06 : 0x50);
712 printf(" Lower Write Status Required: %s\n",
713 vscc & (1 << 19) ? "Yes" : "No");
714 printf(" Lower Write Granularity: %d bytes\n",
715 vscc & (1 << 18) ? 64 : 1);
716 printf(" Lower Block / Sector Erase Size: ");
717 switch ((vscc >> 16) & 0x3) {
718 case 0:
719 printf("256 Byte\n");
720 break;
721 case 1:
722 printf("4KB\n");
723 break;
724 case 2:
725 printf("8KB\n");
726 break;
727 case 3:
728 printf("64KB\n");
729 break;
730 }
731
732 printf(" Upper Erase Opcode: 0x%02x\n",
733 (vscc >> 8) & 0xff);
734 printf(" Upper Write Enable on Write Status: 0x%02x\n",
735 vscc & (1 << 4) ? 0x06 : 0x50);
736 printf(" Upper Write Status Required: %s\n",
737 vscc & (1 << 3) ? "Yes" : "No");
738 printf(" Upper Write Granularity: %d bytes\n",
739 vscc & (1 << 2) ? 64 : 1);
740 printf(" Upper Block / Sector Erase Size: ");
741 switch (vscc & 0x3) {
742 case 0:
743 printf("256 Byte\n");
744 break;
745 case 1:
746 printf("4KB\n");
747 break;
748 case 2:
749 printf("8KB\n");
750 break;
751 case 3:
752 printf("64KB\n");
753 break;
754 }
755}
756
Bill XIEfa5f9942017-09-12 11:22:29 +0800757static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700758{
759 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200760 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
761 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700762
763 printf("ME VSCC table:\n");
764 for (i = 0; i < num; i++) {
765 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
766 dump_jid(vtba->entry[i].jid);
767 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
768 dump_vscc(vtba->entry[i].vscc);
769 }
770 printf("\n");
771}
772
Bill XIEfa5f9942017-09-12 11:22:29 +0800773static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700774{
775 int i, j;
776 printf("OEM Section:\n");
777 for (i = 0; i < 4; i++) {
778 printf("%02x:", i << 4);
779 for (j = 0; j < 16; j++)
780 printf(" %02x", oem[(i<<4)+j]);
781 printf ("\n");
782 }
783 printf ("\n");
784}
785
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700786static void dump_fd(char *image, int size)
787{
Bill XIE612ec0e2017-08-30 16:10:27 +0800788 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700789 if (!fdb)
790 exit(EXIT_FAILURE);
791
Subrata Banik26058dc2020-08-26 15:12:16 +0530792 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
793 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700794 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530795 if (!is_platform_with_100x_series_pch())
796 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700797 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
798 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
799 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
800
801 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530802 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
803 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700804 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
805 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
806 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
807
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530808 if (!is_platform_with_100x_series_pch()) {
809 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
810 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
811 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
812 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700813
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530814 if (chipset == CHIPSET_500_SERIES_TIGER_POINT) {
815 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
816 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
817 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
818 }
819
Stefan Tauner0d226142018-08-05 18:56:53 +0200820 char *flumap = find_flumap(image, size);
821 uint32_t flumap1 = *(uint32_t *)flumap;
822 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700823 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200824 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700825 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200826 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700827 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200828 (image + ((flumap1 & 0xff) << 4)),
829 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800830 dump_oem((const uint8_t *)image + 0xf00);
831
832 const frba_t *frba = find_frba(image, size);
833 const fcba_t *fcba = find_fcba(image, size);
834 const fpsba_t *fpsba = find_fpsba(image, size);
835 const fmba_t *fmba = find_fmba(image, size);
836 const fmsba_t *fmsba = find_fmsba(image, size);
837
838 if (frba && fcba && fpsba && fmba && fmsba) {
839 dump_frba(frba);
840 dump_fcba(fcba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200841 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800842 dump_fmba(fmba);
843 dump_fmsba(fmsba);
844 } else {
845 printf("FD is corrupted!\n");
846 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700847}
848
Bill XIEfa5f9942017-09-12 11:22:29 +0800849static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500850{
Bill XIE612ec0e2017-08-30 16:10:27 +0800851 const frba_t *frba = find_frba(image, size);
852 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500853 exit(EXIT_FAILURE);
854
Bill XIE612ec0e2017-08-30 16:10:27 +0800855 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500856}
857
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700858static void write_regions(char *image, int size)
859{
Bill XIEfa5f9942017-09-12 11:22:29 +0800860 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800861 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700862
Bill XIE612ec0e2017-08-30 16:10:27 +0800863 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700864 exit(EXIT_FAILURE);
865
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700866 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700867 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700868 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700869 if (region.size > 0) {
870 int region_fd;
871 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600872 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700873 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200874 if (region_fd < 0) {
875 perror("Error while trying to open file");
876 exit(EXIT_FAILURE);
877 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700878 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700879 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700880 close(region_fd);
881 }
882 }
883}
884
Mathew Kingc7ddc992019-08-08 14:59:25 -0600885static void validate_layout(char *image, int size)
886{
887 uint i, errors = 0;
888 struct fmap *fmap;
889 long int fmap_loc = fmap_find((uint8_t *)image, size);
890 const frba_t *frba = find_frba(image, size);
891
892 if (fmap_loc < 0 || !frba)
893 exit(EXIT_FAILURE);
894
895 fmap = (struct fmap *)(image + fmap_loc);
896
897 for (i = 0; i < max_regions; i++) {
898 if (region_names[i].fmapname == NULL)
899 continue;
900
901 region_t region = get_region(frba, i);
902
903 if (region.size == 0)
904 continue;
905
906 const struct fmap_area *area =
907 fmap_find_area(fmap, region_names[i].fmapname);
908
909 if (!area)
910 continue;
911
912 if ((uint)region.base != area->offset ||
913 (uint)region.size != area->size) {
914 printf("Region mismatch between %s and %s\n",
915 region_names[i].terse, area->name);
916 printf(" Descriptor region %s:\n", region_names[i].terse);
917 printf(" offset: 0x%08x\n", region.base);
918 printf(" length: 0x%08x\n", region.size);
919 printf(" FMAP area %s:\n", area->name);
920 printf(" offset: 0x%08x\n", area->offset);
921 printf(" length: 0x%08x\n", area->size);
922 errors++;
923 }
924 }
925
926 if (errors > 0)
927 exit(EXIT_FAILURE);
928}
929
Bill XIEfa5f9942017-09-12 11:22:29 +0800930static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700931{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700932 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100933 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700934
935 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100936 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600937 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700938 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200939 if (new_fd < 0) {
940 perror("Error while trying to open file");
941 exit(EXIT_FAILURE);
942 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700943 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700944 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700945 close(new_fd);
946}
947
Bill XIEfa5f9942017-09-12 11:22:29 +0800948static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700949 enum spi_frequency freq)
950{
Bill XIE612ec0e2017-08-30 16:10:27 +0800951 fcba_t *fcba = find_fcba(image, size);
952 if (!fcba)
953 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700954
955 /* clear bits 21-29 */
956 fcba->flcomp &= ~0x3fe00000;
957 /* Read ID and Read Status Clock Frequency */
958 fcba->flcomp |= freq << 27;
959 /* Write and Erase Clock Frequency */
960 fcba->flcomp |= freq << 24;
961 /* Fast Read Clock Frequency */
962 fcba->flcomp |= freq << 21;
963
964 write_image(filename, image, size);
965}
966
Bill XIEfa5f9942017-09-12 11:22:29 +0800967static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700968{
Bill XIE612ec0e2017-08-30 16:10:27 +0800969 fcba_t *fcba = find_fcba(image, size);
970 if (!fcba)
971 exit(EXIT_FAILURE);
972
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700973 int freq;
974
975 switch (ifd_version) {
976 case IFD_VERSION_1:
977 freq = SPI_FREQUENCY_20MHZ;
978 break;
979 case IFD_VERSION_2:
980 freq = SPI_FREQUENCY_17MHZ;
981 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700982 default:
983 freq = SPI_FREQUENCY_17MHZ;
984 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700985 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700986
987 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700988 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700989}
990
Bill XIEfa5f9942017-09-12 11:22:29 +0800991static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100992 unsigned int density)
993{
Bill XIE612ec0e2017-08-30 16:10:27 +0800994 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200995 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800996 if (!fcba)
997 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100998
999 printf("Setting chip density to ");
1000 decode_component_density(density);
1001 printf("\n");
1002
1003 switch (ifd_version) {
1004 case IFD_VERSION_1:
1005 /* fail if selected density is not supported by this version */
1006 if ( (density == COMPONENT_DENSITY_32MB) ||
1007 (density == COMPONENT_DENSITY_64MB) ||
1008 (density == COMPONENT_DENSITY_UNUSED) ) {
1009 printf("error: Selected density not supported in IFD version 1.\n");
1010 exit(EXIT_FAILURE);
1011 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001012 mask = 0x7;
1013 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001014 break;
1015 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001016 mask = 0xf;
1017 chip2_offset = 4;
1018 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001019 default:
1020 printf("error: Unknown IFD version\n");
1021 exit(EXIT_FAILURE);
1022 break;
1023 }
1024
1025 /* clear chip density for corresponding chip */
1026 switch (selected_chip) {
1027 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001028 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001029 break;
1030 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001031 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001032 break;
1033 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001034 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001035 break;
1036 }
1037
1038 /* set the new density */
1039 if (selected_chip == 1 || selected_chip == 0)
1040 fcba->flcomp |= (density); /* first chip */
1041 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001042 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001043
1044 write_image(filename, image, size);
1045}
1046
Duncan Laurie7775d672019-06-06 13:39:26 -07001047static int check_region(const frba_t *frba, unsigned int region_type)
1048{
1049 region_t region;
1050
1051 if (!frba)
1052 return 0;
1053
1054 region = get_region(frba, region_type);
1055 return !!((region.base < region.limit) && (region.size > 0));
1056}
1057
Bill XIEfa5f9942017-09-12 11:22:29 +08001058static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001059{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001060 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001061 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001062 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001063 if (!fmba)
1064 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001065
1066 if (ifd_version >= IFD_VERSION_2) {
1067 wr_shift = FLMSTR_WR_SHIFT_V2;
1068 rd_shift = FLMSTR_RD_SHIFT_V2;
1069
1070 /* Clear non-reserved bits */
1071 fmba->flmstr1 &= 0xff;
1072 fmba->flmstr2 &= 0xff;
1073 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001074 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001075 } else {
1076 wr_shift = FLMSTR_WR_SHIFT_V1;
1077 rd_shift = FLMSTR_RD_SHIFT_V1;
1078
1079 fmba->flmstr1 = 0;
1080 fmba->flmstr2 = 0;
1081 /* Requestor ID */
1082 fmba->flmstr3 = 0x118;
1083 }
1084
Andrey Petrov96ecb772016-10-31 19:31:54 -07001085 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001086 case PLATFORM_APL:
1087 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001088 /* CPU/BIOS can read descriptor and BIOS */
1089 fmba->flmstr1 |= 0x3 << rd_shift;
1090 /* CPU/BIOS can write BIOS */
1091 fmba->flmstr1 |= 0x2 << wr_shift;
1092 /* TXE can read descriptor, BIOS and Device Expansion */
1093 fmba->flmstr2 |= 0x23 << rd_shift;
1094 /* TXE can only write Device Expansion */
1095 fmba->flmstr2 |= 0x20 << wr_shift;
1096 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001097 case PLATFORM_CNL:
1098 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001099 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001100 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301101 case PLATFORM_JSL:
Subrata Banik46f80732020-03-14 15:01:42 +05301102 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001103 /* CPU/BIOS can read descriptor and BIOS. */
1104 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1105 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1106 /* CPU/BIOS can write BIOS. */
1107 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1108 /* ME can read descriptor and ME. */
1109 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1110 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001111 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001112 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1113 if (check_region(frba, REGION_GBE)) {
1114 /* BIOS can read/write GbE. */
1115 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1116 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1117 /* ME can read GbE. */
1118 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1119 /* GbE can read descriptor and read/write GbE.. */
1120 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1121 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1122 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1123 }
1124 if (check_region(frba, REGION_PDR)) {
1125 /* BIOS can read/write PDR. */
1126 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1127 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1128 }
1129 if (check_region(frba, REGION_EC)) {
1130 /* BIOS can read EC. */
1131 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1132 /* EC can read descriptor and read/write EC. */
1133 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1134 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1135 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1136 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001137 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001138 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001139 /* CPU/BIOS can read descriptor and BIOS. */
1140 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1141 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1142 /* CPU/BIOS can write BIOS. */
1143 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1144 /* ME can read descriptor and ME. */
1145 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1146 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1147 /* ME can write ME. */
1148 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1149 if (check_region(frba, REGION_GBE)) {
1150 /* BIOS can read GbE. */
1151 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1152 /* BIOS can write GbE. */
1153 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1154 /* ME can read GbE. */
1155 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1156 /* ME can write GbE. */
1157 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1158 /* GbE can write GbE. */
1159 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1160 /* GbE can read GbE. */
1161 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1162 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001163 break;
1164 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001165
1166 write_image(filename, image, size);
1167}
1168
Bill XIEfa5f9942017-09-12 11:22:29 +08001169static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001170{
Bill XIE612ec0e2017-08-30 16:10:27 +08001171 fmba_t *fmba = find_fmba(image, size);
1172 if (!fmba)
1173 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001174
1175 if (ifd_version >= IFD_VERSION_2) {
1176 /* Access bits for each region are read: 19:8 write: 31:20 */
1177 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1178 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1179 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001180 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001181 } else {
1182 fmba->flmstr1 = 0xffff0000;
1183 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001184 /* Keep chipset specific Requester ID */
1185 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001186 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001187
1188 write_image(filename, image, size);
1189}
1190
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001191static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1192 const unsigned int value)
1193{
1194 if (!fpsba || !fdb) {
1195 fprintf(stderr, "Internal error\n");
1196 exit(EXIT_FAILURE);
1197 }
1198
1199 /* SoC Strap Length, aka PSL, aka ISL */
1200 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1201 if (strap >= SSL) {
1202 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1203 exit(EXIT_FAILURE);
1204 }
1205 fpsba->pchstrp[strap] = value;
1206}
1207
Bill XIEb3e15a22017-09-07 18:34:50 +08001208/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001209static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001210{
1211 if (ifd_version >= IFD_VERSION_2) {
1212 printf("%sting the HAP bit to %s Intel ME...\n",
1213 altmedisable?"Set":"Unset",
1214 altmedisable?"disable":"enable");
1215 if (altmedisable)
1216 fpsba->pchstrp[0] |= (1 << 16);
1217 else
1218 fpsba->pchstrp[0] &= ~(1 << 16);
1219 } else {
1220 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1221 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1222 "and MCH_AltMeDisable to %s Intel ME...\n",
1223 altmedisable?"Set":"Unset",
1224 altmedisable?"disable":"enable");
1225 if (altmedisable) {
1226 /* MCH_MeDisable */
1227 fmsba->data[0] |= 1;
1228 /* MCH_AltMeDisable */
1229 fmsba->data[0] |= (1 << 7);
1230 /* ICH_MeDisable */
1231 fpsba->pchstrp[0] |= 1;
1232 } else {
1233 fmsba->data[0] &= ~1;
1234 fmsba->data[0] &= ~(1 << 7);
1235 fpsba->pchstrp[0] &= ~1;
1236 }
1237 } else {
1238 printf("%sting the AltMeDisable to %s Intel ME...\n",
1239 altmedisable?"Set":"Unset",
1240 altmedisable?"disable":"enable");
1241 if (altmedisable)
1242 fpsba->pchstrp[10] |= (1 << 7);
1243 else
1244 fpsba->pchstrp[10] &= ~(1 << 7);
1245 }
1246 }
1247}
1248
Jacob Garber595d9262019-06-27 17:33:10 -06001249static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001250 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001251{
Bill XIE612ec0e2017-08-30 16:10:27 +08001252 frba_t *frba = find_frba(image, size);
1253 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001254 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001255
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001256 region_t region = get_region(frba, region_type);
1257 if (region.size <= 0xfff) {
1258 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1259 region_name(region_type));
1260 exit(EXIT_FAILURE);
1261 }
1262
Scott Duplichanf2c98372014-12-12 21:03:06 -06001263 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001264 if (region_fd == -1) {
1265 perror("Could not open file");
1266 exit(EXIT_FAILURE);
1267 }
1268 struct stat buf;
1269 if (fstat(region_fd, &buf) == -1) {
1270 perror("Could not stat file");
1271 exit(EXIT_FAILURE);
1272 }
1273 int region_size = buf.st_size;
1274
1275 printf("File %s is %d bytes\n", region_fname, region_size);
1276
1277 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001278 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001279 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1280 " bytes. Not injecting.\n",
1281 region_name(region_type), region.size,
1282 region.size, region_size, region_size);
1283 exit(EXIT_FAILURE);
1284 }
1285
1286 int offset = 0;
1287 if ((region_type == 1) && (region_size < region.size)) {
1288 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1289 " bytes. Padding before injecting.\n",
1290 region_name(region_type), region.size,
1291 region.size, region_size, region_size);
1292 offset = region.size - region_size;
1293 memset(image + region.base, 0xff, offset);
1294 }
1295
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001296 if (size < region.base + offset + region_size) {
1297 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1298 size, region.base + offset + region_size);
1299 exit(EXIT_FAILURE);
1300 }
1301
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001302 if (read(region_fd, image + region.base + offset, region_size)
1303 != region_size) {
1304 perror("Could not read file");
1305 exit(EXIT_FAILURE);
1306 }
1307
1308 close(region_fd);
1309
1310 printf("Adding %s as the %s section of %s\n",
1311 region_fname, region_name(region_type), filename);
1312 write_image(filename, image, size);
1313}
1314
Jacob Garber595d9262019-06-27 17:33:10 -06001315static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001316{
1317 unsigned int y = 1;
1318 if (x == 0)
1319 return 0;
1320 while (y <= x)
1321 y = y << 1;
1322
1323 return y;
1324}
1325
1326/**
1327 * Determine if two memory regions overlap.
1328 *
1329 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001330 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001331 * @return 1 if the two regions overlap
1332 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001333static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001334{
Bill XIEfa5f9942017-09-12 11:22:29 +08001335 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001336 return 0;
1337
Nico Huber844eda02019-01-05 00:06:19 +01001338 /* r1 should be either completely below or completely above r2 */
1339 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001340}
1341
Jacob Garber595d9262019-06-27 17:33:10 -06001342static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001343 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001344{
1345 FILE *romlayout;
1346 char tempstr[256];
1347 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001348 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001349 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001350 region_t current_regions[MAX_REGIONS];
1351 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001352 int new_extent = 0;
1353 char *new_image;
1354
1355 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001356 frba_t *frba = find_frba(image, size);
1357 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001358 exit(EXIT_FAILURE);
1359
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001360 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001361 current_regions[i] = get_region(frba, i);
1362 new_regions[i] = get_region(frba, i);
1363 }
1364
1365 /* read new layout */
1366 romlayout = fopen(layout_fname, "r");
1367
1368 if (!romlayout) {
1369 perror("Could not read layout file.\n");
1370 exit(EXIT_FAILURE);
1371 }
1372
1373 while (!feof(romlayout)) {
1374 char *tstr1, *tstr2;
1375
Patrick Georgi802ad522014-08-09 17:12:23 +02001376 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001377 layout_region_name))
1378 continue;
1379
1380 region_number = region_num(layout_region_name);
1381 if (region_number < 0)
1382 continue;
1383
1384 tstr1 = strtok(tempstr, ":");
1385 tstr2 = strtok(NULL, ":");
1386 if (!tstr1 || !tstr2) {
1387 fprintf(stderr, "Could not parse layout file.\n");
1388 exit(EXIT_FAILURE);
1389 }
1390 new_regions[region_number].base = strtol(tstr1,
1391 (char **)NULL, 16);
1392 new_regions[region_number].limit = strtol(tstr2,
1393 (char **)NULL, 16);
1394 new_regions[region_number].size =
1395 new_regions[region_number].limit -
1396 new_regions[region_number].base + 1;
1397
1398 if (new_regions[region_number].size < 0)
1399 new_regions[region_number].size = 0;
1400 }
1401 fclose(romlayout);
1402
1403 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001404 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001405 if (new_regions[i].size == 0)
1406 continue;
1407
1408 if (new_regions[i].size < current_regions[i].size) {
1409 printf("DANGER: Region %s is shrinking.\n",
1410 region_name(i));
1411 printf(" The region will be truncated to fit.\n");
1412 printf(" This may result in an unusable image.\n");
1413 }
1414
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001415 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001416 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001417 fprintf(stderr, "Regions would overlap.\n");
1418 exit(EXIT_FAILURE);
1419 }
1420 }
1421
1422 /* detect if the image size should grow */
1423 if (new_extent < new_regions[i].limit)
1424 new_extent = new_regions[i].limit;
1425 }
1426
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001427 /* check if the image is actually a Flash Descriptor region */
1428 if (size == new_regions[0].size) {
1429 printf("The image is a single Flash Descriptor:\n");
1430 printf(" Only the descriptor will be modified\n");
1431 new_extent = size;
1432 } else {
1433 new_extent = next_pow2(new_extent - 1);
1434 if (new_extent != size) {
1435 printf("The image has changed in size.\n");
1436 printf("The old image is %d bytes.\n", size);
1437 printf("The new image is %d bytes.\n", new_extent);
1438 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001439 }
1440
1441 /* copy regions to a new image */
1442 new_image = malloc(new_extent);
1443 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001444 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001445 int copy_size = new_regions[i].size;
1446 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001447 const region_t *current = &current_regions[i];
1448 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001449
Bill XIEfa5f9942017-09-12 11:22:29 +08001450 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001451 continue;
1452
Bill XIEfa5f9942017-09-12 11:22:29 +08001453 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001454 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001455 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001456 if (i == REGION_BIOS)
1457 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001458 }
1459
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001460 if ((i == REGION_BIOS) && (new->size < current->size)) {
1461 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001462 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001463 }
1464
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001465 if (size < current->base + offset_current + copy_size) {
1466 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1467 region_name(i));
1468 continue;
1469 };
1470
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001471 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1472 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001473 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1474 offset_current, current->limit, current->size);
1475 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1476 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001477
Bill XIEfa5f9942017-09-12 11:22:29 +08001478 memcpy(new_image + new->base + offset_new,
1479 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001480 copy_size);
1481 }
1482
1483 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001484 frba = find_frba(new_image, new_extent);
1485 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001486 exit(EXIT_FAILURE);
1487
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001488 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001489 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001490 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001491
1492 write_image(filename, new_image, new_extent);
1493 free(new_image);
1494}
1495
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001496static void print_version(void)
1497{
1498 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1499 printf("Copyright (C) 2011 Google Inc.\n\n");
1500 printf
1501 ("This program is free software: you can redistribute it and/or modify\n"
1502 "it under the terms of the GNU General Public License as published by\n"
1503 "the Free Software Foundation, version 2 of the License.\n\n"
1504 "This program is distributed in the hope that it will be useful,\n"
1505 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1506 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001507 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001508}
1509
1510static void print_usage(const char *name)
1511{
1512 printf("usage: %s [-vhdix?] <filename>\n", name);
1513 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001514 " -d | --dump: dump intel firmware descriptor\n"
1515 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1516 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1517 " -x | --extract: extract intel fd modules\n"
1518 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1519 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001520 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001521 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1522 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1523 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1524 " can only be used once per run:\n"
1525 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1526 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1527 " Dual Output Fast Read Support\n"
1528 " -l | --lock Lock firmware descriptor and ME region\n"
1529 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001530 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1531 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001532 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301533 " adl - Alder Lake\n"
1534 " aplk - Apollo Lake\n"
1535 " cnl - Cannon Lake\n"
1536 " glk - Gemini Lake\n"
1537 " icl - Ice Lake\n"
1538 " jsl - Jasper Lake\n"
1539 " sklkbl - Sky Lake/Kaby Lake\n"
1540 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001541 " -S | --setpchstrap Write a PCH strap\n"
1542 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001543 " -v | --version: print the version\n"
1544 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001545 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1546 "\n");
1547}
1548
1549int main(int argc, char *argv[])
1550{
1551 int opt, option_index = 0;
1552 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001553 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001554 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001555 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001556 char *region_type_string = NULL, *region_fname = NULL;
1557 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001558 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001559 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001560 unsigned int value = 0;
1561 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001562 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001563 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1564
Bill XIEfa5f9942017-09-12 11:22:29 +08001565 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001566 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001567 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001568 {"extract", 0, NULL, 'x'},
1569 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001570 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001571 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001572 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001573 {"density", 1, NULL, 'D'},
1574 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001575 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001576 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001577 {"lock", 0, NULL, 'l'},
1578 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001579 {"version", 0, NULL, 'v'},
1580 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001581 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001582 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001583 {"setpchstrap", 1, NULL, 'S'},
1584 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001585 {0, 0, 0, 0}
1586 };
1587
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001588 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 -07001589 long_options, &option_index)) != EOF) {
1590 switch (opt) {
1591 case 'd':
1592 mode_dump = 1;
1593 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001594 case 'S':
1595 mode_setstrap = 1;
1596 pchstrap = strtoul(optarg, NULL, 0);
1597 break;
1598 case 'V':
1599 value = strtoul(optarg, NULL, 0);
1600 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001601 case 'f':
1602 mode_layout = 1;
1603 layout_fname = strdup(optarg);
1604 if (!layout_fname) {
1605 fprintf(stderr, "No layout file specified\n");
1606 print_usage(argv[0]);
1607 exit(EXIT_FAILURE);
1608 }
1609 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001610 case 'x':
1611 mode_extract = 1;
1612 break;
1613 case 'i':
1614 // separate type and file name
1615 region_type_string = strdup(optarg);
1616 region_fname = strchr(region_type_string, ':');
1617 if (!region_fname) {
1618 print_usage(argv[0]);
1619 exit(EXIT_FAILURE);
1620 }
1621 region_fname[0] = '\0';
1622 region_fname++;
1623 // Descriptor, BIOS, ME, GbE, Platform
1624 // valid type?
1625 if (!strcasecmp("Descriptor", region_type_string))
1626 region_type = 0;
1627 else if (!strcasecmp("BIOS", region_type_string))
1628 region_type = 1;
1629 else if (!strcasecmp("ME", region_type_string))
1630 region_type = 2;
1631 else if (!strcasecmp("GbE", region_type_string))
1632 region_type = 3;
1633 else if (!strcasecmp("Platform", region_type_string))
1634 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001635 else if (!strcasecmp("EC", region_type_string))
1636 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001637 if (region_type == -1) {
1638 fprintf(stderr, "No such region type: '%s'\n\n",
1639 region_type_string);
1640 print_usage(argv[0]);
1641 exit(EXIT_FAILURE);
1642 }
1643 mode_inject = 1;
1644 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001645 case 'n':
1646 mode_newlayout = 1;
1647 layout_fname = strdup(optarg);
1648 if (!layout_fname) {
1649 fprintf(stderr, "No layout file specified\n");
1650 print_usage(argv[0]);
1651 exit(EXIT_FAILURE);
1652 }
1653 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001654 case 'O':
1655 new_filename = strdup(optarg);
1656 if (!new_filename) {
1657 fprintf(stderr, "No output filename specified\n");
1658 print_usage(argv[0]);
1659 exit(EXIT_FAILURE);
1660 }
1661 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001662 case 'D':
1663 mode_density = 1;
1664 new_density = strtoul(optarg, NULL, 0);
1665 switch (new_density) {
1666 case 512:
1667 new_density = COMPONENT_DENSITY_512KB;
1668 break;
1669 case 1:
1670 new_density = COMPONENT_DENSITY_1MB;
1671 break;
1672 case 2:
1673 new_density = COMPONENT_DENSITY_2MB;
1674 break;
1675 case 4:
1676 new_density = COMPONENT_DENSITY_4MB;
1677 break;
1678 case 8:
1679 new_density = COMPONENT_DENSITY_8MB;
1680 break;
1681 case 16:
1682 new_density = COMPONENT_DENSITY_16MB;
1683 break;
1684 case 32:
1685 new_density = COMPONENT_DENSITY_32MB;
1686 break;
1687 case 64:
1688 new_density = COMPONENT_DENSITY_64MB;
1689 break;
1690 case 0:
1691 new_density = COMPONENT_DENSITY_UNUSED;
1692 break;
1693 default:
1694 printf("error: Unknown density\n");
1695 print_usage(argv[0]);
1696 exit(EXIT_FAILURE);
1697 }
1698 break;
1699 case 'C':
1700 selected_chip = strtol(optarg, NULL, 0);
1701 if (selected_chip > 2) {
1702 fprintf(stderr, "error: Invalid chip selection\n");
1703 print_usage(argv[0]);
1704 exit(EXIT_FAILURE);
1705 }
1706 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001707 case 'M':
1708 mode_altmedisable = 1;
1709 altmedisable = strtol(optarg, NULL, 0);
1710 if (altmedisable > 1) {
1711 fprintf(stderr, "error: Illegal value\n");
1712 print_usage(argv[0]);
1713 exit(EXIT_FAILURE);
1714 }
1715 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001716 case 's':
1717 // Parse the requested SPI frequency
1718 inputfreq = strtol(optarg, NULL, 0);
1719 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001720 case 17:
1721 spifreq = SPI_FREQUENCY_17MHZ;
1722 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001723 case 20:
1724 spifreq = SPI_FREQUENCY_20MHZ;
1725 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001726 case 30:
1727 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1728 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001729 case 33:
1730 spifreq = SPI_FREQUENCY_33MHZ;
1731 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001732 case 48:
1733 spifreq = SPI_FREQUENCY_48MHZ;
1734 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001735 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001736 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001737 break;
1738 default:
1739 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1740 inputfreq);
1741 print_usage(argv[0]);
1742 exit(EXIT_FAILURE);
1743 }
1744 mode_spifreq = 1;
1745 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001746 case 'e':
1747 mode_em100 = 1;
1748 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001749 case 'l':
1750 mode_locked = 1;
1751 if (mode_unlocked == 1) {
1752 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1753 exit(EXIT_FAILURE);
1754 }
1755 break;
1756 case 'u':
1757 mode_unlocked = 1;
1758 if (mode_locked == 1) {
1759 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1760 exit(EXIT_FAILURE);
1761 }
1762 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001763 case 'p':
1764 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001765 platform = PLATFORM_APL;
1766 } else if (!strcmp(optarg, "cnl")) {
1767 platform = PLATFORM_CNL;
1768 } else if (!strcmp(optarg, "glk")) {
1769 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301770 } else if (!strcmp(optarg, "icl")) {
1771 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301772 } else if (!strcmp(optarg, "jsl")) {
1773 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001774 } else if (!strcmp(optarg, "sklkbl")) {
1775 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001776 } else if (!strcmp(optarg, "tgl")) {
1777 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301778 } else if (!strcmp(optarg, "adl")) {
1779 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001780 } else {
1781 fprintf(stderr, "Unknown platform: %s\n", optarg);
1782 exit(EXIT_FAILURE);
1783 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001784 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001785 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001786 case 't':
1787 mode_validate = 1;
1788 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001789 case 'v':
1790 print_version();
1791 exit(EXIT_SUCCESS);
1792 break;
1793 case 'h':
1794 case '?':
1795 default:
1796 print_usage(argv[0]);
1797 exit(EXIT_SUCCESS);
1798 break;
1799 }
1800 }
1801
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001802 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001803 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001804 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001805 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001806 print_usage(argv[0]);
1807 exit(EXIT_FAILURE);
1808 }
1809
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001810 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001811 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001812 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001813 fprintf(stderr, "You need to specify a mode.\n\n");
1814 print_usage(argv[0]);
1815 exit(EXIT_FAILURE);
1816 }
1817
1818 if (optind + 1 != argc) {
1819 fprintf(stderr, "You need to specify a file.\n\n");
1820 print_usage(argv[0]);
1821 exit(EXIT_FAILURE);
1822 }
1823
1824 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001825 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001826 if (bios_fd == -1) {
1827 perror("Could not open file");
1828 exit(EXIT_FAILURE);
1829 }
1830 struct stat buf;
1831 if (fstat(bios_fd, &buf) == -1) {
1832 perror("Could not stat file");
1833 exit(EXIT_FAILURE);
1834 }
1835 int size = buf.st_size;
1836
1837 printf("File %s is %d bytes\n", filename, size);
1838
1839 char *image = malloc(size);
1840 if (!image) {
1841 printf("Out of memory.\n");
1842 exit(EXIT_FAILURE);
1843 }
1844
1845 if (read(bios_fd, image, size) != size) {
1846 perror("Could not read file");
1847 exit(EXIT_FAILURE);
1848 }
1849
1850 close(bios_fd);
1851
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001852 // generate new filename
1853 if (new_filename == NULL) {
1854 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1855 if (!new_filename) {
1856 printf("Out of memory.\n");
1857 exit(EXIT_FAILURE);
1858 }
1859 // - 5: leave room for ".new\0"
1860 strcpy(new_filename, filename);
1861 strcat(new_filename, ".new");
1862 }
1863
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001864 check_ifd_version(image, size);
1865
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001866 if (mode_dump)
1867 dump_fd(image, size);
1868
Chris Douglass03ce0142014-02-26 13:30:13 -05001869 if (mode_layout)
1870 dump_layout(image, size, layout_fname);
1871
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001872 if (mode_extract)
1873 write_regions(image, size);
1874
Mathew Kingc7ddc992019-08-08 14:59:25 -06001875 if (mode_validate)
1876 validate_layout(image, size);
1877
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001878 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001879 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001880 region_fname);
1881
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001882 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001883 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001884
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001885 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001886 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001887
Jan Tatjefa317512016-03-11 00:52:07 +01001888 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001889 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001890
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001891 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001892 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001893
Alexander Couzensd12ea112016-09-10 13:33:05 +02001894 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001895 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001896
1897 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001898 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001899
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001900 if (mode_setstrap) {
1901 fpsba_t *fpsba = find_fpsba(image, size);
1902 const fdbar_t *fdb = find_fd(image, size);
1903 set_pchstrap(fpsba, fdb, pchstrap, value);
1904 write_image(new_filename, image, size);
1905 }
1906
Bill XIEb3e15a22017-09-07 18:34:50 +08001907 if (mode_altmedisable) {
1908 fpsba_t *fpsba = find_fpsba(image, size);
1909 fmsba_t *fmsba = find_fmsba(image, size);
1910 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001911 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001912 }
1913
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001914 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001915 free(image);
1916
1917 return 0;
1918}