blob: 77fbd7ab668a2047d282f53f4c5f148579dd4fd5 [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,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700245 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530246 PLATFORM_ADL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700247 };
248 unsigned int i;
249
250 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
251 if (platform == ifd_2_platforms[i])
252 return 1;
253 }
254
255 return 0;
256}
257
258/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700259 * There is no version field in the descriptor so to determine
260 * if this is a new descriptor format we check the hardcoded SPI
261 * read frequency to see if it is fixed at 20MHz or 17MHz.
262 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700263static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700264{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700265 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800266 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800267 const fdbar_t *fdb = find_fd(image, size);
Subrata Banik89db2252020-08-26 14:49:17 +0530268 const fpsba_t *fpsba = find_fpsba(image, size);
Subrata Banik60296ae2020-09-06 18:50:14 +0530269 if (!fcba || !fdb || !fpsba)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700270 exit(EXIT_FAILURE);
271
Subrata Banik89db2252020-08-26 14:49:17 +0530272 chipset = guess_ich_chipset(fdb, fpsba);
Bill XIEb3e15a22017-09-07 18:34:50 +0800273 /* TODO: port ifd_version and max_regions
274 * against guess_ich_chipset()
275 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700276 read_freq = (fcba->flcomp >> 17) & 7;
277
278 switch (read_freq) {
279 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700280 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700281 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700282 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700283 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700284 default:
285 fprintf(stderr, "Unknown descriptor version: %d\n",
286 read_freq);
287 exit(EXIT_FAILURE);
288 }
289}
290
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700291static void check_ifd_version(char *image, int size)
292{
293 if (is_platform_ifd_2())
294 ifd_version = IFD_VERSION_2;
295 else
296 ifd_version = get_ifd_version_from_fcba(image, size);
297
298 if (ifd_version == IFD_VERSION_1)
299 max_regions = MAX_REGIONS_OLD;
300 else
301 max_regions = MAX_REGIONS;
302}
303
Bill XIEfa5f9942017-09-12 11:22:29 +0800304static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700305{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500306 int base_mask;
307 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700308 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700309 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500310
311 if (ifd_version >= IFD_VERSION_2)
312 base_mask = 0x7fff;
313 else
314 base_mask = 0xfff;
315
316 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700317
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400318 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800319 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700320 exit (EXIT_FAILURE);
321 }
322
Bill XIE4651d452017-09-12 11:54:48 +0800323 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700324 region.base = (flreg & base_mask) << 12;
325 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700326 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500327
Chris Douglass03ce0142014-02-26 13:30:13 -0500328 if (region.size < 0)
329 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700330
331 return region;
332}
333
Bill XIEfa5f9942017-09-12 11:22:29 +0800334static void set_region(frba_t *frba, unsigned int region_type,
335 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500336{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400337 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800338 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500339 exit (EXIT_FAILURE);
340 }
Bill XIE4651d452017-09-12 11:54:48 +0800341
342 frba->flreg[region_type] =
343 (((region->limit >> 12) & 0x7fff) << 16) |
344 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500345}
346
Bill XIEfa5f9942017-09-12 11:22:29 +0800347static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700348{
Bill XIEfa5f9942017-09-12 11:22:29 +0800349 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700350 fprintf(stderr, "Invalid region type.\n");
351 exit (EXIT_FAILURE);
352 }
353
Chris Douglass03ce0142014-02-26 13:30:13 -0500354 return region_names[region_type].pretty;
355}
356
Bill XIEfa5f9942017-09-12 11:22:29 +0800357static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500358{
Bill XIEfa5f9942017-09-12 11:22:29 +0800359 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500360 fprintf(stderr, "Invalid region type.\n");
361 exit (EXIT_FAILURE);
362 }
363
364 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700365}
366
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500367static int region_num(const char *name)
368{
Bill XIEfa5f9942017-09-12 11:22:29 +0800369 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500370
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200371 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500372 if (strcasecmp(name, region_names[i].pretty) == 0)
373 return i;
374 if (strcasecmp(name, region_names[i].terse) == 0)
375 return i;
376 }
377
378 return -1;
379}
380
Bill XIEfa5f9942017-09-12 11:22:29 +0800381static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700382{
Bill XIEfa5f9942017-09-12 11:22:29 +0800383 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700384 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700385 exit (EXIT_FAILURE);
386 }
387
Bill XIE1bf65062017-09-12 11:31:37 +0800388 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700389}
390
Bill XIEfa5f9942017-09-12 11:22:29 +0800391static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700392{
393 region_t region = get_region(frba, num);
394 printf(" Flash Region %d (%s): %08x - %08x %s\n",
395 num, region_name(num), region.base, region.limit,
396 region.size < 1 ? "(unused)" : "");
397}
398
Bill XIEfa5f9942017-09-12 11:22:29 +0800399static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
400 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500401{
402 region_t region = get_region(frba, num);
403 snprintf(buf, bufsize, "%08x:%08x %s\n",
404 region.base, region.limit, region_name_short(num));
405}
406
Bill XIEfa5f9942017-09-12 11:22:29 +0800407static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700408{
Bill XIE4651d452017-09-12 11:54:48 +0800409 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530410 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700411 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800412 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530413 region = get_region(frba, i);
414 /* Skip unused & reserved Flash Region */
415 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
416 continue;
417
Bill XIE4651d452017-09-12 11:54:48 +0800418 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
419 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700420 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700421}
422
Bill XIEfa5f9942017-09-12 11:22:29 +0800423static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500424{
425 char buf[LAYOUT_LINELEN];
426 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800427 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500428
429 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
430 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
431 if (layout_fd == -1) {
432 perror("Could not open file");
433 exit(EXIT_FAILURE);
434 }
435
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200436 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200437 region_t region = get_region(frba, i);
438 /* is region invalid? */
439 if (region.size < 1)
440 continue;
441
Chris Douglass03ce0142014-02-26 13:30:13 -0500442 dump_region_layout(buf, bufsize, i, frba);
443 if (write(layout_fd, buf, strlen(buf)) < 0) {
444 perror("Could not write to file");
445 exit(EXIT_FAILURE);
446 }
447 }
448 close(layout_fd);
449 printf("Wrote layout to %s\n", layout_fname);
450}
451
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530452static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700453{
454 switch (freq) {
455 case SPI_FREQUENCY_20MHZ:
456 printf("20MHz");
457 break;
458 case SPI_FREQUENCY_33MHZ:
459 printf("33MHz");
460 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700461 case SPI_FREQUENCY_48MHZ:
462 printf("48MHz");
463 break;
464 case SPI_FREQUENCY_50MHZ_30MHZ:
465 switch (ifd_version) {
466 case IFD_VERSION_1:
467 printf("50MHz");
468 break;
469 case IFD_VERSION_2:
470 printf("30MHz");
471 break;
472 }
473 break;
474 case SPI_FREQUENCY_17MHZ:
475 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700476 break;
477 default:
478 printf("unknown<%x>MHz", freq);
479 }
480}
481
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530482static void _decode_spi_frequency_500_series(unsigned int freq)
483{
484 switch (freq) {
485 case SPI_FREQUENCY_100MHZ:
486 printf("100MHz");
487 break;
488 case SPI_FREQUENCY_50MHZ:
489 printf("50MHz");
490 break;
491 case SPI_FREQUENCY_500SERIES_33MHZ:
492 printf("33MHz");
493 break;
494 case SPI_FREQUENCY_25MHZ:
495 printf("25MHz");
496 break;
497 case SPI_FREQUENCY_14MHZ:
498 printf("14MHz");
499 break;
500 default:
501 printf("unknown<%x>MHz", freq);
502 }
503}
504
505static void decode_spi_frequency(unsigned int freq)
506{
Subrata Banika5f47812020-09-29 11:43:01 +0530507 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530508 _decode_spi_frequency_500_series(freq);
509 else
510 _decode_spi_frequency(freq);
511}
512
Subrata Banike5d39922020-08-26 16:01:42 +0530513static void _decode_espi_frequency(unsigned int freq)
514{
515 switch (freq) {
516 case ESPI_FREQUENCY_20MHZ:
517 printf("20MHz");
518 break;
519 case ESPI_FREQUENCY_24MHZ:
520 printf("24MHz");
521 break;
522 case ESPI_FREQUENCY_30MHZ:
523 printf("30MHz");
524 break;
525 case ESPI_FREQUENCY_48MHZ:
526 printf("48MHz");
527 break;
528 case ESPI_FREQUENCY_60MHZ:
529 printf("60MHz");
530 break;
531 case ESPI_FREQUENCY_17MHZ:
532 printf("17MHz");
533 break;
534 default:
535 printf("unknown<%x>MHz", freq);
536 }
537}
538
539static void _decode_espi_frequency_500_series(unsigned int freq)
540{
541 switch (freq) {
542 case ESPI_FREQUENCY_500SERIES_20MHZ:
543 printf("20MHz");
544 break;
545 case ESPI_FREQUENCY_500SERIES_24MHZ:
546 printf("24MHz");
547 break;
548 case ESPI_FREQUENCY_500SERIES_25MHZ:
549 printf("25MHz");
550 break;
551 case ESPI_FREQUENCY_500SERIES_48MHZ:
552 printf("48MHz");
553 break;
554 case ESPI_FREQUENCY_500SERIES_60MHZ:
555 printf("60MHz");
556 break;
557 default:
558 printf("unknown<%x>MHz", freq);
559 }
560}
561
562static void decode_espi_frequency(unsigned int freq)
563{
Subrata Banika5f47812020-09-29 11:43:01 +0530564 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530565 _decode_espi_frequency_500_series(freq);
566 else
567 _decode_espi_frequency(freq);
568}
569
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700570static void decode_component_density(unsigned int density)
571{
572 switch (density) {
573 case COMPONENT_DENSITY_512KB:
574 printf("512KB");
575 break;
576 case COMPONENT_DENSITY_1MB:
577 printf("1MB");
578 break;
579 case COMPONENT_DENSITY_2MB:
580 printf("2MB");
581 break;
582 case COMPONENT_DENSITY_4MB:
583 printf("4MB");
584 break;
585 case COMPONENT_DENSITY_8MB:
586 printf("8MB");
587 break;
588 case COMPONENT_DENSITY_16MB:
589 printf("16MB");
590 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700591 case COMPONENT_DENSITY_32MB:
592 printf("32MB");
593 break;
594 case COMPONENT_DENSITY_64MB:
595 printf("64MB");
596 break;
597 case COMPONENT_DENSITY_UNUSED:
598 printf("UNUSED");
599 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700600 default:
601 printf("unknown<%x>MB", density);
602 }
603}
604
Subrata Banik26058dc2020-08-26 15:12:16 +0530605static int is_platform_with_pch(void)
606{
607 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
608 return 1;
609
610 return 0;
611}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530612
613/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
614static int is_platform_with_100x_series_pch(void)
615{
616 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530617 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530618 return 1;
619
620 return 0;
621}
622
Subrata Banike5d39922020-08-26 16:01:42 +0530623static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700624{
Subrata Banike5d39922020-08-26 16:01:42 +0530625 unsigned int freq;
626
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700627 printf("\nFound Component Section\n");
628 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700629 printf(" Dual Output Fast Read Support: %ssupported\n",
630 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700631 printf(" Read ID/Read Status Clock Frequency: ");
632 decode_spi_frequency((fcba->flcomp >> 27) & 7);
633 printf("\n Write/Erase Clock Frequency: ");
634 decode_spi_frequency((fcba->flcomp >> 24) & 7);
635 printf("\n Fast Read Clock Frequency: ");
636 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700637 printf("\n Fast Read Support: %ssupported",
638 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530639 if (is_platform_with_100x_series_pch() &&
640 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
641 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530642 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530643 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
644 else
645 freq = (fcba->flcomp >> 17) & 7;
646 decode_espi_frequency(freq);
647 } else {
648 printf("\n Read Clock Frequency: ");
649 decode_spi_frequency((fcba->flcomp >> 17) & 7);
650 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700651
652 switch (ifd_version) {
653 case IFD_VERSION_1:
654 printf("\n Component 2 Density: ");
655 decode_component_density((fcba->flcomp >> 3) & 7);
656 printf("\n Component 1 Density: ");
657 decode_component_density(fcba->flcomp & 7);
658 break;
659 case IFD_VERSION_2:
660 printf("\n Component 2 Density: ");
661 decode_component_density((fcba->flcomp >> 4) & 0xf);
662 printf("\n Component 1 Density: ");
663 decode_component_density(fcba->flcomp & 0xf);
664 break;
665 }
666
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700667 printf("\n");
668 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700669 printf(" Invalid Instruction 3: 0x%02x\n",
670 (fcba->flill >> 24) & 0xff);
671 printf(" Invalid Instruction 2: 0x%02x\n",
672 (fcba->flill >> 16) & 0xff);
673 printf(" Invalid Instruction 1: 0x%02x\n",
674 (fcba->flill >> 8) & 0xff);
675 printf(" Invalid Instruction 0: 0x%02x\n",
676 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530677 if (is_platform_with_100x_series_pch()) {
678 printf("FLILL1 0x%08x\n", fcba->flpb);
679 printf(" Invalid Instruction 7: 0x%02x\n",
680 (fcba->flpb >> 24) & 0xff);
681 printf(" Invalid Instruction 6: 0x%02x\n",
682 (fcba->flpb >> 16) & 0xff);
683 printf(" Invalid Instruction 5: 0x%02x\n",
684 (fcba->flpb >> 8) & 0xff);
685 printf(" Invalid Instruction 4: 0x%02x\n",
686 fcba->flpb & 0xff);
687 } else {
688 printf("FLPB 0x%08x\n", fcba->flpb);
689 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
690 (fcba->flpb & 0xfff) << 12);
691 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700692}
693
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200694static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700695{
Bill XIE4651d452017-09-12 11:54:48 +0800696 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200697 /* SoC Strap Length, aka PSL, aka ISL */
698 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
699
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700700 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200701 for (i = 0; i < SSL; i++)
702 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800703
704 if (ifd_version >= IFD_VERSION_2) {
705 printf("HAP bit is %sset\n",
706 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
707 } else if (chipset >= CHIPSET_ICH8
708 && chipset <= CHIPSET_ICH10) {
709 printf("ICH_MeDisable bit is %sset\n",
710 fpsba->pchstrp[0] & 1 ? "" : "not ");
711 } else {
712 printf("AltMeDisable bit is %sset\n",
713 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
714 }
715
Bill XIE4651d452017-09-12 11:54:48 +0800716 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700717}
718
719static void decode_flmstr(uint32_t flmstr)
720{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700721 int wr_shift, rd_shift;
722 if (ifd_version >= IFD_VERSION_2) {
723 wr_shift = FLMSTR_WR_SHIFT_V2;
724 rd_shift = FLMSTR_RD_SHIFT_V2;
725 } else {
726 wr_shift = FLMSTR_WR_SHIFT_V1;
727 rd_shift = FLMSTR_RD_SHIFT_V1;
728 }
729
730 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700731 if (ifd_version >= IFD_VERSION_2)
732 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700733 (flmstr & (1 << (wr_shift + 8))) ?
734 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700735 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700736 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700737 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700738 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700739 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700740 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700741 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700742 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700743 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700744 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700745
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700746 if (ifd_version >= IFD_VERSION_2)
747 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700748 (flmstr & (1 << (rd_shift + 8))) ?
749 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700750 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700751 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700752 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700753 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700754 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700755 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700756 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700757 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700758 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700759 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700760
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700761 /* Requestor ID doesn't exist for ifd 2 */
762 if (ifd_version < IFD_VERSION_2)
763 printf(" Requester ID: 0x%04x\n\n",
764 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700765}
766
Bill XIEfa5f9942017-09-12 11:22:29 +0800767static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700768{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700769 printf("Found Master Section\n");
770 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
771 decode_flmstr(fmba->flmstr1);
772 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
773 decode_flmstr(fmba->flmstr2);
774 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
775 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700776 if (ifd_version >= IFD_VERSION_2) {
777 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
778 decode_flmstr(fmba->flmstr5);
779 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700780}
781
Bill XIEfa5f9942017-09-12 11:22:29 +0800782static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700783{
Bill XIE612ec0e2017-08-30 16:10:27 +0800784 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700785 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800786 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
787 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800788
789 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
790 printf("MCH_MeDisable bit is %sset\n",
791 fmsba->data[0] & 1 ? "" : "not ");
792 printf("MCH_AltMeDisable bit is %sset\n",
793 fmsba->data[0] & (1 << 7) ? "" : "not ");
794 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700795}
796
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700797static void dump_jid(uint32_t jid)
798{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100799 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700800 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100801 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200802 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100803 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200804 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700805}
806
807static void dump_vscc(uint32_t vscc)
808{
809 printf(" Lower Erase Opcode: 0x%02x\n",
810 vscc >> 24);
811 printf(" Lower Write Enable on Write Status: 0x%02x\n",
812 vscc & (1 << 20) ? 0x06 : 0x50);
813 printf(" Lower Write Status Required: %s\n",
814 vscc & (1 << 19) ? "Yes" : "No");
815 printf(" Lower Write Granularity: %d bytes\n",
816 vscc & (1 << 18) ? 64 : 1);
817 printf(" Lower Block / Sector Erase Size: ");
818 switch ((vscc >> 16) & 0x3) {
819 case 0:
820 printf("256 Byte\n");
821 break;
822 case 1:
823 printf("4KB\n");
824 break;
825 case 2:
826 printf("8KB\n");
827 break;
828 case 3:
829 printf("64KB\n");
830 break;
831 }
832
833 printf(" Upper Erase Opcode: 0x%02x\n",
834 (vscc >> 8) & 0xff);
835 printf(" Upper Write Enable on Write Status: 0x%02x\n",
836 vscc & (1 << 4) ? 0x06 : 0x50);
837 printf(" Upper Write Status Required: %s\n",
838 vscc & (1 << 3) ? "Yes" : "No");
839 printf(" Upper Write Granularity: %d bytes\n",
840 vscc & (1 << 2) ? 64 : 1);
841 printf(" Upper Block / Sector Erase Size: ");
842 switch (vscc & 0x3) {
843 case 0:
844 printf("256 Byte\n");
845 break;
846 case 1:
847 printf("4KB\n");
848 break;
849 case 2:
850 printf("8KB\n");
851 break;
852 case 3:
853 printf("64KB\n");
854 break;
855 }
856}
857
Bill XIEfa5f9942017-09-12 11:22:29 +0800858static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700859{
860 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200861 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
862 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700863
864 printf("ME VSCC table:\n");
865 for (i = 0; i < num; i++) {
866 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
867 dump_jid(vtba->entry[i].jid);
868 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
869 dump_vscc(vtba->entry[i].vscc);
870 }
871 printf("\n");
872}
873
Bill XIEfa5f9942017-09-12 11:22:29 +0800874static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700875{
876 int i, j;
877 printf("OEM Section:\n");
878 for (i = 0; i < 4; i++) {
879 printf("%02x:", i << 4);
880 for (j = 0; j < 16; j++)
881 printf(" %02x", oem[(i<<4)+j]);
882 printf ("\n");
883 }
884 printf ("\n");
885}
886
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700887static void dump_fd(char *image, int size)
888{
Bill XIE612ec0e2017-08-30 16:10:27 +0800889 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700890 if (!fdb)
891 exit(EXIT_FAILURE);
892
Subrata Banik26058dc2020-08-26 15:12:16 +0530893 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
894 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700895 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530896 if (!is_platform_with_100x_series_pch())
897 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700898 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
899 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
900 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
901
902 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530903 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
904 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700905 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
906 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
907 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
908
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530909 if (!is_platform_with_100x_series_pch()) {
910 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
911 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
912 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
913 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700914
Subrata Banika5f47812020-09-29 11:43:01 +0530915 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530916 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
917 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
918 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
919 }
920
Stefan Tauner0d226142018-08-05 18:56:53 +0200921 char *flumap = find_flumap(image, size);
922 uint32_t flumap1 = *(uint32_t *)flumap;
923 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700924 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200925 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700926 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200927 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700928 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200929 (image + ((flumap1 & 0xff) << 4)),
930 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800931 dump_oem((const uint8_t *)image + 0xf00);
932
933 const frba_t *frba = find_frba(image, size);
934 const fcba_t *fcba = find_fcba(image, size);
935 const fpsba_t *fpsba = find_fpsba(image, size);
936 const fmba_t *fmba = find_fmba(image, size);
937 const fmsba_t *fmsba = find_fmsba(image, size);
938
939 if (frba && fcba && fpsba && fmba && fmsba) {
940 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530941 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200942 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800943 dump_fmba(fmba);
944 dump_fmsba(fmsba);
945 } else {
946 printf("FD is corrupted!\n");
947 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700948}
949
Bill XIEfa5f9942017-09-12 11:22:29 +0800950static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500951{
Bill XIE612ec0e2017-08-30 16:10:27 +0800952 const frba_t *frba = find_frba(image, size);
953 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500954 exit(EXIT_FAILURE);
955
Bill XIE612ec0e2017-08-30 16:10:27 +0800956 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500957}
958
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700959static void write_regions(char *image, int size)
960{
Bill XIEfa5f9942017-09-12 11:22:29 +0800961 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800962 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700963
Bill XIE612ec0e2017-08-30 16:10:27 +0800964 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700965 exit(EXIT_FAILURE);
966
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700967 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700968 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700969 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700970 if (region.size > 0) {
971 int region_fd;
972 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600973 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700974 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200975 if (region_fd < 0) {
976 perror("Error while trying to open file");
977 exit(EXIT_FAILURE);
978 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700979 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700980 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700981 close(region_fd);
982 }
983 }
984}
985
Mathew Kingc7ddc992019-08-08 14:59:25 -0600986static void validate_layout(char *image, int size)
987{
988 uint i, errors = 0;
989 struct fmap *fmap;
990 long int fmap_loc = fmap_find((uint8_t *)image, size);
991 const frba_t *frba = find_frba(image, size);
992
993 if (fmap_loc < 0 || !frba)
994 exit(EXIT_FAILURE);
995
996 fmap = (struct fmap *)(image + fmap_loc);
997
998 for (i = 0; i < max_regions; i++) {
999 if (region_names[i].fmapname == NULL)
1000 continue;
1001
1002 region_t region = get_region(frba, i);
1003
1004 if (region.size == 0)
1005 continue;
1006
1007 const struct fmap_area *area =
1008 fmap_find_area(fmap, region_names[i].fmapname);
1009
1010 if (!area)
1011 continue;
1012
1013 if ((uint)region.base != area->offset ||
1014 (uint)region.size != area->size) {
1015 printf("Region mismatch between %s and %s\n",
1016 region_names[i].terse, area->name);
1017 printf(" Descriptor region %s:\n", region_names[i].terse);
1018 printf(" offset: 0x%08x\n", region.base);
1019 printf(" length: 0x%08x\n", region.size);
1020 printf(" FMAP area %s:\n", area->name);
1021 printf(" offset: 0x%08x\n", area->offset);
1022 printf(" length: 0x%08x\n", area->size);
1023 errors++;
1024 }
1025 }
1026
1027 if (errors > 0)
1028 exit(EXIT_FAILURE);
1029}
1030
Bill XIEfa5f9942017-09-12 11:22:29 +08001031static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001032{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001033 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001034 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001035
1036 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001037 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001038 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001039 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001040 if (new_fd < 0) {
1041 perror("Error while trying to open file");
1042 exit(EXIT_FAILURE);
1043 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001044 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001045 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001046 close(new_fd);
1047}
1048
Bill XIEfa5f9942017-09-12 11:22:29 +08001049static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001050 enum spi_frequency freq)
1051{
Bill XIE612ec0e2017-08-30 16:10:27 +08001052 fcba_t *fcba = find_fcba(image, size);
1053 if (!fcba)
1054 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001055
1056 /* clear bits 21-29 */
1057 fcba->flcomp &= ~0x3fe00000;
1058 /* Read ID and Read Status Clock Frequency */
1059 fcba->flcomp |= freq << 27;
1060 /* Write and Erase Clock Frequency */
1061 fcba->flcomp |= freq << 24;
1062 /* Fast Read Clock Frequency */
1063 fcba->flcomp |= freq << 21;
1064
1065 write_image(filename, image, size);
1066}
1067
Bill XIEfa5f9942017-09-12 11:22:29 +08001068static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001069{
Bill XIE612ec0e2017-08-30 16:10:27 +08001070 fcba_t *fcba = find_fcba(image, size);
1071 if (!fcba)
1072 exit(EXIT_FAILURE);
1073
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001074 int freq;
1075
1076 switch (ifd_version) {
1077 case IFD_VERSION_1:
1078 freq = SPI_FREQUENCY_20MHZ;
1079 break;
1080 case IFD_VERSION_2:
1081 freq = SPI_FREQUENCY_17MHZ;
1082 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001083 default:
1084 freq = SPI_FREQUENCY_17MHZ;
1085 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001086 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001087
1088 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001089 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001090}
1091
Bill XIEfa5f9942017-09-12 11:22:29 +08001092static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001093 unsigned int density)
1094{
Bill XIE612ec0e2017-08-30 16:10:27 +08001095 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001096 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001097 if (!fcba)
1098 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001099
1100 printf("Setting chip density to ");
1101 decode_component_density(density);
1102 printf("\n");
1103
1104 switch (ifd_version) {
1105 case IFD_VERSION_1:
1106 /* fail if selected density is not supported by this version */
1107 if ( (density == COMPONENT_DENSITY_32MB) ||
1108 (density == COMPONENT_DENSITY_64MB) ||
1109 (density == COMPONENT_DENSITY_UNUSED) ) {
1110 printf("error: Selected density not supported in IFD version 1.\n");
1111 exit(EXIT_FAILURE);
1112 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001113 mask = 0x7;
1114 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001115 break;
1116 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001117 mask = 0xf;
1118 chip2_offset = 4;
1119 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001120 default:
1121 printf("error: Unknown IFD version\n");
1122 exit(EXIT_FAILURE);
1123 break;
1124 }
1125
1126 /* clear chip density for corresponding chip */
1127 switch (selected_chip) {
1128 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001129 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001130 break;
1131 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001132 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001133 break;
1134 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001135 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001136 break;
1137 }
1138
1139 /* set the new density */
1140 if (selected_chip == 1 || selected_chip == 0)
1141 fcba->flcomp |= (density); /* first chip */
1142 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001143 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001144
1145 write_image(filename, image, size);
1146}
1147
Duncan Laurie7775d672019-06-06 13:39:26 -07001148static int check_region(const frba_t *frba, unsigned int region_type)
1149{
1150 region_t region;
1151
1152 if (!frba)
1153 return 0;
1154
1155 region = get_region(frba, region_type);
1156 return !!((region.base < region.limit) && (region.size > 0));
1157}
1158
Bill XIEfa5f9942017-09-12 11:22:29 +08001159static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001160{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001161 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001162 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001163 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001164 if (!fmba)
1165 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001166
1167 if (ifd_version >= IFD_VERSION_2) {
1168 wr_shift = FLMSTR_WR_SHIFT_V2;
1169 rd_shift = FLMSTR_RD_SHIFT_V2;
1170
1171 /* Clear non-reserved bits */
1172 fmba->flmstr1 &= 0xff;
1173 fmba->flmstr2 &= 0xff;
1174 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001175 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001176 } else {
1177 wr_shift = FLMSTR_WR_SHIFT_V1;
1178 rd_shift = FLMSTR_RD_SHIFT_V1;
1179
1180 fmba->flmstr1 = 0;
1181 fmba->flmstr2 = 0;
1182 /* Requestor ID */
1183 fmba->flmstr3 = 0x118;
1184 }
1185
Andrey Petrov96ecb772016-10-31 19:31:54 -07001186 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001187 case PLATFORM_APL:
1188 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001189 /* CPU/BIOS can read descriptor and BIOS */
1190 fmba->flmstr1 |= 0x3 << rd_shift;
1191 /* CPU/BIOS can write BIOS */
1192 fmba->flmstr1 |= 0x2 << wr_shift;
1193 /* TXE can read descriptor, BIOS and Device Expansion */
1194 fmba->flmstr2 |= 0x23 << rd_shift;
1195 /* TXE can only write Device Expansion */
1196 fmba->flmstr2 |= 0x20 << wr_shift;
1197 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001198 case PLATFORM_CNL:
1199 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001200 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001201 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301202 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001203 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301204 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001205 /* CPU/BIOS can read descriptor and BIOS. */
1206 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1207 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1208 /* CPU/BIOS can write BIOS. */
1209 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1210 /* ME can read descriptor and ME. */
1211 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1212 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001213 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001214 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1215 if (check_region(frba, REGION_GBE)) {
1216 /* BIOS can read/write GbE. */
1217 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1218 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1219 /* ME can read GbE. */
1220 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1221 /* GbE can read descriptor and read/write GbE.. */
1222 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1223 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1224 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1225 }
1226 if (check_region(frba, REGION_PDR)) {
1227 /* BIOS can read/write PDR. */
1228 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1229 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1230 }
1231 if (check_region(frba, REGION_EC)) {
1232 /* BIOS can read EC. */
1233 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1234 /* EC can read descriptor and read/write EC. */
1235 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1236 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1237 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1238 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001239 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001240 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001241 /* CPU/BIOS can read descriptor and BIOS. */
1242 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1243 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1244 /* CPU/BIOS can write BIOS. */
1245 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1246 /* ME can read descriptor and ME. */
1247 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1248 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1249 /* ME can write ME. */
1250 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1251 if (check_region(frba, REGION_GBE)) {
1252 /* BIOS can read GbE. */
1253 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1254 /* BIOS can write GbE. */
1255 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1256 /* ME can read GbE. */
1257 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1258 /* ME can write GbE. */
1259 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1260 /* GbE can write GbE. */
1261 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1262 /* GbE can read GbE. */
1263 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1264 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001265 break;
1266 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001267
1268 write_image(filename, image, size);
1269}
1270
Usha P412679d2020-10-15 11:25:08 +05301271static void enable_cpu_read_me(const char *filename, char *image, int size)
1272{
1273 int rd_shift;
1274 fmba_t *fmba = find_fmba(image, size);
1275
1276 if (!fmba)
1277 exit(EXIT_FAILURE);
1278
1279 if (ifd_version >= IFD_VERSION_2)
1280 rd_shift = FLMSTR_RD_SHIFT_V2;
1281 else
1282 rd_shift = FLMSTR_RD_SHIFT_V1;
1283
1284 /* CPU/BIOS can read ME. */
1285 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1286
1287 write_image(filename, image, size);
1288}
1289
Bill XIEfa5f9942017-09-12 11:22:29 +08001290static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001291{
Bill XIE612ec0e2017-08-30 16:10:27 +08001292 fmba_t *fmba = find_fmba(image, size);
1293 if (!fmba)
1294 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001295
1296 if (ifd_version >= IFD_VERSION_2) {
1297 /* Access bits for each region are read: 19:8 write: 31:20 */
1298 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1299 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1300 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001301 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001302 } else {
1303 fmba->flmstr1 = 0xffff0000;
1304 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001305 /* Keep chipset specific Requester ID */
1306 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001307 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001308
1309 write_image(filename, image, size);
1310}
1311
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001312static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1313 const unsigned int value)
1314{
1315 if (!fpsba || !fdb) {
1316 fprintf(stderr, "Internal error\n");
1317 exit(EXIT_FAILURE);
1318 }
1319
1320 /* SoC Strap Length, aka PSL, aka ISL */
1321 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1322 if (strap >= SSL) {
1323 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1324 exit(EXIT_FAILURE);
1325 }
1326 fpsba->pchstrp[strap] = value;
1327}
1328
Bill XIEb3e15a22017-09-07 18:34:50 +08001329/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001330static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001331{
1332 if (ifd_version >= IFD_VERSION_2) {
1333 printf("%sting the HAP bit to %s Intel ME...\n",
1334 altmedisable?"Set":"Unset",
1335 altmedisable?"disable":"enable");
1336 if (altmedisable)
1337 fpsba->pchstrp[0] |= (1 << 16);
1338 else
1339 fpsba->pchstrp[0] &= ~(1 << 16);
1340 } else {
1341 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1342 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1343 "and MCH_AltMeDisable to %s Intel ME...\n",
1344 altmedisable?"Set":"Unset",
1345 altmedisable?"disable":"enable");
1346 if (altmedisable) {
1347 /* MCH_MeDisable */
1348 fmsba->data[0] |= 1;
1349 /* MCH_AltMeDisable */
1350 fmsba->data[0] |= (1 << 7);
1351 /* ICH_MeDisable */
1352 fpsba->pchstrp[0] |= 1;
1353 } else {
1354 fmsba->data[0] &= ~1;
1355 fmsba->data[0] &= ~(1 << 7);
1356 fpsba->pchstrp[0] &= ~1;
1357 }
1358 } else {
1359 printf("%sting the AltMeDisable to %s Intel ME...\n",
1360 altmedisable?"Set":"Unset",
1361 altmedisable?"disable":"enable");
1362 if (altmedisable)
1363 fpsba->pchstrp[10] |= (1 << 7);
1364 else
1365 fpsba->pchstrp[10] &= ~(1 << 7);
1366 }
1367 }
1368}
1369
Jacob Garber595d9262019-06-27 17:33:10 -06001370static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001371 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001372{
Bill XIE612ec0e2017-08-30 16:10:27 +08001373 frba_t *frba = find_frba(image, size);
1374 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001375 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001376
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001377 region_t region = get_region(frba, region_type);
1378 if (region.size <= 0xfff) {
1379 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1380 region_name(region_type));
1381 exit(EXIT_FAILURE);
1382 }
1383
Scott Duplichanf2c98372014-12-12 21:03:06 -06001384 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001385 if (region_fd == -1) {
1386 perror("Could not open file");
1387 exit(EXIT_FAILURE);
1388 }
1389 struct stat buf;
1390 if (fstat(region_fd, &buf) == -1) {
1391 perror("Could not stat file");
1392 exit(EXIT_FAILURE);
1393 }
1394 int region_size = buf.st_size;
1395
1396 printf("File %s is %d bytes\n", region_fname, region_size);
1397
1398 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001399 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001400 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1401 " bytes. Not injecting.\n",
1402 region_name(region_type), region.size,
1403 region.size, region_size, region_size);
1404 exit(EXIT_FAILURE);
1405 }
1406
1407 int offset = 0;
1408 if ((region_type == 1) && (region_size < region.size)) {
1409 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1410 " bytes. Padding before injecting.\n",
1411 region_name(region_type), region.size,
1412 region.size, region_size, region_size);
1413 offset = region.size - region_size;
1414 memset(image + region.base, 0xff, offset);
1415 }
1416
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001417 if (size < region.base + offset + region_size) {
1418 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1419 size, region.base + offset + region_size);
1420 exit(EXIT_FAILURE);
1421 }
1422
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001423 if (read(region_fd, image + region.base + offset, region_size)
1424 != region_size) {
1425 perror("Could not read file");
1426 exit(EXIT_FAILURE);
1427 }
1428
1429 close(region_fd);
1430
1431 printf("Adding %s as the %s section of %s\n",
1432 region_fname, region_name(region_type), filename);
1433 write_image(filename, image, size);
1434}
1435
Jacob Garber595d9262019-06-27 17:33:10 -06001436static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001437{
1438 unsigned int y = 1;
1439 if (x == 0)
1440 return 0;
1441 while (y <= x)
1442 y = y << 1;
1443
1444 return y;
1445}
1446
1447/**
1448 * Determine if two memory regions overlap.
1449 *
1450 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001451 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001452 * @return 1 if the two regions overlap
1453 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001454static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001455{
Bill XIEfa5f9942017-09-12 11:22:29 +08001456 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001457 return 0;
1458
Nico Huber844eda02019-01-05 00:06:19 +01001459 /* r1 should be either completely below or completely above r2 */
1460 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001461}
1462
Jacob Garber595d9262019-06-27 17:33:10 -06001463static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001464 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001465{
1466 FILE *romlayout;
1467 char tempstr[256];
1468 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001469 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001470 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001471 region_t current_regions[MAX_REGIONS];
1472 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001473 int new_extent = 0;
1474 char *new_image;
1475
1476 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001477 frba_t *frba = find_frba(image, size);
1478 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001479 exit(EXIT_FAILURE);
1480
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001481 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001482 current_regions[i] = get_region(frba, i);
1483 new_regions[i] = get_region(frba, i);
1484 }
1485
1486 /* read new layout */
1487 romlayout = fopen(layout_fname, "r");
1488
1489 if (!romlayout) {
1490 perror("Could not read layout file.\n");
1491 exit(EXIT_FAILURE);
1492 }
1493
1494 while (!feof(romlayout)) {
1495 char *tstr1, *tstr2;
1496
Patrick Georgi802ad522014-08-09 17:12:23 +02001497 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001498 layout_region_name))
1499 continue;
1500
1501 region_number = region_num(layout_region_name);
1502 if (region_number < 0)
1503 continue;
1504
1505 tstr1 = strtok(tempstr, ":");
1506 tstr2 = strtok(NULL, ":");
1507 if (!tstr1 || !tstr2) {
1508 fprintf(stderr, "Could not parse layout file.\n");
1509 exit(EXIT_FAILURE);
1510 }
1511 new_regions[region_number].base = strtol(tstr1,
1512 (char **)NULL, 16);
1513 new_regions[region_number].limit = strtol(tstr2,
1514 (char **)NULL, 16);
1515 new_regions[region_number].size =
1516 new_regions[region_number].limit -
1517 new_regions[region_number].base + 1;
1518
1519 if (new_regions[region_number].size < 0)
1520 new_regions[region_number].size = 0;
1521 }
1522 fclose(romlayout);
1523
1524 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001525 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001526 if (new_regions[i].size == 0)
1527 continue;
1528
1529 if (new_regions[i].size < current_regions[i].size) {
1530 printf("DANGER: Region %s is shrinking.\n",
1531 region_name(i));
1532 printf(" The region will be truncated to fit.\n");
1533 printf(" This may result in an unusable image.\n");
1534 }
1535
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001536 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001537 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001538 fprintf(stderr, "Regions would overlap.\n");
1539 exit(EXIT_FAILURE);
1540 }
1541 }
1542
1543 /* detect if the image size should grow */
1544 if (new_extent < new_regions[i].limit)
1545 new_extent = new_regions[i].limit;
1546 }
1547
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001548 /* check if the image is actually a Flash Descriptor region */
1549 if (size == new_regions[0].size) {
1550 printf("The image is a single Flash Descriptor:\n");
1551 printf(" Only the descriptor will be modified\n");
1552 new_extent = size;
1553 } else {
1554 new_extent = next_pow2(new_extent - 1);
1555 if (new_extent != size) {
1556 printf("The image has changed in size.\n");
1557 printf("The old image is %d bytes.\n", size);
1558 printf("The new image is %d bytes.\n", new_extent);
1559 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001560 }
1561
1562 /* copy regions to a new image */
1563 new_image = malloc(new_extent);
1564 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001565 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001566 int copy_size = new_regions[i].size;
1567 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001568 const region_t *current = &current_regions[i];
1569 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001570
Bill XIEfa5f9942017-09-12 11:22:29 +08001571 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001572 continue;
1573
Bill XIEfa5f9942017-09-12 11:22:29 +08001574 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001575 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001576 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001577 if (i == REGION_BIOS)
1578 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001579 }
1580
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001581 if ((i == REGION_BIOS) && (new->size < current->size)) {
1582 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001583 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001584 }
1585
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001586 if (size < current->base + offset_current + copy_size) {
1587 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1588 region_name(i));
1589 continue;
1590 };
1591
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001592 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1593 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001594 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1595 offset_current, current->limit, current->size);
1596 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1597 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001598
Bill XIEfa5f9942017-09-12 11:22:29 +08001599 memcpy(new_image + new->base + offset_new,
1600 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001601 copy_size);
1602 }
1603
1604 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001605 frba = find_frba(new_image, new_extent);
1606 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001607 exit(EXIT_FAILURE);
1608
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001609 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001610 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001611 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001612
1613 write_image(filename, new_image, new_extent);
1614 free(new_image);
1615}
1616
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001617static void print_version(void)
1618{
1619 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1620 printf("Copyright (C) 2011 Google Inc.\n\n");
1621 printf
1622 ("This program is free software: you can redistribute it and/or modify\n"
1623 "it under the terms of the GNU General Public License as published by\n"
1624 "the Free Software Foundation, version 2 of the License.\n\n"
1625 "This program is distributed in the hope that it will be useful,\n"
1626 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1627 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001628 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001629}
1630
1631static void print_usage(const char *name)
1632{
1633 printf("usage: %s [-vhdix?] <filename>\n", name);
1634 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001635 " -d | --dump: dump intel firmware descriptor\n"
1636 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1637 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1638 " -x | --extract: extract intel fd modules\n"
1639 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1640 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001641 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001642 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1643 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1644 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1645 " can only be used once per run:\n"
1646 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1647 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1648 " Dual Output Fast Read Support\n"
1649 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301650 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001651 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001652 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1653 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001654 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301655 " adl - Alder Lake\n"
1656 " aplk - Apollo Lake\n"
1657 " cnl - Cannon Lake\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001658 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301659 " glk - Gemini Lake\n"
1660 " icl - Ice Lake\n"
1661 " jsl - Jasper Lake\n"
1662 " sklkbl - Sky Lake/Kaby Lake\n"
1663 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001664 " -S | --setpchstrap Write a PCH strap\n"
1665 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001666 " -v | --version: print the version\n"
1667 " -h | --help: print this help\n\n"
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001668 "<region> is one of Descriptor, BIOS, ME, GbE, Platform, res1, res2, res3\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001669 "\n");
1670}
1671
1672int main(int argc, char *argv[])
1673{
1674 int opt, option_index = 0;
1675 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001676 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001677 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301678 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001679 char *region_type_string = NULL, *region_fname = NULL;
1680 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001681 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001682 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001683 unsigned int value = 0;
1684 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001685 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001686 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1687
Bill XIEfa5f9942017-09-12 11:22:29 +08001688 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001689 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001690 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001691 {"extract", 0, NULL, 'x'},
1692 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001693 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001694 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001695 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001696 {"density", 1, NULL, 'D'},
1697 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001698 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001699 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001700 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301701 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001702 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001703 {"version", 0, NULL, 'v'},
1704 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001705 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001706 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001707 {"setpchstrap", 1, NULL, 'S'},
1708 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001709 {0, 0, 0, 0}
1710 };
1711
Usha P412679d2020-10-15 11:25:08 +05301712 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 -07001713 long_options, &option_index)) != EOF) {
1714 switch (opt) {
1715 case 'd':
1716 mode_dump = 1;
1717 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001718 case 'S':
1719 mode_setstrap = 1;
1720 pchstrap = strtoul(optarg, NULL, 0);
1721 break;
1722 case 'V':
1723 value = strtoul(optarg, NULL, 0);
1724 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001725 case 'f':
1726 mode_layout = 1;
1727 layout_fname = strdup(optarg);
1728 if (!layout_fname) {
1729 fprintf(stderr, "No layout file specified\n");
1730 print_usage(argv[0]);
1731 exit(EXIT_FAILURE);
1732 }
1733 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001734 case 'x':
1735 mode_extract = 1;
1736 break;
1737 case 'i':
1738 // separate type and file name
1739 region_type_string = strdup(optarg);
1740 region_fname = strchr(region_type_string, ':');
1741 if (!region_fname) {
1742 print_usage(argv[0]);
1743 exit(EXIT_FAILURE);
1744 }
1745 region_fname[0] = '\0';
1746 region_fname++;
1747 // Descriptor, BIOS, ME, GbE, Platform
1748 // valid type?
1749 if (!strcasecmp("Descriptor", region_type_string))
1750 region_type = 0;
1751 else if (!strcasecmp("BIOS", region_type_string))
1752 region_type = 1;
1753 else if (!strcasecmp("ME", region_type_string))
1754 region_type = 2;
1755 else if (!strcasecmp("GbE", region_type_string))
1756 region_type = 3;
1757 else if (!strcasecmp("Platform", region_type_string))
1758 region_type = 4;
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001759 else if (!strcasecmp("res1", region_type_string))
1760 region_type = 5;
1761 else if (!strcasecmp("res2", region_type_string))
1762 region_type = 6;
1763 else if (!strcasecmp("res3", region_type_string))
1764 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001765 else if (!strcasecmp("EC", region_type_string))
1766 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001767 if (region_type == -1) {
1768 fprintf(stderr, "No such region type: '%s'\n\n",
1769 region_type_string);
1770 print_usage(argv[0]);
1771 exit(EXIT_FAILURE);
1772 }
1773 mode_inject = 1;
1774 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001775 case 'n':
1776 mode_newlayout = 1;
1777 layout_fname = strdup(optarg);
1778 if (!layout_fname) {
1779 fprintf(stderr, "No layout file specified\n");
1780 print_usage(argv[0]);
1781 exit(EXIT_FAILURE);
1782 }
1783 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001784 case 'O':
1785 new_filename = strdup(optarg);
1786 if (!new_filename) {
1787 fprintf(stderr, "No output filename specified\n");
1788 print_usage(argv[0]);
1789 exit(EXIT_FAILURE);
1790 }
1791 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001792 case 'D':
1793 mode_density = 1;
1794 new_density = strtoul(optarg, NULL, 0);
1795 switch (new_density) {
1796 case 512:
1797 new_density = COMPONENT_DENSITY_512KB;
1798 break;
1799 case 1:
1800 new_density = COMPONENT_DENSITY_1MB;
1801 break;
1802 case 2:
1803 new_density = COMPONENT_DENSITY_2MB;
1804 break;
1805 case 4:
1806 new_density = COMPONENT_DENSITY_4MB;
1807 break;
1808 case 8:
1809 new_density = COMPONENT_DENSITY_8MB;
1810 break;
1811 case 16:
1812 new_density = COMPONENT_DENSITY_16MB;
1813 break;
1814 case 32:
1815 new_density = COMPONENT_DENSITY_32MB;
1816 break;
1817 case 64:
1818 new_density = COMPONENT_DENSITY_64MB;
1819 break;
1820 case 0:
1821 new_density = COMPONENT_DENSITY_UNUSED;
1822 break;
1823 default:
1824 printf("error: Unknown density\n");
1825 print_usage(argv[0]);
1826 exit(EXIT_FAILURE);
1827 }
1828 break;
1829 case 'C':
1830 selected_chip = strtol(optarg, NULL, 0);
1831 if (selected_chip > 2) {
1832 fprintf(stderr, "error: Invalid chip selection\n");
1833 print_usage(argv[0]);
1834 exit(EXIT_FAILURE);
1835 }
1836 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001837 case 'M':
1838 mode_altmedisable = 1;
1839 altmedisable = strtol(optarg, NULL, 0);
1840 if (altmedisable > 1) {
1841 fprintf(stderr, "error: Illegal value\n");
1842 print_usage(argv[0]);
1843 exit(EXIT_FAILURE);
1844 }
1845 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001846 case 's':
1847 // Parse the requested SPI frequency
1848 inputfreq = strtol(optarg, NULL, 0);
1849 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001850 case 17:
1851 spifreq = SPI_FREQUENCY_17MHZ;
1852 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001853 case 20:
1854 spifreq = SPI_FREQUENCY_20MHZ;
1855 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001856 case 30:
1857 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1858 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001859 case 33:
1860 spifreq = SPI_FREQUENCY_33MHZ;
1861 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001862 case 48:
1863 spifreq = SPI_FREQUENCY_48MHZ;
1864 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001865 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001866 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001867 break;
1868 default:
1869 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1870 inputfreq);
1871 print_usage(argv[0]);
1872 exit(EXIT_FAILURE);
1873 }
1874 mode_spifreq = 1;
1875 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001876 case 'e':
1877 mode_em100 = 1;
1878 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001879 case 'l':
1880 mode_locked = 1;
1881 if (mode_unlocked == 1) {
1882 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1883 exit(EXIT_FAILURE);
1884 }
1885 break;
Usha P412679d2020-10-15 11:25:08 +05301886 case 'r':
1887 mode_read = 1;
1888 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001889 case 'u':
1890 mode_unlocked = 1;
1891 if (mode_locked == 1) {
1892 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1893 exit(EXIT_FAILURE);
1894 }
1895 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001896 case 'p':
1897 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001898 platform = PLATFORM_APL;
1899 } else if (!strcmp(optarg, "cnl")) {
1900 platform = PLATFORM_CNL;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001901 } else if (!strcmp(optarg, "ehl")) {
1902 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001903 } else if (!strcmp(optarg, "glk")) {
1904 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301905 } else if (!strcmp(optarg, "icl")) {
1906 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301907 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001908 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001909 } else if (!strcmp(optarg, "sklkbl")) {
1910 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001911 } else if (!strcmp(optarg, "tgl")) {
1912 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301913 } else if (!strcmp(optarg, "adl")) {
1914 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001915 } else {
1916 fprintf(stderr, "Unknown platform: %s\n", optarg);
1917 exit(EXIT_FAILURE);
1918 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001919 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001920 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001921 case 't':
1922 mode_validate = 1;
1923 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001924 case 'v':
1925 print_version();
1926 exit(EXIT_SUCCESS);
1927 break;
1928 case 'h':
1929 case '?':
1930 default:
1931 print_usage(argv[0]);
1932 exit(EXIT_SUCCESS);
1933 break;
1934 }
1935 }
1936
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001937 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001938 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001939 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001940 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001941 print_usage(argv[0]);
1942 exit(EXIT_FAILURE);
1943 }
1944
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001945 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001946 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001947 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001948 fprintf(stderr, "You need to specify a mode.\n\n");
1949 print_usage(argv[0]);
1950 exit(EXIT_FAILURE);
1951 }
1952
1953 if (optind + 1 != argc) {
1954 fprintf(stderr, "You need to specify a file.\n\n");
1955 print_usage(argv[0]);
1956 exit(EXIT_FAILURE);
1957 }
1958
1959 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001960 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001961 if (bios_fd == -1) {
1962 perror("Could not open file");
1963 exit(EXIT_FAILURE);
1964 }
1965 struct stat buf;
1966 if (fstat(bios_fd, &buf) == -1) {
1967 perror("Could not stat file");
1968 exit(EXIT_FAILURE);
1969 }
1970 int size = buf.st_size;
1971
1972 printf("File %s is %d bytes\n", filename, size);
1973
1974 char *image = malloc(size);
1975 if (!image) {
1976 printf("Out of memory.\n");
1977 exit(EXIT_FAILURE);
1978 }
1979
1980 if (read(bios_fd, image, size) != size) {
1981 perror("Could not read file");
1982 exit(EXIT_FAILURE);
1983 }
1984
1985 close(bios_fd);
1986
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001987 // generate new filename
1988 if (new_filename == NULL) {
1989 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1990 if (!new_filename) {
1991 printf("Out of memory.\n");
1992 exit(EXIT_FAILURE);
1993 }
1994 // - 5: leave room for ".new\0"
1995 strcpy(new_filename, filename);
1996 strcat(new_filename, ".new");
1997 }
1998
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001999 check_ifd_version(image, size);
2000
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002001 if (mode_dump)
2002 dump_fd(image, size);
2003
Chris Douglass03ce0142014-02-26 13:30:13 -05002004 if (mode_layout)
2005 dump_layout(image, size, layout_fname);
2006
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002007 if (mode_extract)
2008 write_regions(image, size);
2009
Mathew Kingc7ddc992019-08-08 14:59:25 -06002010 if (mode_validate)
2011 validate_layout(image, size);
2012
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002013 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002014 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002015 region_fname);
2016
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002017 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002018 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002019
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002020 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002021 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002022
Jan Tatjefa317512016-03-11 00:52:07 +01002023 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002024 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002025
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002026 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002027 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002028
Alexander Couzensd12ea112016-09-10 13:33:05 +02002029 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002030 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002031
Usha P412679d2020-10-15 11:25:08 +05302032 if (mode_read)
2033 enable_cpu_read_me(new_filename, image, size);
2034
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002035 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002036 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002037
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002038 if (mode_setstrap) {
2039 fpsba_t *fpsba = find_fpsba(image, size);
2040 const fdbar_t *fdb = find_fd(image, size);
2041 set_pchstrap(fpsba, fdb, pchstrap, value);
2042 write_image(new_filename, image, size);
2043 }
2044
Bill XIEb3e15a22017-09-07 18:34:50 +08002045 if (mode_altmedisable) {
2046 fpsba_t *fpsba = find_fpsba(image, size);
2047 fmsba_t *fmsba = find_fmsba(image, size);
2048 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002049 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002050 }
2051
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002052 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002053 free(image);
2054
2055 return 0;
2056}