blob: 7dbed66df6aaf2c04b3e9d3a4d9e6833405736c1 [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",
Subrata Banika5f47812020-09-29 11:43:01 +053075 "500 series Tiger Point/ 600 series Alder 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))
Subrata Banika5f47812020-09-29 11:43:01 +0530184 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
Subrata Banik89db2252020-08-26 14:49:17 +0530185
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);
Subrata Banik60296ae2020-09-06 18:50:14 +0530268 if (!fcba || !fdb || !fpsba)
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{
Subrata Banika5f47812020-09-29 11:43:01 +0530506 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530507 _decode_spi_frequency_500_series(freq);
508 else
509 _decode_spi_frequency(freq);
510}
511
Subrata Banike5d39922020-08-26 16:01:42 +0530512static void _decode_espi_frequency(unsigned int freq)
513{
514 switch (freq) {
515 case ESPI_FREQUENCY_20MHZ:
516 printf("20MHz");
517 break;
518 case ESPI_FREQUENCY_24MHZ:
519 printf("24MHz");
520 break;
521 case ESPI_FREQUENCY_30MHZ:
522 printf("30MHz");
523 break;
524 case ESPI_FREQUENCY_48MHZ:
525 printf("48MHz");
526 break;
527 case ESPI_FREQUENCY_60MHZ:
528 printf("60MHz");
529 break;
530 case ESPI_FREQUENCY_17MHZ:
531 printf("17MHz");
532 break;
533 default:
534 printf("unknown<%x>MHz", freq);
535 }
536}
537
538static void _decode_espi_frequency_500_series(unsigned int freq)
539{
540 switch (freq) {
541 case ESPI_FREQUENCY_500SERIES_20MHZ:
542 printf("20MHz");
543 break;
544 case ESPI_FREQUENCY_500SERIES_24MHZ:
545 printf("24MHz");
546 break;
547 case ESPI_FREQUENCY_500SERIES_25MHZ:
548 printf("25MHz");
549 break;
550 case ESPI_FREQUENCY_500SERIES_48MHZ:
551 printf("48MHz");
552 break;
553 case ESPI_FREQUENCY_500SERIES_60MHZ:
554 printf("60MHz");
555 break;
556 default:
557 printf("unknown<%x>MHz", freq);
558 }
559}
560
561static void decode_espi_frequency(unsigned int freq)
562{
Subrata Banika5f47812020-09-29 11:43:01 +0530563 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530564 _decode_espi_frequency_500_series(freq);
565 else
566 _decode_espi_frequency(freq);
567}
568
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700569static void decode_component_density(unsigned int density)
570{
571 switch (density) {
572 case COMPONENT_DENSITY_512KB:
573 printf("512KB");
574 break;
575 case COMPONENT_DENSITY_1MB:
576 printf("1MB");
577 break;
578 case COMPONENT_DENSITY_2MB:
579 printf("2MB");
580 break;
581 case COMPONENT_DENSITY_4MB:
582 printf("4MB");
583 break;
584 case COMPONENT_DENSITY_8MB:
585 printf("8MB");
586 break;
587 case COMPONENT_DENSITY_16MB:
588 printf("16MB");
589 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700590 case COMPONENT_DENSITY_32MB:
591 printf("32MB");
592 break;
593 case COMPONENT_DENSITY_64MB:
594 printf("64MB");
595 break;
596 case COMPONENT_DENSITY_UNUSED:
597 printf("UNUSED");
598 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700599 default:
600 printf("unknown<%x>MB", density);
601 }
602}
603
Subrata Banik26058dc2020-08-26 15:12:16 +0530604static int is_platform_with_pch(void)
605{
606 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
607 return 1;
608
609 return 0;
610}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530611
612/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
613static int is_platform_with_100x_series_pch(void)
614{
615 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530616 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530617 return 1;
618
619 return 0;
620}
621
Subrata Banike5d39922020-08-26 16:01:42 +0530622static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700623{
Subrata Banike5d39922020-08-26 16:01:42 +0530624 unsigned int freq;
625
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700626 printf("\nFound Component Section\n");
627 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700628 printf(" Dual Output Fast Read Support: %ssupported\n",
629 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700630 printf(" Read ID/Read Status Clock Frequency: ");
631 decode_spi_frequency((fcba->flcomp >> 27) & 7);
632 printf("\n Write/Erase Clock Frequency: ");
633 decode_spi_frequency((fcba->flcomp >> 24) & 7);
634 printf("\n Fast Read Clock Frequency: ");
635 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700636 printf("\n Fast Read Support: %ssupported",
637 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530638 if (is_platform_with_100x_series_pch() &&
639 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
640 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530641 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530642 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
643 else
644 freq = (fcba->flcomp >> 17) & 7;
645 decode_espi_frequency(freq);
646 } else {
647 printf("\n Read Clock Frequency: ");
648 decode_spi_frequency((fcba->flcomp >> 17) & 7);
649 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700650
651 switch (ifd_version) {
652 case IFD_VERSION_1:
653 printf("\n Component 2 Density: ");
654 decode_component_density((fcba->flcomp >> 3) & 7);
655 printf("\n Component 1 Density: ");
656 decode_component_density(fcba->flcomp & 7);
657 break;
658 case IFD_VERSION_2:
659 printf("\n Component 2 Density: ");
660 decode_component_density((fcba->flcomp >> 4) & 0xf);
661 printf("\n Component 1 Density: ");
662 decode_component_density(fcba->flcomp & 0xf);
663 break;
664 }
665
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700666 printf("\n");
667 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700668 printf(" Invalid Instruction 3: 0x%02x\n",
669 (fcba->flill >> 24) & 0xff);
670 printf(" Invalid Instruction 2: 0x%02x\n",
671 (fcba->flill >> 16) & 0xff);
672 printf(" Invalid Instruction 1: 0x%02x\n",
673 (fcba->flill >> 8) & 0xff);
674 printf(" Invalid Instruction 0: 0x%02x\n",
675 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530676 if (is_platform_with_100x_series_pch()) {
677 printf("FLILL1 0x%08x\n", fcba->flpb);
678 printf(" Invalid Instruction 7: 0x%02x\n",
679 (fcba->flpb >> 24) & 0xff);
680 printf(" Invalid Instruction 6: 0x%02x\n",
681 (fcba->flpb >> 16) & 0xff);
682 printf(" Invalid Instruction 5: 0x%02x\n",
683 (fcba->flpb >> 8) & 0xff);
684 printf(" Invalid Instruction 4: 0x%02x\n",
685 fcba->flpb & 0xff);
686 } else {
687 printf("FLPB 0x%08x\n", fcba->flpb);
688 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
689 (fcba->flpb & 0xfff) << 12);
690 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700691}
692
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200693static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700694{
Bill XIE4651d452017-09-12 11:54:48 +0800695 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200696 /* SoC Strap Length, aka PSL, aka ISL */
697 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
698
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700699 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200700 for (i = 0; i < SSL; i++)
701 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800702
703 if (ifd_version >= IFD_VERSION_2) {
704 printf("HAP bit is %sset\n",
705 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
706 } else if (chipset >= CHIPSET_ICH8
707 && chipset <= CHIPSET_ICH10) {
708 printf("ICH_MeDisable bit is %sset\n",
709 fpsba->pchstrp[0] & 1 ? "" : "not ");
710 } else {
711 printf("AltMeDisable bit is %sset\n",
712 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
713 }
714
Bill XIE4651d452017-09-12 11:54:48 +0800715 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700716}
717
718static void decode_flmstr(uint32_t flmstr)
719{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700720 int wr_shift, rd_shift;
721 if (ifd_version >= IFD_VERSION_2) {
722 wr_shift = FLMSTR_WR_SHIFT_V2;
723 rd_shift = FLMSTR_RD_SHIFT_V2;
724 } else {
725 wr_shift = FLMSTR_WR_SHIFT_V1;
726 rd_shift = FLMSTR_RD_SHIFT_V1;
727 }
728
729 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700730 if (ifd_version >= IFD_VERSION_2)
731 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700732 (flmstr & (1 << (wr_shift + 8))) ?
733 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700734 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700735 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700736 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700737 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700738 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700739 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700740 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700741 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700742 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700743 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700744
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700745 if (ifd_version >= IFD_VERSION_2)
746 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700747 (flmstr & (1 << (rd_shift + 8))) ?
748 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700749 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700750 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700751 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700752 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700753 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700754 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700755 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700756 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700757 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700758 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700759
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700760 /* Requestor ID doesn't exist for ifd 2 */
761 if (ifd_version < IFD_VERSION_2)
762 printf(" Requester ID: 0x%04x\n\n",
763 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700764}
765
Bill XIEfa5f9942017-09-12 11:22:29 +0800766static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700767{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700768 printf("Found Master Section\n");
769 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
770 decode_flmstr(fmba->flmstr1);
771 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
772 decode_flmstr(fmba->flmstr2);
773 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
774 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700775 if (ifd_version >= IFD_VERSION_2) {
776 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
777 decode_flmstr(fmba->flmstr5);
778 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700779}
780
Bill XIEfa5f9942017-09-12 11:22:29 +0800781static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700782{
Bill XIE612ec0e2017-08-30 16:10:27 +0800783 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700784 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800785 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
786 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800787
788 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
789 printf("MCH_MeDisable bit is %sset\n",
790 fmsba->data[0] & 1 ? "" : "not ");
791 printf("MCH_AltMeDisable bit is %sset\n",
792 fmsba->data[0] & (1 << 7) ? "" : "not ");
793 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700794}
795
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700796static void dump_jid(uint32_t jid)
797{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100798 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700799 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100800 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200801 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100802 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200803 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700804}
805
806static void dump_vscc(uint32_t vscc)
807{
808 printf(" Lower Erase Opcode: 0x%02x\n",
809 vscc >> 24);
810 printf(" Lower Write Enable on Write Status: 0x%02x\n",
811 vscc & (1 << 20) ? 0x06 : 0x50);
812 printf(" Lower Write Status Required: %s\n",
813 vscc & (1 << 19) ? "Yes" : "No");
814 printf(" Lower Write Granularity: %d bytes\n",
815 vscc & (1 << 18) ? 64 : 1);
816 printf(" Lower Block / Sector Erase Size: ");
817 switch ((vscc >> 16) & 0x3) {
818 case 0:
819 printf("256 Byte\n");
820 break;
821 case 1:
822 printf("4KB\n");
823 break;
824 case 2:
825 printf("8KB\n");
826 break;
827 case 3:
828 printf("64KB\n");
829 break;
830 }
831
832 printf(" Upper Erase Opcode: 0x%02x\n",
833 (vscc >> 8) & 0xff);
834 printf(" Upper Write Enable on Write Status: 0x%02x\n",
835 vscc & (1 << 4) ? 0x06 : 0x50);
836 printf(" Upper Write Status Required: %s\n",
837 vscc & (1 << 3) ? "Yes" : "No");
838 printf(" Upper Write Granularity: %d bytes\n",
839 vscc & (1 << 2) ? 64 : 1);
840 printf(" Upper Block / Sector Erase Size: ");
841 switch (vscc & 0x3) {
842 case 0:
843 printf("256 Byte\n");
844 break;
845 case 1:
846 printf("4KB\n");
847 break;
848 case 2:
849 printf("8KB\n");
850 break;
851 case 3:
852 printf("64KB\n");
853 break;
854 }
855}
856
Bill XIEfa5f9942017-09-12 11:22:29 +0800857static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700858{
859 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200860 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
861 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700862
863 printf("ME VSCC table:\n");
864 for (i = 0; i < num; i++) {
865 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
866 dump_jid(vtba->entry[i].jid);
867 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
868 dump_vscc(vtba->entry[i].vscc);
869 }
870 printf("\n");
871}
872
Bill XIEfa5f9942017-09-12 11:22:29 +0800873static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700874{
875 int i, j;
876 printf("OEM Section:\n");
877 for (i = 0; i < 4; i++) {
878 printf("%02x:", i << 4);
879 for (j = 0; j < 16; j++)
880 printf(" %02x", oem[(i<<4)+j]);
881 printf ("\n");
882 }
883 printf ("\n");
884}
885
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700886static void dump_fd(char *image, int size)
887{
Bill XIE612ec0e2017-08-30 16:10:27 +0800888 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700889 if (!fdb)
890 exit(EXIT_FAILURE);
891
Subrata Banik26058dc2020-08-26 15:12:16 +0530892 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
893 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700894 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530895 if (!is_platform_with_100x_series_pch())
896 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700897 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
898 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
899 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
900
901 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530902 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
903 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700904 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
905 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
906 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
907
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530908 if (!is_platform_with_100x_series_pch()) {
909 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
910 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
911 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
912 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700913
Subrata Banika5f47812020-09-29 11:43:01 +0530914 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530915 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
916 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
917 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
918 }
919
Stefan Tauner0d226142018-08-05 18:56:53 +0200920 char *flumap = find_flumap(image, size);
921 uint32_t flumap1 = *(uint32_t *)flumap;
922 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700923 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200924 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700925 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200926 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700927 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200928 (image + ((flumap1 & 0xff) << 4)),
929 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800930 dump_oem((const uint8_t *)image + 0xf00);
931
932 const frba_t *frba = find_frba(image, size);
933 const fcba_t *fcba = find_fcba(image, size);
934 const fpsba_t *fpsba = find_fpsba(image, size);
935 const fmba_t *fmba = find_fmba(image, size);
936 const fmsba_t *fmsba = find_fmsba(image, size);
937
938 if (frba && fcba && fpsba && fmba && fmsba) {
939 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530940 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200941 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800942 dump_fmba(fmba);
943 dump_fmsba(fmsba);
944 } else {
945 printf("FD is corrupted!\n");
946 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700947}
948
Bill XIEfa5f9942017-09-12 11:22:29 +0800949static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500950{
Bill XIE612ec0e2017-08-30 16:10:27 +0800951 const frba_t *frba = find_frba(image, size);
952 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500953 exit(EXIT_FAILURE);
954
Bill XIE612ec0e2017-08-30 16:10:27 +0800955 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500956}
957
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700958static void write_regions(char *image, int size)
959{
Bill XIEfa5f9942017-09-12 11:22:29 +0800960 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800961 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700962
Bill XIE612ec0e2017-08-30 16:10:27 +0800963 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700964 exit(EXIT_FAILURE);
965
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700966 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700967 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700968 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700969 if (region.size > 0) {
970 int region_fd;
971 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600972 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700973 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200974 if (region_fd < 0) {
975 perror("Error while trying to open file");
976 exit(EXIT_FAILURE);
977 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700978 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700979 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700980 close(region_fd);
981 }
982 }
983}
984
Mathew Kingc7ddc992019-08-08 14:59:25 -0600985static void validate_layout(char *image, int size)
986{
987 uint i, errors = 0;
988 struct fmap *fmap;
989 long int fmap_loc = fmap_find((uint8_t *)image, size);
990 const frba_t *frba = find_frba(image, size);
991
992 if (fmap_loc < 0 || !frba)
993 exit(EXIT_FAILURE);
994
995 fmap = (struct fmap *)(image + fmap_loc);
996
997 for (i = 0; i < max_regions; i++) {
998 if (region_names[i].fmapname == NULL)
999 continue;
1000
1001 region_t region = get_region(frba, i);
1002
1003 if (region.size == 0)
1004 continue;
1005
1006 const struct fmap_area *area =
1007 fmap_find_area(fmap, region_names[i].fmapname);
1008
1009 if (!area)
1010 continue;
1011
1012 if ((uint)region.base != area->offset ||
1013 (uint)region.size != area->size) {
1014 printf("Region mismatch between %s and %s\n",
1015 region_names[i].terse, area->name);
1016 printf(" Descriptor region %s:\n", region_names[i].terse);
1017 printf(" offset: 0x%08x\n", region.base);
1018 printf(" length: 0x%08x\n", region.size);
1019 printf(" FMAP area %s:\n", area->name);
1020 printf(" offset: 0x%08x\n", area->offset);
1021 printf(" length: 0x%08x\n", area->size);
1022 errors++;
1023 }
1024 }
1025
1026 if (errors > 0)
1027 exit(EXIT_FAILURE);
1028}
1029
Bill XIEfa5f9942017-09-12 11:22:29 +08001030static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001031{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001032 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001033 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001034
1035 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001036 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001037 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001038 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001039 if (new_fd < 0) {
1040 perror("Error while trying to open file");
1041 exit(EXIT_FAILURE);
1042 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001043 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001044 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001045 close(new_fd);
1046}
1047
Bill XIEfa5f9942017-09-12 11:22:29 +08001048static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001049 enum spi_frequency freq)
1050{
Bill XIE612ec0e2017-08-30 16:10:27 +08001051 fcba_t *fcba = find_fcba(image, size);
1052 if (!fcba)
1053 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001054
1055 /* clear bits 21-29 */
1056 fcba->flcomp &= ~0x3fe00000;
1057 /* Read ID and Read Status Clock Frequency */
1058 fcba->flcomp |= freq << 27;
1059 /* Write and Erase Clock Frequency */
1060 fcba->flcomp |= freq << 24;
1061 /* Fast Read Clock Frequency */
1062 fcba->flcomp |= freq << 21;
1063
1064 write_image(filename, image, size);
1065}
1066
Bill XIEfa5f9942017-09-12 11:22:29 +08001067static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001068{
Bill XIE612ec0e2017-08-30 16:10:27 +08001069 fcba_t *fcba = find_fcba(image, size);
1070 if (!fcba)
1071 exit(EXIT_FAILURE);
1072
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001073 int freq;
1074
1075 switch (ifd_version) {
1076 case IFD_VERSION_1:
1077 freq = SPI_FREQUENCY_20MHZ;
1078 break;
1079 case IFD_VERSION_2:
1080 freq = SPI_FREQUENCY_17MHZ;
1081 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001082 default:
1083 freq = SPI_FREQUENCY_17MHZ;
1084 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001085 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001086
1087 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001088 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001089}
1090
Bill XIEfa5f9942017-09-12 11:22:29 +08001091static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001092 unsigned int density)
1093{
Bill XIE612ec0e2017-08-30 16:10:27 +08001094 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001095 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001096 if (!fcba)
1097 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001098
1099 printf("Setting chip density to ");
1100 decode_component_density(density);
1101 printf("\n");
1102
1103 switch (ifd_version) {
1104 case IFD_VERSION_1:
1105 /* fail if selected density is not supported by this version */
1106 if ( (density == COMPONENT_DENSITY_32MB) ||
1107 (density == COMPONENT_DENSITY_64MB) ||
1108 (density == COMPONENT_DENSITY_UNUSED) ) {
1109 printf("error: Selected density not supported in IFD version 1.\n");
1110 exit(EXIT_FAILURE);
1111 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001112 mask = 0x7;
1113 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001114 break;
1115 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001116 mask = 0xf;
1117 chip2_offset = 4;
1118 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001119 default:
1120 printf("error: Unknown IFD version\n");
1121 exit(EXIT_FAILURE);
1122 break;
1123 }
1124
1125 /* clear chip density for corresponding chip */
1126 switch (selected_chip) {
1127 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001128 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001129 break;
1130 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001131 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001132 break;
1133 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001134 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001135 break;
1136 }
1137
1138 /* set the new density */
1139 if (selected_chip == 1 || selected_chip == 0)
1140 fcba->flcomp |= (density); /* first chip */
1141 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001142 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001143
1144 write_image(filename, image, size);
1145}
1146
Duncan Laurie7775d672019-06-06 13:39:26 -07001147static int check_region(const frba_t *frba, unsigned int region_type)
1148{
1149 region_t region;
1150
1151 if (!frba)
1152 return 0;
1153
1154 region = get_region(frba, region_type);
1155 return !!((region.base < region.limit) && (region.size > 0));
1156}
1157
Bill XIEfa5f9942017-09-12 11:22:29 +08001158static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001159{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001160 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001161 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001162 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001163 if (!fmba)
1164 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001165
1166 if (ifd_version >= IFD_VERSION_2) {
1167 wr_shift = FLMSTR_WR_SHIFT_V2;
1168 rd_shift = FLMSTR_RD_SHIFT_V2;
1169
1170 /* Clear non-reserved bits */
1171 fmba->flmstr1 &= 0xff;
1172 fmba->flmstr2 &= 0xff;
1173 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001174 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001175 } else {
1176 wr_shift = FLMSTR_WR_SHIFT_V1;
1177 rd_shift = FLMSTR_RD_SHIFT_V1;
1178
1179 fmba->flmstr1 = 0;
1180 fmba->flmstr2 = 0;
1181 /* Requestor ID */
1182 fmba->flmstr3 = 0x118;
1183 }
1184
Andrey Petrov96ecb772016-10-31 19:31:54 -07001185 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001186 case PLATFORM_APL:
1187 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001188 /* CPU/BIOS can read descriptor and BIOS */
1189 fmba->flmstr1 |= 0x3 << rd_shift;
1190 /* CPU/BIOS can write BIOS */
1191 fmba->flmstr1 |= 0x2 << wr_shift;
1192 /* TXE can read descriptor, BIOS and Device Expansion */
1193 fmba->flmstr2 |= 0x23 << rd_shift;
1194 /* TXE can only write Device Expansion */
1195 fmba->flmstr2 |= 0x20 << wr_shift;
1196 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001197 case PLATFORM_CNL:
1198 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001199 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001200 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301201 case PLATFORM_JSL:
Subrata Banik46f80732020-03-14 15:01:42 +05301202 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001203 /* CPU/BIOS can read descriptor and BIOS. */
1204 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1205 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1206 /* CPU/BIOS can write BIOS. */
1207 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1208 /* ME can read descriptor and ME. */
1209 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1210 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001211 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001212 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1213 if (check_region(frba, REGION_GBE)) {
1214 /* BIOS can read/write GbE. */
1215 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1216 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1217 /* ME can read GbE. */
1218 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1219 /* GbE can read descriptor and read/write GbE.. */
1220 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1221 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1222 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1223 }
1224 if (check_region(frba, REGION_PDR)) {
1225 /* BIOS can read/write PDR. */
1226 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1227 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1228 }
1229 if (check_region(frba, REGION_EC)) {
1230 /* BIOS can read EC. */
1231 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1232 /* EC can read descriptor and read/write EC. */
1233 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1234 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1235 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1236 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001237 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001238 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001239 /* CPU/BIOS can read descriptor and BIOS. */
1240 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1241 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1242 /* CPU/BIOS can write BIOS. */
1243 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1244 /* ME can read descriptor and ME. */
1245 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1246 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1247 /* ME can write ME. */
1248 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1249 if (check_region(frba, REGION_GBE)) {
1250 /* BIOS can read GbE. */
1251 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1252 /* BIOS can write GbE. */
1253 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1254 /* ME can read GbE. */
1255 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1256 /* ME can write GbE. */
1257 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1258 /* GbE can write GbE. */
1259 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1260 /* GbE can read GbE. */
1261 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1262 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001263 break;
1264 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001265
1266 write_image(filename, image, size);
1267}
1268
Usha P412679d2020-10-15 11:25:08 +05301269static void enable_cpu_read_me(const char *filename, char *image, int size)
1270{
1271 int rd_shift;
1272 fmba_t *fmba = find_fmba(image, size);
1273
1274 if (!fmba)
1275 exit(EXIT_FAILURE);
1276
1277 if (ifd_version >= IFD_VERSION_2)
1278 rd_shift = FLMSTR_RD_SHIFT_V2;
1279 else
1280 rd_shift = FLMSTR_RD_SHIFT_V1;
1281
1282 /* CPU/BIOS can read ME. */
1283 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1284
1285 write_image(filename, image, size);
1286}
1287
Bill XIEfa5f9942017-09-12 11:22:29 +08001288static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001289{
Bill XIE612ec0e2017-08-30 16:10:27 +08001290 fmba_t *fmba = find_fmba(image, size);
1291 if (!fmba)
1292 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001293
1294 if (ifd_version >= IFD_VERSION_2) {
1295 /* Access bits for each region are read: 19:8 write: 31:20 */
1296 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1297 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1298 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001299 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001300 } else {
1301 fmba->flmstr1 = 0xffff0000;
1302 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001303 /* Keep chipset specific Requester ID */
1304 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001305 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001306
1307 write_image(filename, image, size);
1308}
1309
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001310static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1311 const unsigned int value)
1312{
1313 if (!fpsba || !fdb) {
1314 fprintf(stderr, "Internal error\n");
1315 exit(EXIT_FAILURE);
1316 }
1317
1318 /* SoC Strap Length, aka PSL, aka ISL */
1319 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1320 if (strap >= SSL) {
1321 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1322 exit(EXIT_FAILURE);
1323 }
1324 fpsba->pchstrp[strap] = value;
1325}
1326
Bill XIEb3e15a22017-09-07 18:34:50 +08001327/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001328static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001329{
1330 if (ifd_version >= IFD_VERSION_2) {
1331 printf("%sting the HAP bit to %s Intel ME...\n",
1332 altmedisable?"Set":"Unset",
1333 altmedisable?"disable":"enable");
1334 if (altmedisable)
1335 fpsba->pchstrp[0] |= (1 << 16);
1336 else
1337 fpsba->pchstrp[0] &= ~(1 << 16);
1338 } else {
1339 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1340 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1341 "and MCH_AltMeDisable to %s Intel ME...\n",
1342 altmedisable?"Set":"Unset",
1343 altmedisable?"disable":"enable");
1344 if (altmedisable) {
1345 /* MCH_MeDisable */
1346 fmsba->data[0] |= 1;
1347 /* MCH_AltMeDisable */
1348 fmsba->data[0] |= (1 << 7);
1349 /* ICH_MeDisable */
1350 fpsba->pchstrp[0] |= 1;
1351 } else {
1352 fmsba->data[0] &= ~1;
1353 fmsba->data[0] &= ~(1 << 7);
1354 fpsba->pchstrp[0] &= ~1;
1355 }
1356 } else {
1357 printf("%sting the AltMeDisable to %s Intel ME...\n",
1358 altmedisable?"Set":"Unset",
1359 altmedisable?"disable":"enable");
1360 if (altmedisable)
1361 fpsba->pchstrp[10] |= (1 << 7);
1362 else
1363 fpsba->pchstrp[10] &= ~(1 << 7);
1364 }
1365 }
1366}
1367
Jacob Garber595d9262019-06-27 17:33:10 -06001368static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001369 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001370{
Bill XIE612ec0e2017-08-30 16:10:27 +08001371 frba_t *frba = find_frba(image, size);
1372 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001373 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001374
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001375 region_t region = get_region(frba, region_type);
1376 if (region.size <= 0xfff) {
1377 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1378 region_name(region_type));
1379 exit(EXIT_FAILURE);
1380 }
1381
Scott Duplichanf2c98372014-12-12 21:03:06 -06001382 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001383 if (region_fd == -1) {
1384 perror("Could not open file");
1385 exit(EXIT_FAILURE);
1386 }
1387 struct stat buf;
1388 if (fstat(region_fd, &buf) == -1) {
1389 perror("Could not stat file");
1390 exit(EXIT_FAILURE);
1391 }
1392 int region_size = buf.st_size;
1393
1394 printf("File %s is %d bytes\n", region_fname, region_size);
1395
1396 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001397 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001398 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1399 " bytes. Not injecting.\n",
1400 region_name(region_type), region.size,
1401 region.size, region_size, region_size);
1402 exit(EXIT_FAILURE);
1403 }
1404
1405 int offset = 0;
1406 if ((region_type == 1) && (region_size < region.size)) {
1407 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1408 " bytes. Padding before injecting.\n",
1409 region_name(region_type), region.size,
1410 region.size, region_size, region_size);
1411 offset = region.size - region_size;
1412 memset(image + region.base, 0xff, offset);
1413 }
1414
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001415 if (size < region.base + offset + region_size) {
1416 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1417 size, region.base + offset + region_size);
1418 exit(EXIT_FAILURE);
1419 }
1420
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001421 if (read(region_fd, image + region.base + offset, region_size)
1422 != region_size) {
1423 perror("Could not read file");
1424 exit(EXIT_FAILURE);
1425 }
1426
1427 close(region_fd);
1428
1429 printf("Adding %s as the %s section of %s\n",
1430 region_fname, region_name(region_type), filename);
1431 write_image(filename, image, size);
1432}
1433
Jacob Garber595d9262019-06-27 17:33:10 -06001434static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001435{
1436 unsigned int y = 1;
1437 if (x == 0)
1438 return 0;
1439 while (y <= x)
1440 y = y << 1;
1441
1442 return y;
1443}
1444
1445/**
1446 * Determine if two memory regions overlap.
1447 *
1448 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001449 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001450 * @return 1 if the two regions overlap
1451 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001452static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001453{
Bill XIEfa5f9942017-09-12 11:22:29 +08001454 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001455 return 0;
1456
Nico Huber844eda02019-01-05 00:06:19 +01001457 /* r1 should be either completely below or completely above r2 */
1458 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001459}
1460
Jacob Garber595d9262019-06-27 17:33:10 -06001461static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001462 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001463{
1464 FILE *romlayout;
1465 char tempstr[256];
1466 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001467 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001468 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001469 region_t current_regions[MAX_REGIONS];
1470 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001471 int new_extent = 0;
1472 char *new_image;
1473
1474 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001475 frba_t *frba = find_frba(image, size);
1476 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001477 exit(EXIT_FAILURE);
1478
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001479 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001480 current_regions[i] = get_region(frba, i);
1481 new_regions[i] = get_region(frba, i);
1482 }
1483
1484 /* read new layout */
1485 romlayout = fopen(layout_fname, "r");
1486
1487 if (!romlayout) {
1488 perror("Could not read layout file.\n");
1489 exit(EXIT_FAILURE);
1490 }
1491
1492 while (!feof(romlayout)) {
1493 char *tstr1, *tstr2;
1494
Patrick Georgi802ad522014-08-09 17:12:23 +02001495 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001496 layout_region_name))
1497 continue;
1498
1499 region_number = region_num(layout_region_name);
1500 if (region_number < 0)
1501 continue;
1502
1503 tstr1 = strtok(tempstr, ":");
1504 tstr2 = strtok(NULL, ":");
1505 if (!tstr1 || !tstr2) {
1506 fprintf(stderr, "Could not parse layout file.\n");
1507 exit(EXIT_FAILURE);
1508 }
1509 new_regions[region_number].base = strtol(tstr1,
1510 (char **)NULL, 16);
1511 new_regions[region_number].limit = strtol(tstr2,
1512 (char **)NULL, 16);
1513 new_regions[region_number].size =
1514 new_regions[region_number].limit -
1515 new_regions[region_number].base + 1;
1516
1517 if (new_regions[region_number].size < 0)
1518 new_regions[region_number].size = 0;
1519 }
1520 fclose(romlayout);
1521
1522 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001523 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001524 if (new_regions[i].size == 0)
1525 continue;
1526
1527 if (new_regions[i].size < current_regions[i].size) {
1528 printf("DANGER: Region %s is shrinking.\n",
1529 region_name(i));
1530 printf(" The region will be truncated to fit.\n");
1531 printf(" This may result in an unusable image.\n");
1532 }
1533
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001534 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001535 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001536 fprintf(stderr, "Regions would overlap.\n");
1537 exit(EXIT_FAILURE);
1538 }
1539 }
1540
1541 /* detect if the image size should grow */
1542 if (new_extent < new_regions[i].limit)
1543 new_extent = new_regions[i].limit;
1544 }
1545
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001546 /* check if the image is actually a Flash Descriptor region */
1547 if (size == new_regions[0].size) {
1548 printf("The image is a single Flash Descriptor:\n");
1549 printf(" Only the descriptor will be modified\n");
1550 new_extent = size;
1551 } else {
1552 new_extent = next_pow2(new_extent - 1);
1553 if (new_extent != size) {
1554 printf("The image has changed in size.\n");
1555 printf("The old image is %d bytes.\n", size);
1556 printf("The new image is %d bytes.\n", new_extent);
1557 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001558 }
1559
1560 /* copy regions to a new image */
1561 new_image = malloc(new_extent);
1562 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001563 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001564 int copy_size = new_regions[i].size;
1565 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001566 const region_t *current = &current_regions[i];
1567 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001568
Bill XIEfa5f9942017-09-12 11:22:29 +08001569 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001570 continue;
1571
Bill XIEfa5f9942017-09-12 11:22:29 +08001572 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001573 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001574 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001575 if (i == REGION_BIOS)
1576 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001577 }
1578
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001579 if ((i == REGION_BIOS) && (new->size < current->size)) {
1580 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001581 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001582 }
1583
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001584 if (size < current->base + offset_current + copy_size) {
1585 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1586 region_name(i));
1587 continue;
1588 };
1589
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001590 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1591 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001592 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1593 offset_current, current->limit, current->size);
1594 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1595 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001596
Bill XIEfa5f9942017-09-12 11:22:29 +08001597 memcpy(new_image + new->base + offset_new,
1598 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001599 copy_size);
1600 }
1601
1602 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001603 frba = find_frba(new_image, new_extent);
1604 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001605 exit(EXIT_FAILURE);
1606
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001607 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001608 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001609 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001610
1611 write_image(filename, new_image, new_extent);
1612 free(new_image);
1613}
1614
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001615static void print_version(void)
1616{
1617 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1618 printf("Copyright (C) 2011 Google Inc.\n\n");
1619 printf
1620 ("This program is free software: you can redistribute it and/or modify\n"
1621 "it under the terms of the GNU General Public License as published by\n"
1622 "the Free Software Foundation, version 2 of the License.\n\n"
1623 "This program is distributed in the hope that it will be useful,\n"
1624 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1625 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001626 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001627}
1628
1629static void print_usage(const char *name)
1630{
1631 printf("usage: %s [-vhdix?] <filename>\n", name);
1632 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001633 " -d | --dump: dump intel firmware descriptor\n"
1634 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1635 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1636 " -x | --extract: extract intel fd modules\n"
1637 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1638 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001639 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001640 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1641 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1642 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1643 " can only be used once per run:\n"
1644 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1645 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1646 " Dual Output Fast Read Support\n"
1647 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301648 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001649 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001650 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1651 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001652 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301653 " adl - Alder Lake\n"
1654 " aplk - Apollo Lake\n"
1655 " cnl - Cannon Lake\n"
1656 " glk - Gemini Lake\n"
1657 " icl - Ice Lake\n"
1658 " jsl - Jasper Lake\n"
1659 " sklkbl - Sky Lake/Kaby Lake\n"
1660 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001661 " -S | --setpchstrap Write a PCH strap\n"
1662 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001663 " -v | --version: print the version\n"
1664 " -h | --help: print this help\n\n"
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001665 "<region> is one of Descriptor, BIOS, ME, GbE, Platform, res1, res2, res3\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001666 "\n");
1667}
1668
1669int main(int argc, char *argv[])
1670{
1671 int opt, option_index = 0;
1672 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001673 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001674 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301675 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001676 char *region_type_string = NULL, *region_fname = NULL;
1677 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001678 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001679 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001680 unsigned int value = 0;
1681 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001682 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001683 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1684
Bill XIEfa5f9942017-09-12 11:22:29 +08001685 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001686 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001687 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001688 {"extract", 0, NULL, 'x'},
1689 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001690 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001691 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001692 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001693 {"density", 1, NULL, 'D'},
1694 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001695 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001696 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001697 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301698 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001699 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001700 {"version", 0, NULL, 'v'},
1701 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001702 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001703 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001704 {"setpchstrap", 1, NULL, 'S'},
1705 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001706 {0, 0, 0, 0}
1707 };
1708
Usha P412679d2020-10-15 11:25:08 +05301709 while ((opt = getopt_long(argc, argv, "S:V:df:D:C:M:xi:n:O:s:p:elruvth?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001710 long_options, &option_index)) != EOF) {
1711 switch (opt) {
1712 case 'd':
1713 mode_dump = 1;
1714 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001715 case 'S':
1716 mode_setstrap = 1;
1717 pchstrap = strtoul(optarg, NULL, 0);
1718 break;
1719 case 'V':
1720 value = strtoul(optarg, NULL, 0);
1721 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001722 case 'f':
1723 mode_layout = 1;
1724 layout_fname = strdup(optarg);
1725 if (!layout_fname) {
1726 fprintf(stderr, "No layout file specified\n");
1727 print_usage(argv[0]);
1728 exit(EXIT_FAILURE);
1729 }
1730 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001731 case 'x':
1732 mode_extract = 1;
1733 break;
1734 case 'i':
1735 // separate type and file name
1736 region_type_string = strdup(optarg);
1737 region_fname = strchr(region_type_string, ':');
1738 if (!region_fname) {
1739 print_usage(argv[0]);
1740 exit(EXIT_FAILURE);
1741 }
1742 region_fname[0] = '\0';
1743 region_fname++;
1744 // Descriptor, BIOS, ME, GbE, Platform
1745 // valid type?
1746 if (!strcasecmp("Descriptor", region_type_string))
1747 region_type = 0;
1748 else if (!strcasecmp("BIOS", region_type_string))
1749 region_type = 1;
1750 else if (!strcasecmp("ME", region_type_string))
1751 region_type = 2;
1752 else if (!strcasecmp("GbE", region_type_string))
1753 region_type = 3;
1754 else if (!strcasecmp("Platform", region_type_string))
1755 region_type = 4;
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001756 else if (!strcasecmp("res1", region_type_string))
1757 region_type = 5;
1758 else if (!strcasecmp("res2", region_type_string))
1759 region_type = 6;
1760 else if (!strcasecmp("res3", region_type_string))
1761 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001762 else if (!strcasecmp("EC", region_type_string))
1763 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001764 if (region_type == -1) {
1765 fprintf(stderr, "No such region type: '%s'\n\n",
1766 region_type_string);
1767 print_usage(argv[0]);
1768 exit(EXIT_FAILURE);
1769 }
1770 mode_inject = 1;
1771 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001772 case 'n':
1773 mode_newlayout = 1;
1774 layout_fname = strdup(optarg);
1775 if (!layout_fname) {
1776 fprintf(stderr, "No layout file specified\n");
1777 print_usage(argv[0]);
1778 exit(EXIT_FAILURE);
1779 }
1780 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001781 case 'O':
1782 new_filename = strdup(optarg);
1783 if (!new_filename) {
1784 fprintf(stderr, "No output filename specified\n");
1785 print_usage(argv[0]);
1786 exit(EXIT_FAILURE);
1787 }
1788 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001789 case 'D':
1790 mode_density = 1;
1791 new_density = strtoul(optarg, NULL, 0);
1792 switch (new_density) {
1793 case 512:
1794 new_density = COMPONENT_DENSITY_512KB;
1795 break;
1796 case 1:
1797 new_density = COMPONENT_DENSITY_1MB;
1798 break;
1799 case 2:
1800 new_density = COMPONENT_DENSITY_2MB;
1801 break;
1802 case 4:
1803 new_density = COMPONENT_DENSITY_4MB;
1804 break;
1805 case 8:
1806 new_density = COMPONENT_DENSITY_8MB;
1807 break;
1808 case 16:
1809 new_density = COMPONENT_DENSITY_16MB;
1810 break;
1811 case 32:
1812 new_density = COMPONENT_DENSITY_32MB;
1813 break;
1814 case 64:
1815 new_density = COMPONENT_DENSITY_64MB;
1816 break;
1817 case 0:
1818 new_density = COMPONENT_DENSITY_UNUSED;
1819 break;
1820 default:
1821 printf("error: Unknown density\n");
1822 print_usage(argv[0]);
1823 exit(EXIT_FAILURE);
1824 }
1825 break;
1826 case 'C':
1827 selected_chip = strtol(optarg, NULL, 0);
1828 if (selected_chip > 2) {
1829 fprintf(stderr, "error: Invalid chip selection\n");
1830 print_usage(argv[0]);
1831 exit(EXIT_FAILURE);
1832 }
1833 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001834 case 'M':
1835 mode_altmedisable = 1;
1836 altmedisable = strtol(optarg, NULL, 0);
1837 if (altmedisable > 1) {
1838 fprintf(stderr, "error: Illegal value\n");
1839 print_usage(argv[0]);
1840 exit(EXIT_FAILURE);
1841 }
1842 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001843 case 's':
1844 // Parse the requested SPI frequency
1845 inputfreq = strtol(optarg, NULL, 0);
1846 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001847 case 17:
1848 spifreq = SPI_FREQUENCY_17MHZ;
1849 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001850 case 20:
1851 spifreq = SPI_FREQUENCY_20MHZ;
1852 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001853 case 30:
1854 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1855 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001856 case 33:
1857 spifreq = SPI_FREQUENCY_33MHZ;
1858 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001859 case 48:
1860 spifreq = SPI_FREQUENCY_48MHZ;
1861 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001862 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001863 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001864 break;
1865 default:
1866 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1867 inputfreq);
1868 print_usage(argv[0]);
1869 exit(EXIT_FAILURE);
1870 }
1871 mode_spifreq = 1;
1872 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001873 case 'e':
1874 mode_em100 = 1;
1875 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001876 case 'l':
1877 mode_locked = 1;
1878 if (mode_unlocked == 1) {
1879 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1880 exit(EXIT_FAILURE);
1881 }
1882 break;
Usha P412679d2020-10-15 11:25:08 +05301883 case 'r':
1884 mode_read = 1;
1885 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001886 case 'u':
1887 mode_unlocked = 1;
1888 if (mode_locked == 1) {
1889 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1890 exit(EXIT_FAILURE);
1891 }
1892 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001893 case 'p':
1894 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001895 platform = PLATFORM_APL;
1896 } else if (!strcmp(optarg, "cnl")) {
1897 platform = PLATFORM_CNL;
1898 } else if (!strcmp(optarg, "glk")) {
1899 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301900 } else if (!strcmp(optarg, "icl")) {
1901 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301902 } else if (!strcmp(optarg, "jsl")) {
1903 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001904 } else if (!strcmp(optarg, "sklkbl")) {
1905 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001906 } else if (!strcmp(optarg, "tgl")) {
1907 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301908 } else if (!strcmp(optarg, "adl")) {
1909 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001910 } else {
1911 fprintf(stderr, "Unknown platform: %s\n", optarg);
1912 exit(EXIT_FAILURE);
1913 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001914 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001915 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001916 case 't':
1917 mode_validate = 1;
1918 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001919 case 'v':
1920 print_version();
1921 exit(EXIT_SUCCESS);
1922 break;
1923 case 'h':
1924 case '?':
1925 default:
1926 print_usage(argv[0]);
1927 exit(EXIT_SUCCESS);
1928 break;
1929 }
1930 }
1931
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001932 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001933 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001934 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001935 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001936 print_usage(argv[0]);
1937 exit(EXIT_FAILURE);
1938 }
1939
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001940 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001941 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001942 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001943 fprintf(stderr, "You need to specify a mode.\n\n");
1944 print_usage(argv[0]);
1945 exit(EXIT_FAILURE);
1946 }
1947
1948 if (optind + 1 != argc) {
1949 fprintf(stderr, "You need to specify a file.\n\n");
1950 print_usage(argv[0]);
1951 exit(EXIT_FAILURE);
1952 }
1953
1954 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001955 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001956 if (bios_fd == -1) {
1957 perror("Could not open file");
1958 exit(EXIT_FAILURE);
1959 }
1960 struct stat buf;
1961 if (fstat(bios_fd, &buf) == -1) {
1962 perror("Could not stat file");
1963 exit(EXIT_FAILURE);
1964 }
1965 int size = buf.st_size;
1966
1967 printf("File %s is %d bytes\n", filename, size);
1968
1969 char *image = malloc(size);
1970 if (!image) {
1971 printf("Out of memory.\n");
1972 exit(EXIT_FAILURE);
1973 }
1974
1975 if (read(bios_fd, image, size) != size) {
1976 perror("Could not read file");
1977 exit(EXIT_FAILURE);
1978 }
1979
1980 close(bios_fd);
1981
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001982 // generate new filename
1983 if (new_filename == NULL) {
1984 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1985 if (!new_filename) {
1986 printf("Out of memory.\n");
1987 exit(EXIT_FAILURE);
1988 }
1989 // - 5: leave room for ".new\0"
1990 strcpy(new_filename, filename);
1991 strcat(new_filename, ".new");
1992 }
1993
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001994 check_ifd_version(image, size);
1995
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001996 if (mode_dump)
1997 dump_fd(image, size);
1998
Chris Douglass03ce0142014-02-26 13:30:13 -05001999 if (mode_layout)
2000 dump_layout(image, size, layout_fname);
2001
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002002 if (mode_extract)
2003 write_regions(image, size);
2004
Mathew Kingc7ddc992019-08-08 14:59:25 -06002005 if (mode_validate)
2006 validate_layout(image, size);
2007
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002008 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002009 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002010 region_fname);
2011
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002012 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002013 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002014
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002015 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002016 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002017
Jan Tatjefa317512016-03-11 00:52:07 +01002018 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002019 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002020
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002021 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002022 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002023
Alexander Couzensd12ea112016-09-10 13:33:05 +02002024 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002025 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002026
Usha P412679d2020-10-15 11:25:08 +05302027 if (mode_read)
2028 enable_cpu_read_me(new_filename, image, size);
2029
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002030 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002031 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002032
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002033 if (mode_setstrap) {
2034 fpsba_t *fpsba = find_fpsba(image, size);
2035 const fdbar_t *fdb = find_fd(image, size);
2036 set_pchstrap(fpsba, fdb, pchstrap, value);
2037 write_image(new_filename, image, size);
2038 }
2039
Bill XIEb3e15a22017-09-07 18:34:50 +08002040 if (mode_altmedisable) {
2041 fpsba_t *fpsba = find_fpsba(image, size);
2042 fmsba_t *fmsba = find_fmsba(image, size);
2043 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002044 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002045 }
2046
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002047 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002048 free(image);
2049
2050 return 0;
2051}