blob: 9f507bb68dc0ccf890f17dded4364c5b71140e3a [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
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530451static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700452{
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
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530481static void _decode_spi_frequency_500_series(unsigned int freq)
482{
483 switch (freq) {
484 case SPI_FREQUENCY_100MHZ:
485 printf("100MHz");
486 break;
487 case SPI_FREQUENCY_50MHZ:
488 printf("50MHz");
489 break;
490 case SPI_FREQUENCY_500SERIES_33MHZ:
491 printf("33MHz");
492 break;
493 case SPI_FREQUENCY_25MHZ:
494 printf("25MHz");
495 break;
496 case SPI_FREQUENCY_14MHZ:
497 printf("14MHz");
498 break;
499 default:
500 printf("unknown<%x>MHz", freq);
501 }
502}
503
504static void decode_spi_frequency(unsigned int freq)
505{
506 if (chipset == CHIPSET_500_SERIES_TIGER_POINT)
507 _decode_spi_frequency_500_series(freq);
508 else
509 _decode_spi_frequency(freq);
510}
511
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700512static void decode_component_density(unsigned int density)
513{
514 switch (density) {
515 case COMPONENT_DENSITY_512KB:
516 printf("512KB");
517 break;
518 case COMPONENT_DENSITY_1MB:
519 printf("1MB");
520 break;
521 case COMPONENT_DENSITY_2MB:
522 printf("2MB");
523 break;
524 case COMPONENT_DENSITY_4MB:
525 printf("4MB");
526 break;
527 case COMPONENT_DENSITY_8MB:
528 printf("8MB");
529 break;
530 case COMPONENT_DENSITY_16MB:
531 printf("16MB");
532 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700533 case COMPONENT_DENSITY_32MB:
534 printf("32MB");
535 break;
536 case COMPONENT_DENSITY_64MB:
537 printf("64MB");
538 break;
539 case COMPONENT_DENSITY_UNUSED:
540 printf("UNUSED");
541 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700542 default:
543 printf("unknown<%x>MB", density);
544 }
545}
546
Subrata Banik26058dc2020-08-26 15:12:16 +0530547static int is_platform_with_pch(void)
548{
549 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
550 return 1;
551
552 return 0;
553}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530554
555/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
556static int is_platform_with_100x_series_pch(void)
557{
558 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
559 chipset <= CHIPSET_500_SERIES_TIGER_POINT)
560 return 1;
561
562 return 0;
563}
564
Bill XIEfa5f9942017-09-12 11:22:29 +0800565static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700566{
567 printf("\nFound Component Section\n");
568 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700569 printf(" Dual Output Fast Read Support: %ssupported\n",
570 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700571 printf(" Read ID/Read Status Clock Frequency: ");
572 decode_spi_frequency((fcba->flcomp >> 27) & 7);
573 printf("\n Write/Erase Clock Frequency: ");
574 decode_spi_frequency((fcba->flcomp >> 24) & 7);
575 printf("\n Fast Read Clock Frequency: ");
576 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700577 printf("\n Fast Read Support: %ssupported",
578 (fcba->flcomp & (1 << 20))?"":"not ");
579 printf("\n Read Clock Frequency: ");
580 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700581
582 switch (ifd_version) {
583 case IFD_VERSION_1:
584 printf("\n Component 2 Density: ");
585 decode_component_density((fcba->flcomp >> 3) & 7);
586 printf("\n Component 1 Density: ");
587 decode_component_density(fcba->flcomp & 7);
588 break;
589 case IFD_VERSION_2:
590 printf("\n Component 2 Density: ");
591 decode_component_density((fcba->flcomp >> 4) & 0xf);
592 printf("\n Component 1 Density: ");
593 decode_component_density(fcba->flcomp & 0xf);
594 break;
595 }
596
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700597 printf("\n");
598 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700599 printf(" Invalid Instruction 3: 0x%02x\n",
600 (fcba->flill >> 24) & 0xff);
601 printf(" Invalid Instruction 2: 0x%02x\n",
602 (fcba->flill >> 16) & 0xff);
603 printf(" Invalid Instruction 1: 0x%02x\n",
604 (fcba->flill >> 8) & 0xff);
605 printf(" Invalid Instruction 0: 0x%02x\n",
606 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530607 if (is_platform_with_100x_series_pch()) {
608 printf("FLILL1 0x%08x\n", fcba->flpb);
609 printf(" Invalid Instruction 7: 0x%02x\n",
610 (fcba->flpb >> 24) & 0xff);
611 printf(" Invalid Instruction 6: 0x%02x\n",
612 (fcba->flpb >> 16) & 0xff);
613 printf(" Invalid Instruction 5: 0x%02x\n",
614 (fcba->flpb >> 8) & 0xff);
615 printf(" Invalid Instruction 4: 0x%02x\n",
616 fcba->flpb & 0xff);
617 } else {
618 printf("FLPB 0x%08x\n", fcba->flpb);
619 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
620 (fcba->flpb & 0xfff) << 12);
621 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700622}
623
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200624static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700625{
Bill XIE4651d452017-09-12 11:54:48 +0800626 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200627 /* SoC Strap Length, aka PSL, aka ISL */
628 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
629
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700630 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200631 for (i = 0; i < SSL; i++)
632 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800633
634 if (ifd_version >= IFD_VERSION_2) {
635 printf("HAP bit is %sset\n",
636 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
637 } else if (chipset >= CHIPSET_ICH8
638 && chipset <= CHIPSET_ICH10) {
639 printf("ICH_MeDisable bit is %sset\n",
640 fpsba->pchstrp[0] & 1 ? "" : "not ");
641 } else {
642 printf("AltMeDisable bit is %sset\n",
643 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
644 }
645
Bill XIE4651d452017-09-12 11:54:48 +0800646 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700647}
648
649static void decode_flmstr(uint32_t flmstr)
650{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700651 int wr_shift, rd_shift;
652 if (ifd_version >= IFD_VERSION_2) {
653 wr_shift = FLMSTR_WR_SHIFT_V2;
654 rd_shift = FLMSTR_RD_SHIFT_V2;
655 } else {
656 wr_shift = FLMSTR_WR_SHIFT_V1;
657 rd_shift = FLMSTR_RD_SHIFT_V1;
658 }
659
660 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700661 if (ifd_version >= IFD_VERSION_2)
662 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700663 (flmstr & (1 << (wr_shift + 8))) ?
664 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700665 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700666 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700667 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700668 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700669 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700670 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700671 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700672 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700673 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700674 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700675
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700676 if (ifd_version >= IFD_VERSION_2)
677 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700678 (flmstr & (1 << (rd_shift + 8))) ?
679 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700680 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700681 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700682 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700683 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700684 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700685 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700686 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700687 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700688 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700689 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700690
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700691 /* Requestor ID doesn't exist for ifd 2 */
692 if (ifd_version < IFD_VERSION_2)
693 printf(" Requester ID: 0x%04x\n\n",
694 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700695}
696
Bill XIEfa5f9942017-09-12 11:22:29 +0800697static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700698{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700699 printf("Found Master Section\n");
700 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
701 decode_flmstr(fmba->flmstr1);
702 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
703 decode_flmstr(fmba->flmstr2);
704 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
705 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700706 if (ifd_version >= IFD_VERSION_2) {
707 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
708 decode_flmstr(fmba->flmstr5);
709 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700710}
711
Bill XIEfa5f9942017-09-12 11:22:29 +0800712static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700713{
Bill XIE612ec0e2017-08-30 16:10:27 +0800714 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700715 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800716 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
717 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800718
719 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
720 printf("MCH_MeDisable bit is %sset\n",
721 fmsba->data[0] & 1 ? "" : "not ");
722 printf("MCH_AltMeDisable bit is %sset\n",
723 fmsba->data[0] & (1 << 7) ? "" : "not ");
724 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700725}
726
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700727static void dump_jid(uint32_t jid)
728{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100729 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700730 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100731 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200732 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100733 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200734 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700735}
736
737static void dump_vscc(uint32_t vscc)
738{
739 printf(" Lower Erase Opcode: 0x%02x\n",
740 vscc >> 24);
741 printf(" Lower Write Enable on Write Status: 0x%02x\n",
742 vscc & (1 << 20) ? 0x06 : 0x50);
743 printf(" Lower Write Status Required: %s\n",
744 vscc & (1 << 19) ? "Yes" : "No");
745 printf(" Lower Write Granularity: %d bytes\n",
746 vscc & (1 << 18) ? 64 : 1);
747 printf(" Lower Block / Sector Erase Size: ");
748 switch ((vscc >> 16) & 0x3) {
749 case 0:
750 printf("256 Byte\n");
751 break;
752 case 1:
753 printf("4KB\n");
754 break;
755 case 2:
756 printf("8KB\n");
757 break;
758 case 3:
759 printf("64KB\n");
760 break;
761 }
762
763 printf(" Upper Erase Opcode: 0x%02x\n",
764 (vscc >> 8) & 0xff);
765 printf(" Upper Write Enable on Write Status: 0x%02x\n",
766 vscc & (1 << 4) ? 0x06 : 0x50);
767 printf(" Upper Write Status Required: %s\n",
768 vscc & (1 << 3) ? "Yes" : "No");
769 printf(" Upper Write Granularity: %d bytes\n",
770 vscc & (1 << 2) ? 64 : 1);
771 printf(" Upper Block / Sector Erase Size: ");
772 switch (vscc & 0x3) {
773 case 0:
774 printf("256 Byte\n");
775 break;
776 case 1:
777 printf("4KB\n");
778 break;
779 case 2:
780 printf("8KB\n");
781 break;
782 case 3:
783 printf("64KB\n");
784 break;
785 }
786}
787
Bill XIEfa5f9942017-09-12 11:22:29 +0800788static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700789{
790 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200791 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
792 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700793
794 printf("ME VSCC table:\n");
795 for (i = 0; i < num; i++) {
796 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
797 dump_jid(vtba->entry[i].jid);
798 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
799 dump_vscc(vtba->entry[i].vscc);
800 }
801 printf("\n");
802}
803
Bill XIEfa5f9942017-09-12 11:22:29 +0800804static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700805{
806 int i, j;
807 printf("OEM Section:\n");
808 for (i = 0; i < 4; i++) {
809 printf("%02x:", i << 4);
810 for (j = 0; j < 16; j++)
811 printf(" %02x", oem[(i<<4)+j]);
812 printf ("\n");
813 }
814 printf ("\n");
815}
816
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700817static void dump_fd(char *image, int size)
818{
Bill XIE612ec0e2017-08-30 16:10:27 +0800819 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700820 if (!fdb)
821 exit(EXIT_FAILURE);
822
Subrata Banik26058dc2020-08-26 15:12:16 +0530823 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
824 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700825 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530826 if (!is_platform_with_100x_series_pch())
827 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700828 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
829 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
830 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
831
832 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530833 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
834 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700835 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
836 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
837 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
838
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530839 if (!is_platform_with_100x_series_pch()) {
840 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
841 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
842 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
843 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700844
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530845 if (chipset == CHIPSET_500_SERIES_TIGER_POINT) {
846 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
847 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
848 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
849 }
850
Stefan Tauner0d226142018-08-05 18:56:53 +0200851 char *flumap = find_flumap(image, size);
852 uint32_t flumap1 = *(uint32_t *)flumap;
853 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700854 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200855 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700856 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200857 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700858 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200859 (image + ((flumap1 & 0xff) << 4)),
860 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800861 dump_oem((const uint8_t *)image + 0xf00);
862
863 const frba_t *frba = find_frba(image, size);
864 const fcba_t *fcba = find_fcba(image, size);
865 const fpsba_t *fpsba = find_fpsba(image, size);
866 const fmba_t *fmba = find_fmba(image, size);
867 const fmsba_t *fmsba = find_fmsba(image, size);
868
869 if (frba && fcba && fpsba && fmba && fmsba) {
870 dump_frba(frba);
871 dump_fcba(fcba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200872 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800873 dump_fmba(fmba);
874 dump_fmsba(fmsba);
875 } else {
876 printf("FD is corrupted!\n");
877 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700878}
879
Bill XIEfa5f9942017-09-12 11:22:29 +0800880static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500881{
Bill XIE612ec0e2017-08-30 16:10:27 +0800882 const frba_t *frba = find_frba(image, size);
883 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500884 exit(EXIT_FAILURE);
885
Bill XIE612ec0e2017-08-30 16:10:27 +0800886 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500887}
888
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700889static void write_regions(char *image, int size)
890{
Bill XIEfa5f9942017-09-12 11:22:29 +0800891 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800892 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700893
Bill XIE612ec0e2017-08-30 16:10:27 +0800894 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700895 exit(EXIT_FAILURE);
896
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700897 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700898 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700899 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700900 if (region.size > 0) {
901 int region_fd;
902 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600903 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700904 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200905 if (region_fd < 0) {
906 perror("Error while trying to open file");
907 exit(EXIT_FAILURE);
908 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700909 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700910 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700911 close(region_fd);
912 }
913 }
914}
915
Mathew Kingc7ddc992019-08-08 14:59:25 -0600916static void validate_layout(char *image, int size)
917{
918 uint i, errors = 0;
919 struct fmap *fmap;
920 long int fmap_loc = fmap_find((uint8_t *)image, size);
921 const frba_t *frba = find_frba(image, size);
922
923 if (fmap_loc < 0 || !frba)
924 exit(EXIT_FAILURE);
925
926 fmap = (struct fmap *)(image + fmap_loc);
927
928 for (i = 0; i < max_regions; i++) {
929 if (region_names[i].fmapname == NULL)
930 continue;
931
932 region_t region = get_region(frba, i);
933
934 if (region.size == 0)
935 continue;
936
937 const struct fmap_area *area =
938 fmap_find_area(fmap, region_names[i].fmapname);
939
940 if (!area)
941 continue;
942
943 if ((uint)region.base != area->offset ||
944 (uint)region.size != area->size) {
945 printf("Region mismatch between %s and %s\n",
946 region_names[i].terse, area->name);
947 printf(" Descriptor region %s:\n", region_names[i].terse);
948 printf(" offset: 0x%08x\n", region.base);
949 printf(" length: 0x%08x\n", region.size);
950 printf(" FMAP area %s:\n", area->name);
951 printf(" offset: 0x%08x\n", area->offset);
952 printf(" length: 0x%08x\n", area->size);
953 errors++;
954 }
955 }
956
957 if (errors > 0)
958 exit(EXIT_FAILURE);
959}
960
Bill XIEfa5f9942017-09-12 11:22:29 +0800961static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700962{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700963 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100964 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700965
966 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100967 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600968 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700969 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200970 if (new_fd < 0) {
971 perror("Error while trying to open file");
972 exit(EXIT_FAILURE);
973 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700974 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700975 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700976 close(new_fd);
977}
978
Bill XIEfa5f9942017-09-12 11:22:29 +0800979static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700980 enum spi_frequency freq)
981{
Bill XIE612ec0e2017-08-30 16:10:27 +0800982 fcba_t *fcba = find_fcba(image, size);
983 if (!fcba)
984 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700985
986 /* clear bits 21-29 */
987 fcba->flcomp &= ~0x3fe00000;
988 /* Read ID and Read Status Clock Frequency */
989 fcba->flcomp |= freq << 27;
990 /* Write and Erase Clock Frequency */
991 fcba->flcomp |= freq << 24;
992 /* Fast Read Clock Frequency */
993 fcba->flcomp |= freq << 21;
994
995 write_image(filename, image, size);
996}
997
Bill XIEfa5f9942017-09-12 11:22:29 +0800998static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700999{
Bill XIE612ec0e2017-08-30 16:10:27 +08001000 fcba_t *fcba = find_fcba(image, size);
1001 if (!fcba)
1002 exit(EXIT_FAILURE);
1003
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001004 int freq;
1005
1006 switch (ifd_version) {
1007 case IFD_VERSION_1:
1008 freq = SPI_FREQUENCY_20MHZ;
1009 break;
1010 case IFD_VERSION_2:
1011 freq = SPI_FREQUENCY_17MHZ;
1012 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001013 default:
1014 freq = SPI_FREQUENCY_17MHZ;
1015 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001016 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001017
1018 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001019 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001020}
1021
Bill XIEfa5f9942017-09-12 11:22:29 +08001022static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001023 unsigned int density)
1024{
Bill XIE612ec0e2017-08-30 16:10:27 +08001025 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001026 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001027 if (!fcba)
1028 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001029
1030 printf("Setting chip density to ");
1031 decode_component_density(density);
1032 printf("\n");
1033
1034 switch (ifd_version) {
1035 case IFD_VERSION_1:
1036 /* fail if selected density is not supported by this version */
1037 if ( (density == COMPONENT_DENSITY_32MB) ||
1038 (density == COMPONENT_DENSITY_64MB) ||
1039 (density == COMPONENT_DENSITY_UNUSED) ) {
1040 printf("error: Selected density not supported in IFD version 1.\n");
1041 exit(EXIT_FAILURE);
1042 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001043 mask = 0x7;
1044 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001045 break;
1046 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001047 mask = 0xf;
1048 chip2_offset = 4;
1049 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001050 default:
1051 printf("error: Unknown IFD version\n");
1052 exit(EXIT_FAILURE);
1053 break;
1054 }
1055
1056 /* clear chip density for corresponding chip */
1057 switch (selected_chip) {
1058 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001059 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001060 break;
1061 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001062 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001063 break;
1064 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001065 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001066 break;
1067 }
1068
1069 /* set the new density */
1070 if (selected_chip == 1 || selected_chip == 0)
1071 fcba->flcomp |= (density); /* first chip */
1072 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001073 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001074
1075 write_image(filename, image, size);
1076}
1077
Duncan Laurie7775d672019-06-06 13:39:26 -07001078static int check_region(const frba_t *frba, unsigned int region_type)
1079{
1080 region_t region;
1081
1082 if (!frba)
1083 return 0;
1084
1085 region = get_region(frba, region_type);
1086 return !!((region.base < region.limit) && (region.size > 0));
1087}
1088
Bill XIEfa5f9942017-09-12 11:22:29 +08001089static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001090{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001091 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001092 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001093 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001094 if (!fmba)
1095 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001096
1097 if (ifd_version >= IFD_VERSION_2) {
1098 wr_shift = FLMSTR_WR_SHIFT_V2;
1099 rd_shift = FLMSTR_RD_SHIFT_V2;
1100
1101 /* Clear non-reserved bits */
1102 fmba->flmstr1 &= 0xff;
1103 fmba->flmstr2 &= 0xff;
1104 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001105 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001106 } else {
1107 wr_shift = FLMSTR_WR_SHIFT_V1;
1108 rd_shift = FLMSTR_RD_SHIFT_V1;
1109
1110 fmba->flmstr1 = 0;
1111 fmba->flmstr2 = 0;
1112 /* Requestor ID */
1113 fmba->flmstr3 = 0x118;
1114 }
1115
Andrey Petrov96ecb772016-10-31 19:31:54 -07001116 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001117 case PLATFORM_APL:
1118 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001119 /* CPU/BIOS can read descriptor and BIOS */
1120 fmba->flmstr1 |= 0x3 << rd_shift;
1121 /* CPU/BIOS can write BIOS */
1122 fmba->flmstr1 |= 0x2 << wr_shift;
1123 /* TXE can read descriptor, BIOS and Device Expansion */
1124 fmba->flmstr2 |= 0x23 << rd_shift;
1125 /* TXE can only write Device Expansion */
1126 fmba->flmstr2 |= 0x20 << wr_shift;
1127 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001128 case PLATFORM_CNL:
1129 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001130 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001131 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301132 case PLATFORM_JSL:
Subrata Banik46f80732020-03-14 15:01:42 +05301133 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001134 /* CPU/BIOS can read descriptor and BIOS. */
1135 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1136 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1137 /* CPU/BIOS can write BIOS. */
1138 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1139 /* ME can read descriptor and ME. */
1140 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1141 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001142 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001143 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1144 if (check_region(frba, REGION_GBE)) {
1145 /* BIOS can read/write GbE. */
1146 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1147 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1148 /* ME can read GbE. */
1149 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1150 /* GbE can read descriptor and read/write GbE.. */
1151 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1152 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1153 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1154 }
1155 if (check_region(frba, REGION_PDR)) {
1156 /* BIOS can read/write PDR. */
1157 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1158 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1159 }
1160 if (check_region(frba, REGION_EC)) {
1161 /* BIOS can read EC. */
1162 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1163 /* EC can read descriptor and read/write EC. */
1164 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1165 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1166 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1167 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001168 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001169 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001170 /* CPU/BIOS can read descriptor and BIOS. */
1171 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1172 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1173 /* CPU/BIOS can write BIOS. */
1174 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1175 /* ME can read descriptor and ME. */
1176 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1177 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1178 /* ME can write ME. */
1179 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1180 if (check_region(frba, REGION_GBE)) {
1181 /* BIOS can read GbE. */
1182 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1183 /* BIOS can write GbE. */
1184 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1185 /* ME can read GbE. */
1186 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1187 /* ME can write GbE. */
1188 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1189 /* GbE can write GbE. */
1190 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1191 /* GbE can read GbE. */
1192 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1193 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001194 break;
1195 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001196
1197 write_image(filename, image, size);
1198}
1199
Bill XIEfa5f9942017-09-12 11:22:29 +08001200static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001201{
Bill XIE612ec0e2017-08-30 16:10:27 +08001202 fmba_t *fmba = find_fmba(image, size);
1203 if (!fmba)
1204 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001205
1206 if (ifd_version >= IFD_VERSION_2) {
1207 /* Access bits for each region are read: 19:8 write: 31:20 */
1208 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1209 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1210 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001211 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001212 } else {
1213 fmba->flmstr1 = 0xffff0000;
1214 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001215 /* Keep chipset specific Requester ID */
1216 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001217 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001218
1219 write_image(filename, image, size);
1220}
1221
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001222static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1223 const unsigned int value)
1224{
1225 if (!fpsba || !fdb) {
1226 fprintf(stderr, "Internal error\n");
1227 exit(EXIT_FAILURE);
1228 }
1229
1230 /* SoC Strap Length, aka PSL, aka ISL */
1231 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1232 if (strap >= SSL) {
1233 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1234 exit(EXIT_FAILURE);
1235 }
1236 fpsba->pchstrp[strap] = value;
1237}
1238
Bill XIEb3e15a22017-09-07 18:34:50 +08001239/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001240static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001241{
1242 if (ifd_version >= IFD_VERSION_2) {
1243 printf("%sting the HAP bit to %s Intel ME...\n",
1244 altmedisable?"Set":"Unset",
1245 altmedisable?"disable":"enable");
1246 if (altmedisable)
1247 fpsba->pchstrp[0] |= (1 << 16);
1248 else
1249 fpsba->pchstrp[0] &= ~(1 << 16);
1250 } else {
1251 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1252 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1253 "and MCH_AltMeDisable to %s Intel ME...\n",
1254 altmedisable?"Set":"Unset",
1255 altmedisable?"disable":"enable");
1256 if (altmedisable) {
1257 /* MCH_MeDisable */
1258 fmsba->data[0] |= 1;
1259 /* MCH_AltMeDisable */
1260 fmsba->data[0] |= (1 << 7);
1261 /* ICH_MeDisable */
1262 fpsba->pchstrp[0] |= 1;
1263 } else {
1264 fmsba->data[0] &= ~1;
1265 fmsba->data[0] &= ~(1 << 7);
1266 fpsba->pchstrp[0] &= ~1;
1267 }
1268 } else {
1269 printf("%sting the AltMeDisable to %s Intel ME...\n",
1270 altmedisable?"Set":"Unset",
1271 altmedisable?"disable":"enable");
1272 if (altmedisable)
1273 fpsba->pchstrp[10] |= (1 << 7);
1274 else
1275 fpsba->pchstrp[10] &= ~(1 << 7);
1276 }
1277 }
1278}
1279
Jacob Garber595d9262019-06-27 17:33:10 -06001280static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001281 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001282{
Bill XIE612ec0e2017-08-30 16:10:27 +08001283 frba_t *frba = find_frba(image, size);
1284 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001285 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001286
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001287 region_t region = get_region(frba, region_type);
1288 if (region.size <= 0xfff) {
1289 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1290 region_name(region_type));
1291 exit(EXIT_FAILURE);
1292 }
1293
Scott Duplichanf2c98372014-12-12 21:03:06 -06001294 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001295 if (region_fd == -1) {
1296 perror("Could not open file");
1297 exit(EXIT_FAILURE);
1298 }
1299 struct stat buf;
1300 if (fstat(region_fd, &buf) == -1) {
1301 perror("Could not stat file");
1302 exit(EXIT_FAILURE);
1303 }
1304 int region_size = buf.st_size;
1305
1306 printf("File %s is %d bytes\n", region_fname, region_size);
1307
1308 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001309 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001310 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1311 " bytes. Not injecting.\n",
1312 region_name(region_type), region.size,
1313 region.size, region_size, region_size);
1314 exit(EXIT_FAILURE);
1315 }
1316
1317 int offset = 0;
1318 if ((region_type == 1) && (region_size < region.size)) {
1319 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1320 " bytes. Padding before injecting.\n",
1321 region_name(region_type), region.size,
1322 region.size, region_size, region_size);
1323 offset = region.size - region_size;
1324 memset(image + region.base, 0xff, offset);
1325 }
1326
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001327 if (size < region.base + offset + region_size) {
1328 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1329 size, region.base + offset + region_size);
1330 exit(EXIT_FAILURE);
1331 }
1332
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001333 if (read(region_fd, image + region.base + offset, region_size)
1334 != region_size) {
1335 perror("Could not read file");
1336 exit(EXIT_FAILURE);
1337 }
1338
1339 close(region_fd);
1340
1341 printf("Adding %s as the %s section of %s\n",
1342 region_fname, region_name(region_type), filename);
1343 write_image(filename, image, size);
1344}
1345
Jacob Garber595d9262019-06-27 17:33:10 -06001346static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001347{
1348 unsigned int y = 1;
1349 if (x == 0)
1350 return 0;
1351 while (y <= x)
1352 y = y << 1;
1353
1354 return y;
1355}
1356
1357/**
1358 * Determine if two memory regions overlap.
1359 *
1360 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001361 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001362 * @return 1 if the two regions overlap
1363 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001364static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001365{
Bill XIEfa5f9942017-09-12 11:22:29 +08001366 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001367 return 0;
1368
Nico Huber844eda02019-01-05 00:06:19 +01001369 /* r1 should be either completely below or completely above r2 */
1370 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001371}
1372
Jacob Garber595d9262019-06-27 17:33:10 -06001373static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001374 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001375{
1376 FILE *romlayout;
1377 char tempstr[256];
1378 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001379 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001380 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001381 region_t current_regions[MAX_REGIONS];
1382 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001383 int new_extent = 0;
1384 char *new_image;
1385
1386 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001387 frba_t *frba = find_frba(image, size);
1388 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001389 exit(EXIT_FAILURE);
1390
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001391 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001392 current_regions[i] = get_region(frba, i);
1393 new_regions[i] = get_region(frba, i);
1394 }
1395
1396 /* read new layout */
1397 romlayout = fopen(layout_fname, "r");
1398
1399 if (!romlayout) {
1400 perror("Could not read layout file.\n");
1401 exit(EXIT_FAILURE);
1402 }
1403
1404 while (!feof(romlayout)) {
1405 char *tstr1, *tstr2;
1406
Patrick Georgi802ad522014-08-09 17:12:23 +02001407 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001408 layout_region_name))
1409 continue;
1410
1411 region_number = region_num(layout_region_name);
1412 if (region_number < 0)
1413 continue;
1414
1415 tstr1 = strtok(tempstr, ":");
1416 tstr2 = strtok(NULL, ":");
1417 if (!tstr1 || !tstr2) {
1418 fprintf(stderr, "Could not parse layout file.\n");
1419 exit(EXIT_FAILURE);
1420 }
1421 new_regions[region_number].base = strtol(tstr1,
1422 (char **)NULL, 16);
1423 new_regions[region_number].limit = strtol(tstr2,
1424 (char **)NULL, 16);
1425 new_regions[region_number].size =
1426 new_regions[region_number].limit -
1427 new_regions[region_number].base + 1;
1428
1429 if (new_regions[region_number].size < 0)
1430 new_regions[region_number].size = 0;
1431 }
1432 fclose(romlayout);
1433
1434 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001435 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001436 if (new_regions[i].size == 0)
1437 continue;
1438
1439 if (new_regions[i].size < current_regions[i].size) {
1440 printf("DANGER: Region %s is shrinking.\n",
1441 region_name(i));
1442 printf(" The region will be truncated to fit.\n");
1443 printf(" This may result in an unusable image.\n");
1444 }
1445
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001446 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001447 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001448 fprintf(stderr, "Regions would overlap.\n");
1449 exit(EXIT_FAILURE);
1450 }
1451 }
1452
1453 /* detect if the image size should grow */
1454 if (new_extent < new_regions[i].limit)
1455 new_extent = new_regions[i].limit;
1456 }
1457
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001458 /* check if the image is actually a Flash Descriptor region */
1459 if (size == new_regions[0].size) {
1460 printf("The image is a single Flash Descriptor:\n");
1461 printf(" Only the descriptor will be modified\n");
1462 new_extent = size;
1463 } else {
1464 new_extent = next_pow2(new_extent - 1);
1465 if (new_extent != size) {
1466 printf("The image has changed in size.\n");
1467 printf("The old image is %d bytes.\n", size);
1468 printf("The new image is %d bytes.\n", new_extent);
1469 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001470 }
1471
1472 /* copy regions to a new image */
1473 new_image = malloc(new_extent);
1474 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001475 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001476 int copy_size = new_regions[i].size;
1477 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001478 const region_t *current = &current_regions[i];
1479 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001480
Bill XIEfa5f9942017-09-12 11:22:29 +08001481 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001482 continue;
1483
Bill XIEfa5f9942017-09-12 11:22:29 +08001484 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001485 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001486 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001487 if (i == REGION_BIOS)
1488 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001489 }
1490
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001491 if ((i == REGION_BIOS) && (new->size < current->size)) {
1492 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001493 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001494 }
1495
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001496 if (size < current->base + offset_current + copy_size) {
1497 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1498 region_name(i));
1499 continue;
1500 };
1501
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001502 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1503 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001504 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1505 offset_current, current->limit, current->size);
1506 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1507 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001508
Bill XIEfa5f9942017-09-12 11:22:29 +08001509 memcpy(new_image + new->base + offset_new,
1510 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001511 copy_size);
1512 }
1513
1514 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001515 frba = find_frba(new_image, new_extent);
1516 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001517 exit(EXIT_FAILURE);
1518
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001519 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001520 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001521 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001522
1523 write_image(filename, new_image, new_extent);
1524 free(new_image);
1525}
1526
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001527static void print_version(void)
1528{
1529 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1530 printf("Copyright (C) 2011 Google Inc.\n\n");
1531 printf
1532 ("This program is free software: you can redistribute it and/or modify\n"
1533 "it under the terms of the GNU General Public License as published by\n"
1534 "the Free Software Foundation, version 2 of the License.\n\n"
1535 "This program is distributed in the hope that it will be useful,\n"
1536 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1537 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001538 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001539}
1540
1541static void print_usage(const char *name)
1542{
1543 printf("usage: %s [-vhdix?] <filename>\n", name);
1544 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001545 " -d | --dump: dump intel firmware descriptor\n"
1546 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1547 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1548 " -x | --extract: extract intel fd modules\n"
1549 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1550 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001551 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001552 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1553 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1554 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1555 " can only be used once per run:\n"
1556 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1557 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1558 " Dual Output Fast Read Support\n"
1559 " -l | --lock Lock firmware descriptor and ME region\n"
1560 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001561 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1562 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001563 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301564 " adl - Alder Lake\n"
1565 " aplk - Apollo Lake\n"
1566 " cnl - Cannon Lake\n"
1567 " glk - Gemini Lake\n"
1568 " icl - Ice Lake\n"
1569 " jsl - Jasper Lake\n"
1570 " sklkbl - Sky Lake/Kaby Lake\n"
1571 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001572 " -S | --setpchstrap Write a PCH strap\n"
1573 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001574 " -v | --version: print the version\n"
1575 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001576 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1577 "\n");
1578}
1579
1580int main(int argc, char *argv[])
1581{
1582 int opt, option_index = 0;
1583 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001584 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001585 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001586 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001587 char *region_type_string = NULL, *region_fname = NULL;
1588 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001589 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001590 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001591 unsigned int value = 0;
1592 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001593 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001594 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1595
Bill XIEfa5f9942017-09-12 11:22:29 +08001596 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001597 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001598 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001599 {"extract", 0, NULL, 'x'},
1600 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001601 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001602 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001603 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001604 {"density", 1, NULL, 'D'},
1605 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001606 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001607 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001608 {"lock", 0, NULL, 'l'},
1609 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001610 {"version", 0, NULL, 'v'},
1611 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001612 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001613 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001614 {"setpchstrap", 1, NULL, 'S'},
1615 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001616 {0, 0, 0, 0}
1617 };
1618
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001619 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 -07001620 long_options, &option_index)) != EOF) {
1621 switch (opt) {
1622 case 'd':
1623 mode_dump = 1;
1624 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001625 case 'S':
1626 mode_setstrap = 1;
1627 pchstrap = strtoul(optarg, NULL, 0);
1628 break;
1629 case 'V':
1630 value = strtoul(optarg, NULL, 0);
1631 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001632 case 'f':
1633 mode_layout = 1;
1634 layout_fname = strdup(optarg);
1635 if (!layout_fname) {
1636 fprintf(stderr, "No layout file specified\n");
1637 print_usage(argv[0]);
1638 exit(EXIT_FAILURE);
1639 }
1640 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001641 case 'x':
1642 mode_extract = 1;
1643 break;
1644 case 'i':
1645 // separate type and file name
1646 region_type_string = strdup(optarg);
1647 region_fname = strchr(region_type_string, ':');
1648 if (!region_fname) {
1649 print_usage(argv[0]);
1650 exit(EXIT_FAILURE);
1651 }
1652 region_fname[0] = '\0';
1653 region_fname++;
1654 // Descriptor, BIOS, ME, GbE, Platform
1655 // valid type?
1656 if (!strcasecmp("Descriptor", region_type_string))
1657 region_type = 0;
1658 else if (!strcasecmp("BIOS", region_type_string))
1659 region_type = 1;
1660 else if (!strcasecmp("ME", region_type_string))
1661 region_type = 2;
1662 else if (!strcasecmp("GbE", region_type_string))
1663 region_type = 3;
1664 else if (!strcasecmp("Platform", region_type_string))
1665 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001666 else if (!strcasecmp("EC", region_type_string))
1667 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001668 if (region_type == -1) {
1669 fprintf(stderr, "No such region type: '%s'\n\n",
1670 region_type_string);
1671 print_usage(argv[0]);
1672 exit(EXIT_FAILURE);
1673 }
1674 mode_inject = 1;
1675 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001676 case 'n':
1677 mode_newlayout = 1;
1678 layout_fname = strdup(optarg);
1679 if (!layout_fname) {
1680 fprintf(stderr, "No layout file specified\n");
1681 print_usage(argv[0]);
1682 exit(EXIT_FAILURE);
1683 }
1684 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001685 case 'O':
1686 new_filename = strdup(optarg);
1687 if (!new_filename) {
1688 fprintf(stderr, "No output filename specified\n");
1689 print_usage(argv[0]);
1690 exit(EXIT_FAILURE);
1691 }
1692 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001693 case 'D':
1694 mode_density = 1;
1695 new_density = strtoul(optarg, NULL, 0);
1696 switch (new_density) {
1697 case 512:
1698 new_density = COMPONENT_DENSITY_512KB;
1699 break;
1700 case 1:
1701 new_density = COMPONENT_DENSITY_1MB;
1702 break;
1703 case 2:
1704 new_density = COMPONENT_DENSITY_2MB;
1705 break;
1706 case 4:
1707 new_density = COMPONENT_DENSITY_4MB;
1708 break;
1709 case 8:
1710 new_density = COMPONENT_DENSITY_8MB;
1711 break;
1712 case 16:
1713 new_density = COMPONENT_DENSITY_16MB;
1714 break;
1715 case 32:
1716 new_density = COMPONENT_DENSITY_32MB;
1717 break;
1718 case 64:
1719 new_density = COMPONENT_DENSITY_64MB;
1720 break;
1721 case 0:
1722 new_density = COMPONENT_DENSITY_UNUSED;
1723 break;
1724 default:
1725 printf("error: Unknown density\n");
1726 print_usage(argv[0]);
1727 exit(EXIT_FAILURE);
1728 }
1729 break;
1730 case 'C':
1731 selected_chip = strtol(optarg, NULL, 0);
1732 if (selected_chip > 2) {
1733 fprintf(stderr, "error: Invalid chip selection\n");
1734 print_usage(argv[0]);
1735 exit(EXIT_FAILURE);
1736 }
1737 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001738 case 'M':
1739 mode_altmedisable = 1;
1740 altmedisable = strtol(optarg, NULL, 0);
1741 if (altmedisable > 1) {
1742 fprintf(stderr, "error: Illegal value\n");
1743 print_usage(argv[0]);
1744 exit(EXIT_FAILURE);
1745 }
1746 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001747 case 's':
1748 // Parse the requested SPI frequency
1749 inputfreq = strtol(optarg, NULL, 0);
1750 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001751 case 17:
1752 spifreq = SPI_FREQUENCY_17MHZ;
1753 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001754 case 20:
1755 spifreq = SPI_FREQUENCY_20MHZ;
1756 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001757 case 30:
1758 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1759 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001760 case 33:
1761 spifreq = SPI_FREQUENCY_33MHZ;
1762 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001763 case 48:
1764 spifreq = SPI_FREQUENCY_48MHZ;
1765 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001766 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001767 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001768 break;
1769 default:
1770 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1771 inputfreq);
1772 print_usage(argv[0]);
1773 exit(EXIT_FAILURE);
1774 }
1775 mode_spifreq = 1;
1776 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001777 case 'e':
1778 mode_em100 = 1;
1779 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001780 case 'l':
1781 mode_locked = 1;
1782 if (mode_unlocked == 1) {
1783 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1784 exit(EXIT_FAILURE);
1785 }
1786 break;
1787 case 'u':
1788 mode_unlocked = 1;
1789 if (mode_locked == 1) {
1790 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1791 exit(EXIT_FAILURE);
1792 }
1793 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001794 case 'p':
1795 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001796 platform = PLATFORM_APL;
1797 } else if (!strcmp(optarg, "cnl")) {
1798 platform = PLATFORM_CNL;
1799 } else if (!strcmp(optarg, "glk")) {
1800 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301801 } else if (!strcmp(optarg, "icl")) {
1802 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301803 } else if (!strcmp(optarg, "jsl")) {
1804 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001805 } else if (!strcmp(optarg, "sklkbl")) {
1806 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001807 } else if (!strcmp(optarg, "tgl")) {
1808 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301809 } else if (!strcmp(optarg, "adl")) {
1810 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001811 } else {
1812 fprintf(stderr, "Unknown platform: %s\n", optarg);
1813 exit(EXIT_FAILURE);
1814 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001815 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001816 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001817 case 't':
1818 mode_validate = 1;
1819 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001820 case 'v':
1821 print_version();
1822 exit(EXIT_SUCCESS);
1823 break;
1824 case 'h':
1825 case '?':
1826 default:
1827 print_usage(argv[0]);
1828 exit(EXIT_SUCCESS);
1829 break;
1830 }
1831 }
1832
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001833 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001834 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001835 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001836 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001837 print_usage(argv[0]);
1838 exit(EXIT_FAILURE);
1839 }
1840
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001841 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001842 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001843 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001844 fprintf(stderr, "You need to specify a mode.\n\n");
1845 print_usage(argv[0]);
1846 exit(EXIT_FAILURE);
1847 }
1848
1849 if (optind + 1 != argc) {
1850 fprintf(stderr, "You need to specify a file.\n\n");
1851 print_usage(argv[0]);
1852 exit(EXIT_FAILURE);
1853 }
1854
1855 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001856 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001857 if (bios_fd == -1) {
1858 perror("Could not open file");
1859 exit(EXIT_FAILURE);
1860 }
1861 struct stat buf;
1862 if (fstat(bios_fd, &buf) == -1) {
1863 perror("Could not stat file");
1864 exit(EXIT_FAILURE);
1865 }
1866 int size = buf.st_size;
1867
1868 printf("File %s is %d bytes\n", filename, size);
1869
1870 char *image = malloc(size);
1871 if (!image) {
1872 printf("Out of memory.\n");
1873 exit(EXIT_FAILURE);
1874 }
1875
1876 if (read(bios_fd, image, size) != size) {
1877 perror("Could not read file");
1878 exit(EXIT_FAILURE);
1879 }
1880
1881 close(bios_fd);
1882
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001883 // generate new filename
1884 if (new_filename == NULL) {
1885 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1886 if (!new_filename) {
1887 printf("Out of memory.\n");
1888 exit(EXIT_FAILURE);
1889 }
1890 // - 5: leave room for ".new\0"
1891 strcpy(new_filename, filename);
1892 strcat(new_filename, ".new");
1893 }
1894
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001895 check_ifd_version(image, size);
1896
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001897 if (mode_dump)
1898 dump_fd(image, size);
1899
Chris Douglass03ce0142014-02-26 13:30:13 -05001900 if (mode_layout)
1901 dump_layout(image, size, layout_fname);
1902
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001903 if (mode_extract)
1904 write_regions(image, size);
1905
Mathew Kingc7ddc992019-08-08 14:59:25 -06001906 if (mode_validate)
1907 validate_layout(image, size);
1908
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001909 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001910 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001911 region_fname);
1912
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001913 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001914 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001915
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001916 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001917 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001918
Jan Tatjefa317512016-03-11 00:52:07 +01001919 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001920 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001921
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001922 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001923 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001924
Alexander Couzensd12ea112016-09-10 13:33:05 +02001925 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001926 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001927
1928 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001929 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001930
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001931 if (mode_setstrap) {
1932 fpsba_t *fpsba = find_fpsba(image, size);
1933 const fdbar_t *fdb = find_fd(image, size);
1934 set_pchstrap(fpsba, fdb, pchstrap, value);
1935 write_image(new_filename, image, size);
1936 }
1937
Bill XIEb3e15a22017-09-07 18:34:50 +08001938 if (mode_altmedisable) {
1939 fpsba_t *fpsba = find_fpsba(image, size);
1940 fmsba_t *fmsba = find_fmsba(image, size);
1941 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001942 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001943 }
1944
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001945 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001946 free(image);
1947
1948 return 0;
1949}