blob: e2fd0abd1b58ffe64373f502e4f5b57e6208de56 [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
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{
563 if (chipset == CHIPSET_500_SERIES_TIGER_POINT)
564 _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 &&
616 chipset <= CHIPSET_500_SERIES_TIGER_POINT)
617 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: ");
641 if (chipset == CHIPSET_500_SERIES_TIGER_POINT)
642 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 Banikbd2da5a2020-08-26 15:43:51 +0530914 if (chipset == CHIPSET_500_SERIES_TIGER_POINT) {
915 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
Bill XIEfa5f9942017-09-12 11:22:29 +08001269static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001270{
Bill XIE612ec0e2017-08-30 16:10:27 +08001271 fmba_t *fmba = find_fmba(image, size);
1272 if (!fmba)
1273 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001274
1275 if (ifd_version >= IFD_VERSION_2) {
1276 /* Access bits for each region are read: 19:8 write: 31:20 */
1277 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1278 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1279 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001280 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001281 } else {
1282 fmba->flmstr1 = 0xffff0000;
1283 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001284 /* Keep chipset specific Requester ID */
1285 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001286 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001287
1288 write_image(filename, image, size);
1289}
1290
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001291static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1292 const unsigned int value)
1293{
1294 if (!fpsba || !fdb) {
1295 fprintf(stderr, "Internal error\n");
1296 exit(EXIT_FAILURE);
1297 }
1298
1299 /* SoC Strap Length, aka PSL, aka ISL */
1300 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1301 if (strap >= SSL) {
1302 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1303 exit(EXIT_FAILURE);
1304 }
1305 fpsba->pchstrp[strap] = value;
1306}
1307
Bill XIEb3e15a22017-09-07 18:34:50 +08001308/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001309static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001310{
1311 if (ifd_version >= IFD_VERSION_2) {
1312 printf("%sting the HAP bit to %s Intel ME...\n",
1313 altmedisable?"Set":"Unset",
1314 altmedisable?"disable":"enable");
1315 if (altmedisable)
1316 fpsba->pchstrp[0] |= (1 << 16);
1317 else
1318 fpsba->pchstrp[0] &= ~(1 << 16);
1319 } else {
1320 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1321 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1322 "and MCH_AltMeDisable to %s Intel ME...\n",
1323 altmedisable?"Set":"Unset",
1324 altmedisable?"disable":"enable");
1325 if (altmedisable) {
1326 /* MCH_MeDisable */
1327 fmsba->data[0] |= 1;
1328 /* MCH_AltMeDisable */
1329 fmsba->data[0] |= (1 << 7);
1330 /* ICH_MeDisable */
1331 fpsba->pchstrp[0] |= 1;
1332 } else {
1333 fmsba->data[0] &= ~1;
1334 fmsba->data[0] &= ~(1 << 7);
1335 fpsba->pchstrp[0] &= ~1;
1336 }
1337 } else {
1338 printf("%sting the AltMeDisable to %s Intel ME...\n",
1339 altmedisable?"Set":"Unset",
1340 altmedisable?"disable":"enable");
1341 if (altmedisable)
1342 fpsba->pchstrp[10] |= (1 << 7);
1343 else
1344 fpsba->pchstrp[10] &= ~(1 << 7);
1345 }
1346 }
1347}
1348
Jacob Garber595d9262019-06-27 17:33:10 -06001349static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001350 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001351{
Bill XIE612ec0e2017-08-30 16:10:27 +08001352 frba_t *frba = find_frba(image, size);
1353 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001354 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001355
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001356 region_t region = get_region(frba, region_type);
1357 if (region.size <= 0xfff) {
1358 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1359 region_name(region_type));
1360 exit(EXIT_FAILURE);
1361 }
1362
Scott Duplichanf2c98372014-12-12 21:03:06 -06001363 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001364 if (region_fd == -1) {
1365 perror("Could not open file");
1366 exit(EXIT_FAILURE);
1367 }
1368 struct stat buf;
1369 if (fstat(region_fd, &buf) == -1) {
1370 perror("Could not stat file");
1371 exit(EXIT_FAILURE);
1372 }
1373 int region_size = buf.st_size;
1374
1375 printf("File %s is %d bytes\n", region_fname, region_size);
1376
1377 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001378 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001379 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1380 " bytes. Not injecting.\n",
1381 region_name(region_type), region.size,
1382 region.size, region_size, region_size);
1383 exit(EXIT_FAILURE);
1384 }
1385
1386 int offset = 0;
1387 if ((region_type == 1) && (region_size < region.size)) {
1388 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1389 " bytes. Padding before injecting.\n",
1390 region_name(region_type), region.size,
1391 region.size, region_size, region_size);
1392 offset = region.size - region_size;
1393 memset(image + region.base, 0xff, offset);
1394 }
1395
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001396 if (size < region.base + offset + region_size) {
1397 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1398 size, region.base + offset + region_size);
1399 exit(EXIT_FAILURE);
1400 }
1401
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001402 if (read(region_fd, image + region.base + offset, region_size)
1403 != region_size) {
1404 perror("Could not read file");
1405 exit(EXIT_FAILURE);
1406 }
1407
1408 close(region_fd);
1409
1410 printf("Adding %s as the %s section of %s\n",
1411 region_fname, region_name(region_type), filename);
1412 write_image(filename, image, size);
1413}
1414
Jacob Garber595d9262019-06-27 17:33:10 -06001415static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001416{
1417 unsigned int y = 1;
1418 if (x == 0)
1419 return 0;
1420 while (y <= x)
1421 y = y << 1;
1422
1423 return y;
1424}
1425
1426/**
1427 * Determine if two memory regions overlap.
1428 *
1429 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001430 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001431 * @return 1 if the two regions overlap
1432 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001433static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001434{
Bill XIEfa5f9942017-09-12 11:22:29 +08001435 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001436 return 0;
1437
Nico Huber844eda02019-01-05 00:06:19 +01001438 /* r1 should be either completely below or completely above r2 */
1439 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001440}
1441
Jacob Garber595d9262019-06-27 17:33:10 -06001442static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001443 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001444{
1445 FILE *romlayout;
1446 char tempstr[256];
1447 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001448 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001449 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001450 region_t current_regions[MAX_REGIONS];
1451 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001452 int new_extent = 0;
1453 char *new_image;
1454
1455 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001456 frba_t *frba = find_frba(image, size);
1457 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001458 exit(EXIT_FAILURE);
1459
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001460 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001461 current_regions[i] = get_region(frba, i);
1462 new_regions[i] = get_region(frba, i);
1463 }
1464
1465 /* read new layout */
1466 romlayout = fopen(layout_fname, "r");
1467
1468 if (!romlayout) {
1469 perror("Could not read layout file.\n");
1470 exit(EXIT_FAILURE);
1471 }
1472
1473 while (!feof(romlayout)) {
1474 char *tstr1, *tstr2;
1475
Patrick Georgi802ad522014-08-09 17:12:23 +02001476 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001477 layout_region_name))
1478 continue;
1479
1480 region_number = region_num(layout_region_name);
1481 if (region_number < 0)
1482 continue;
1483
1484 tstr1 = strtok(tempstr, ":");
1485 tstr2 = strtok(NULL, ":");
1486 if (!tstr1 || !tstr2) {
1487 fprintf(stderr, "Could not parse layout file.\n");
1488 exit(EXIT_FAILURE);
1489 }
1490 new_regions[region_number].base = strtol(tstr1,
1491 (char **)NULL, 16);
1492 new_regions[region_number].limit = strtol(tstr2,
1493 (char **)NULL, 16);
1494 new_regions[region_number].size =
1495 new_regions[region_number].limit -
1496 new_regions[region_number].base + 1;
1497
1498 if (new_regions[region_number].size < 0)
1499 new_regions[region_number].size = 0;
1500 }
1501 fclose(romlayout);
1502
1503 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001504 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001505 if (new_regions[i].size == 0)
1506 continue;
1507
1508 if (new_regions[i].size < current_regions[i].size) {
1509 printf("DANGER: Region %s is shrinking.\n",
1510 region_name(i));
1511 printf(" The region will be truncated to fit.\n");
1512 printf(" This may result in an unusable image.\n");
1513 }
1514
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001515 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001516 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001517 fprintf(stderr, "Regions would overlap.\n");
1518 exit(EXIT_FAILURE);
1519 }
1520 }
1521
1522 /* detect if the image size should grow */
1523 if (new_extent < new_regions[i].limit)
1524 new_extent = new_regions[i].limit;
1525 }
1526
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001527 /* check if the image is actually a Flash Descriptor region */
1528 if (size == new_regions[0].size) {
1529 printf("The image is a single Flash Descriptor:\n");
1530 printf(" Only the descriptor will be modified\n");
1531 new_extent = size;
1532 } else {
1533 new_extent = next_pow2(new_extent - 1);
1534 if (new_extent != size) {
1535 printf("The image has changed in size.\n");
1536 printf("The old image is %d bytes.\n", size);
1537 printf("The new image is %d bytes.\n", new_extent);
1538 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001539 }
1540
1541 /* copy regions to a new image */
1542 new_image = malloc(new_extent);
1543 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001544 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001545 int copy_size = new_regions[i].size;
1546 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001547 const region_t *current = &current_regions[i];
1548 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001549
Bill XIEfa5f9942017-09-12 11:22:29 +08001550 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001551 continue;
1552
Bill XIEfa5f9942017-09-12 11:22:29 +08001553 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001554 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001555 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001556 if (i == REGION_BIOS)
1557 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001558 }
1559
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001560 if ((i == REGION_BIOS) && (new->size < current->size)) {
1561 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001562 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001563 }
1564
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001565 if (size < current->base + offset_current + copy_size) {
1566 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1567 region_name(i));
1568 continue;
1569 };
1570
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001571 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1572 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001573 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1574 offset_current, current->limit, current->size);
1575 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1576 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001577
Bill XIEfa5f9942017-09-12 11:22:29 +08001578 memcpy(new_image + new->base + offset_new,
1579 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001580 copy_size);
1581 }
1582
1583 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001584 frba = find_frba(new_image, new_extent);
1585 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001586 exit(EXIT_FAILURE);
1587
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001588 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001589 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001590 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001591
1592 write_image(filename, new_image, new_extent);
1593 free(new_image);
1594}
1595
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001596static void print_version(void)
1597{
1598 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1599 printf("Copyright (C) 2011 Google Inc.\n\n");
1600 printf
1601 ("This program is free software: you can redistribute it and/or modify\n"
1602 "it under the terms of the GNU General Public License as published by\n"
1603 "the Free Software Foundation, version 2 of the License.\n\n"
1604 "This program is distributed in the hope that it will be useful,\n"
1605 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1606 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001607 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001608}
1609
1610static void print_usage(const char *name)
1611{
1612 printf("usage: %s [-vhdix?] <filename>\n", name);
1613 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001614 " -d | --dump: dump intel firmware descriptor\n"
1615 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1616 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1617 " -x | --extract: extract intel fd modules\n"
1618 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1619 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001620 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001621 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1622 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1623 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1624 " can only be used once per run:\n"
1625 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1626 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1627 " Dual Output Fast Read Support\n"
1628 " -l | --lock Lock firmware descriptor and ME region\n"
1629 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001630 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1631 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001632 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301633 " adl - Alder Lake\n"
1634 " aplk - Apollo Lake\n"
1635 " cnl - Cannon Lake\n"
1636 " glk - Gemini Lake\n"
1637 " icl - Ice Lake\n"
1638 " jsl - Jasper Lake\n"
1639 " sklkbl - Sky Lake/Kaby Lake\n"
1640 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001641 " -S | --setpchstrap Write a PCH strap\n"
1642 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001643 " -v | --version: print the version\n"
1644 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001645 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1646 "\n");
1647}
1648
1649int main(int argc, char *argv[])
1650{
1651 int opt, option_index = 0;
1652 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001653 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001654 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001655 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001656 char *region_type_string = NULL, *region_fname = NULL;
1657 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001658 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001659 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001660 unsigned int value = 0;
1661 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001662 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001663 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1664
Bill XIEfa5f9942017-09-12 11:22:29 +08001665 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001666 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001667 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001668 {"extract", 0, NULL, 'x'},
1669 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001670 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001671 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001672 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001673 {"density", 1, NULL, 'D'},
1674 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001675 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001676 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001677 {"lock", 0, NULL, 'l'},
1678 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001679 {"version", 0, NULL, 'v'},
1680 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001681 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001682 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001683 {"setpchstrap", 1, NULL, 'S'},
1684 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001685 {0, 0, 0, 0}
1686 };
1687
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001688 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 -07001689 long_options, &option_index)) != EOF) {
1690 switch (opt) {
1691 case 'd':
1692 mode_dump = 1;
1693 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001694 case 'S':
1695 mode_setstrap = 1;
1696 pchstrap = strtoul(optarg, NULL, 0);
1697 break;
1698 case 'V':
1699 value = strtoul(optarg, NULL, 0);
1700 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001701 case 'f':
1702 mode_layout = 1;
1703 layout_fname = strdup(optarg);
1704 if (!layout_fname) {
1705 fprintf(stderr, "No layout file specified\n");
1706 print_usage(argv[0]);
1707 exit(EXIT_FAILURE);
1708 }
1709 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001710 case 'x':
1711 mode_extract = 1;
1712 break;
1713 case 'i':
1714 // separate type and file name
1715 region_type_string = strdup(optarg);
1716 region_fname = strchr(region_type_string, ':');
1717 if (!region_fname) {
1718 print_usage(argv[0]);
1719 exit(EXIT_FAILURE);
1720 }
1721 region_fname[0] = '\0';
1722 region_fname++;
1723 // Descriptor, BIOS, ME, GbE, Platform
1724 // valid type?
1725 if (!strcasecmp("Descriptor", region_type_string))
1726 region_type = 0;
1727 else if (!strcasecmp("BIOS", region_type_string))
1728 region_type = 1;
1729 else if (!strcasecmp("ME", region_type_string))
1730 region_type = 2;
1731 else if (!strcasecmp("GbE", region_type_string))
1732 region_type = 3;
1733 else if (!strcasecmp("Platform", region_type_string))
1734 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001735 else if (!strcasecmp("EC", region_type_string))
1736 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001737 if (region_type == -1) {
1738 fprintf(stderr, "No such region type: '%s'\n\n",
1739 region_type_string);
1740 print_usage(argv[0]);
1741 exit(EXIT_FAILURE);
1742 }
1743 mode_inject = 1;
1744 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001745 case 'n':
1746 mode_newlayout = 1;
1747 layout_fname = strdup(optarg);
1748 if (!layout_fname) {
1749 fprintf(stderr, "No layout file specified\n");
1750 print_usage(argv[0]);
1751 exit(EXIT_FAILURE);
1752 }
1753 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001754 case 'O':
1755 new_filename = strdup(optarg);
1756 if (!new_filename) {
1757 fprintf(stderr, "No output filename specified\n");
1758 print_usage(argv[0]);
1759 exit(EXIT_FAILURE);
1760 }
1761 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001762 case 'D':
1763 mode_density = 1;
1764 new_density = strtoul(optarg, NULL, 0);
1765 switch (new_density) {
1766 case 512:
1767 new_density = COMPONENT_DENSITY_512KB;
1768 break;
1769 case 1:
1770 new_density = COMPONENT_DENSITY_1MB;
1771 break;
1772 case 2:
1773 new_density = COMPONENT_DENSITY_2MB;
1774 break;
1775 case 4:
1776 new_density = COMPONENT_DENSITY_4MB;
1777 break;
1778 case 8:
1779 new_density = COMPONENT_DENSITY_8MB;
1780 break;
1781 case 16:
1782 new_density = COMPONENT_DENSITY_16MB;
1783 break;
1784 case 32:
1785 new_density = COMPONENT_DENSITY_32MB;
1786 break;
1787 case 64:
1788 new_density = COMPONENT_DENSITY_64MB;
1789 break;
1790 case 0:
1791 new_density = COMPONENT_DENSITY_UNUSED;
1792 break;
1793 default:
1794 printf("error: Unknown density\n");
1795 print_usage(argv[0]);
1796 exit(EXIT_FAILURE);
1797 }
1798 break;
1799 case 'C':
1800 selected_chip = strtol(optarg, NULL, 0);
1801 if (selected_chip > 2) {
1802 fprintf(stderr, "error: Invalid chip selection\n");
1803 print_usage(argv[0]);
1804 exit(EXIT_FAILURE);
1805 }
1806 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001807 case 'M':
1808 mode_altmedisable = 1;
1809 altmedisable = strtol(optarg, NULL, 0);
1810 if (altmedisable > 1) {
1811 fprintf(stderr, "error: Illegal value\n");
1812 print_usage(argv[0]);
1813 exit(EXIT_FAILURE);
1814 }
1815 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001816 case 's':
1817 // Parse the requested SPI frequency
1818 inputfreq = strtol(optarg, NULL, 0);
1819 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001820 case 17:
1821 spifreq = SPI_FREQUENCY_17MHZ;
1822 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001823 case 20:
1824 spifreq = SPI_FREQUENCY_20MHZ;
1825 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001826 case 30:
1827 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1828 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001829 case 33:
1830 spifreq = SPI_FREQUENCY_33MHZ;
1831 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001832 case 48:
1833 spifreq = SPI_FREQUENCY_48MHZ;
1834 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001835 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001836 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001837 break;
1838 default:
1839 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1840 inputfreq);
1841 print_usage(argv[0]);
1842 exit(EXIT_FAILURE);
1843 }
1844 mode_spifreq = 1;
1845 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001846 case 'e':
1847 mode_em100 = 1;
1848 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001849 case 'l':
1850 mode_locked = 1;
1851 if (mode_unlocked == 1) {
1852 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1853 exit(EXIT_FAILURE);
1854 }
1855 break;
1856 case 'u':
1857 mode_unlocked = 1;
1858 if (mode_locked == 1) {
1859 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1860 exit(EXIT_FAILURE);
1861 }
1862 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001863 case 'p':
1864 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001865 platform = PLATFORM_APL;
1866 } else if (!strcmp(optarg, "cnl")) {
1867 platform = PLATFORM_CNL;
1868 } else if (!strcmp(optarg, "glk")) {
1869 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301870 } else if (!strcmp(optarg, "icl")) {
1871 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301872 } else if (!strcmp(optarg, "jsl")) {
1873 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001874 } else if (!strcmp(optarg, "sklkbl")) {
1875 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001876 } else if (!strcmp(optarg, "tgl")) {
1877 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301878 } else if (!strcmp(optarg, "adl")) {
1879 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001880 } else {
1881 fprintf(stderr, "Unknown platform: %s\n", optarg);
1882 exit(EXIT_FAILURE);
1883 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001884 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001885 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001886 case 't':
1887 mode_validate = 1;
1888 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001889 case 'v':
1890 print_version();
1891 exit(EXIT_SUCCESS);
1892 break;
1893 case 'h':
1894 case '?':
1895 default:
1896 print_usage(argv[0]);
1897 exit(EXIT_SUCCESS);
1898 break;
1899 }
1900 }
1901
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001902 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001903 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001904 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001905 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001906 print_usage(argv[0]);
1907 exit(EXIT_FAILURE);
1908 }
1909
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001910 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001911 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001912 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001913 fprintf(stderr, "You need to specify a mode.\n\n");
1914 print_usage(argv[0]);
1915 exit(EXIT_FAILURE);
1916 }
1917
1918 if (optind + 1 != argc) {
1919 fprintf(stderr, "You need to specify a file.\n\n");
1920 print_usage(argv[0]);
1921 exit(EXIT_FAILURE);
1922 }
1923
1924 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001925 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001926 if (bios_fd == -1) {
1927 perror("Could not open file");
1928 exit(EXIT_FAILURE);
1929 }
1930 struct stat buf;
1931 if (fstat(bios_fd, &buf) == -1) {
1932 perror("Could not stat file");
1933 exit(EXIT_FAILURE);
1934 }
1935 int size = buf.st_size;
1936
1937 printf("File %s is %d bytes\n", filename, size);
1938
1939 char *image = malloc(size);
1940 if (!image) {
1941 printf("Out of memory.\n");
1942 exit(EXIT_FAILURE);
1943 }
1944
1945 if (read(bios_fd, image, size) != size) {
1946 perror("Could not read file");
1947 exit(EXIT_FAILURE);
1948 }
1949
1950 close(bios_fd);
1951
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001952 // generate new filename
1953 if (new_filename == NULL) {
1954 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1955 if (!new_filename) {
1956 printf("Out of memory.\n");
1957 exit(EXIT_FAILURE);
1958 }
1959 // - 5: leave room for ".new\0"
1960 strcpy(new_filename, filename);
1961 strcat(new_filename, ".new");
1962 }
1963
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001964 check_ifd_version(image, size);
1965
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001966 if (mode_dump)
1967 dump_fd(image, size);
1968
Chris Douglass03ce0142014-02-26 13:30:13 -05001969 if (mode_layout)
1970 dump_layout(image, size, layout_fname);
1971
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001972 if (mode_extract)
1973 write_regions(image, size);
1974
Mathew Kingc7ddc992019-08-08 14:59:25 -06001975 if (mode_validate)
1976 validate_layout(image, size);
1977
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001978 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001979 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001980 region_fname);
1981
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001982 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001983 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001984
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001985 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001986 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001987
Jan Tatjefa317512016-03-11 00:52:07 +01001988 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001989 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001990
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001991 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001992 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001993
Alexander Couzensd12ea112016-09-10 13:33:05 +02001994 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001995 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001996
1997 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001998 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001999
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002000 if (mode_setstrap) {
2001 fpsba_t *fpsba = find_fpsba(image, size);
2002 const fdbar_t *fdb = find_fd(image, size);
2003 set_pchstrap(fpsba, fdb, pchstrap, value);
2004 write_image(new_filename, image, size);
2005 }
2006
Bill XIEb3e15a22017-09-07 18:34:50 +08002007 if (mode_altmedisable) {
2008 fpsba_t *fpsba = find_fpsba(image, size);
2009 fmsba_t *fmsba = find_fmsba(image, size);
2010 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002011 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002012 }
2013
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002014 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002015 free(image);
2016
2017 return 0;
2018}