blob: 93f29d4fc35a6a776e4a86ec83e0fc23260fc824 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003
4#include <unistd.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <getopt.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080012#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060013#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014#include "ifdtool.h"
15
Scott Duplichanf2c98372014-12-12 21:03:06 -060016#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
Bill XIE612ec0e2017-08-30 16:10:27 +080020/**
21 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
22 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
23 * @param base: base address represented with char* type.
24 * @param limit: upper limit of the legal address.
25 *
26 */
27#define PTR_IN_RANGE(ptr, base, limit) \
28 ((const char *)(ptr) >= (base) && \
29 (const char *)&(ptr)[1] <= (base) + (limit))
30
Duncan Laurie1f7fd722015-06-22 11:14:48 -070031static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080032static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080033static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010034static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070035static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050036
Duncan Laurie1f7fd722015-06-22 11:14:48 -070037static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060038 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
39 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
40 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
41 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
42 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
43 { "Reserved", "res1", "flashregion_5_reserved.bin", NULL },
44 { "Reserved", "res2", "flashregion_6_reserved.bin", NULL },
45 { "Reserved", "res3", "flashregion_7_reserved.bin", NULL },
46 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Chris Douglass03ce0142014-02-26 13:30:13 -050047};
48
Bill XIEb3e15a22017-09-07 18:34:50 +080049/* port from flashrom */
50static const char *const ich_chipset_names[] = {
51 "Unknown ICH",
52 "ICH",
53 "ICH2345",
54 "ICH6",
55 "SCH U",
56 "Atom E6xx",
57 "Atom S1220 S1240 S1260",
58 "ICH7",
59 "ICH8",
60 "ICH9",
61 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053062 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080063 "5 series Ibex Peak",
64 "6 series Cougar Point",
65 "7 series Panther Point",
66 "8 series Lynx Point",
67 "Baytrail",
68 "8 series Lynx Point LP",
69 "8 series Wellsburg",
70 "9 series Wildcat Point",
71 "9 series Wildcat Point LP",
Subrata Banik89db2252020-08-26 14:49:17 +053072 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
73 "100/200 series Sunrise Point",
74 "300 series Cannon Point/ 400 series Ice Point",
75 "500 series Tiger Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080076 "C620 series Lewisburg",
77 NULL
78};
79
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070080static fdbar_t *find_fd(char *image, int size)
81{
82 int i, found = 0;
83
84 /* Scan for FD signature */
85 for (i = 0; i < (size - 4); i += 4) {
86 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
87 found = 1;
88 break; // signature found.
89 }
90 }
91
92 if (!found) {
93 printf("No Flash Descriptor found in this image\n");
94 return NULL;
95 }
96
Bill XIE612ec0e2017-08-30 16:10:27 +080097 fdbar_t *fdb = (fdbar_t *) (image + i);
98 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
99}
100
Stefan Tauner0d226142018-08-05 18:56:53 +0200101static char *find_flumap(char *image, int size)
102{
103 /* The upper map is located in the word before the 256B-long OEM section
104 * at the end of the 4kB-long flash descriptor. In the official
105 * documentation this is defined as FDBAR + 0xEFC. However, starting
106 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
107 * has moved 16 bytes back to offset 0x10 of the image. Although
108 * official documentation still maintains the offset relative to FDBAR
109 * this is wrong and a simple fixed offset from the start of the image
110 * works.
111 */
112 char *flumap = image + 4096 - 256 - 4;
113 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
114}
115
Bill XIE612ec0e2017-08-30 16:10:27 +0800116static fcba_t *find_fcba(char *image, int size)
117{
118 fdbar_t *fdb = find_fd(image, size);
119 if (!fdb)
120 return NULL;
121 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
122 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
123
124}
125
126static fmba_t *find_fmba(char *image, int size)
127{
128 fdbar_t *fdb = find_fd(image, size);
129 if (!fdb)
130 return NULL;
131 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
132 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
133}
134
135static frba_t *find_frba(char *image, int size)
136{
137 fdbar_t *fdb = find_fd(image, size);
138 if (!fdb)
139 return NULL;
140 frba_t *frba =
141 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
142 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
143}
144
145static fpsba_t *find_fpsba(char *image, int size)
146{
147 fdbar_t *fdb = find_fd(image, size);
148 if (!fdb)
149 return NULL;
150 fpsba_t *fpsba =
151 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200152
153 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
154 if ((((char *)fpsba) + SSL) >= (image + size))
155 return NULL;
156 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800157}
158
159static fmsba_t *find_fmsba(char *image, int size)
160{
161 fdbar_t *fdb = find_fd(image, size);
162 if (!fdb)
163 return NULL;
164 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
165 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700166}
167
Subrata Banik89db2252020-08-26 14:49:17 +0530168static enum ich_chipset guess_ifd_2_chipset(const fpsba_t *fpsba)
169{
170 uint32_t pchstrp_22 = fpsba->pchstrp[22];
171 uint32_t pchstrp_23 = fpsba->pchstrp[23];
172
173 /* Offset 0x5B is the last PCH descriptor record */
174 if (pchstrp_23 == 0xFFFFFFFF)
175 return CHIPSET_N_J_SERIES;
176
177 /* Offset 0x58 is PCH descriptor record is reserved */
178 if (pchstrp_22 == 0x0)
179 return CHIPSET_300_400_SERIES_CANNON_ICE_POINT;
180
181 /* Offset 0x58 bit [2:0] is reserved 0x4 and 0x5a bit [7:0] is reserved 0x58 */
182 if (((pchstrp_22 & 0x07) == 0x4) &&
183 ((pchstrp_22 & 0xFF0000) >> 16 == 0x58))
184 return CHIPSET_500_SERIES_TIGER_POINT;
185
186 return CHIPSET_PCH_UNKNOWN;
187}
188
Bill XIEb3e15a22017-09-07 18:34:50 +0800189/* port from flashrom */
Subrata Banik89db2252020-08-26 14:49:17 +0530190static enum ich_chipset guess_ich_chipset(const fdbar_t *fdb, const fpsba_t *fpsba)
Bill XIEb3e15a22017-09-07 18:34:50 +0800191{
192 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
193 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
194 uint32_t isl = (fdb->flmap1 >> 24);
195 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
Subrata Banik89db2252020-08-26 14:49:17 +0530196 int temp_chipset;
Bill XIEb3e15a22017-09-07 18:34:50 +0800197
Subrata Banik89db2252020-08-26 14:49:17 +0530198 /* Check for IFD2 chipset type */
199 temp_chipset = guess_ifd_2_chipset(fpsba);
200 if (temp_chipset != CHIPSET_PCH_UNKNOWN)
201 return temp_chipset;
202
203 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800204 if (iccriba == 0x00) {
205 if (msl == 0 && isl <= 2)
206 return CHIPSET_ICH8;
207 else if (isl <= 2)
208 return CHIPSET_ICH9;
209 else if (isl <= 10)
210 return CHIPSET_ICH10;
211 else if (isl <= 16)
212 return CHIPSET_5_SERIES_IBEX_PEAK;
213 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
214 return CHIPSET_5_SERIES_IBEX_PEAK;
215 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
216 if (msl == 0 && isl <= 17)
217 return CHIPSET_BAYTRAIL;
218 else if (msl <= 1 && isl <= 18)
219 return CHIPSET_6_SERIES_COUGAR_POINT;
220 else if (msl <= 1 && isl <= 21)
221 return CHIPSET_8_SERIES_LYNX_POINT;
222 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
223 return CHIPSET_9_SERIES_WILDCAT_POINT;
224 } else if (nm == 6) {
225 return CHIPSET_C620_SERIES_LEWISBURG;
226 } else {
Subrata Banik89db2252020-08-26 14:49:17 +0530227 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800228 }
229}
230
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700231/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700232 * Some newer platforms have re-defined the FCBA field that was used to
233 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
234 * have the required FCBA field, but are IFD v2 and return true if current
235 * platform is one of them.
236 */
237static int is_platform_ifd_2(void)
238{
239 static const int ifd_2_platforms[] = {
240 PLATFORM_GLK,
241 PLATFORM_CNL,
Aamir Bohra1018be22018-06-29 15:08:50 +0530242 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700243 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530244 PLATFORM_JSL,
Subrata Banik46f80732020-03-14 15:01:42 +0530245 PLATFORM_ADL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700246 };
247 unsigned int i;
248
249 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
250 if (platform == ifd_2_platforms[i])
251 return 1;
252 }
253
254 return 0;
255}
256
257/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700258 * There is no version field in the descriptor so to determine
259 * if this is a new descriptor format we check the hardcoded SPI
260 * read frequency to see if it is fixed at 20MHz or 17MHz.
261 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700262static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700263{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700264 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800265 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800266 const fdbar_t *fdb = find_fd(image, size);
Subrata Banik89db2252020-08-26 14:49:17 +0530267 const fpsba_t *fpsba = find_fpsba(image, size);
Jacob Garber9bb04612019-05-08 13:40:45 -0600268 if (!fcba || !fdb)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700269 exit(EXIT_FAILURE);
270
Subrata Banik89db2252020-08-26 14:49:17 +0530271 chipset = guess_ich_chipset(fdb, fpsba);
Bill XIEb3e15a22017-09-07 18:34:50 +0800272 /* TODO: port ifd_version and max_regions
273 * against guess_ich_chipset()
274 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700275 read_freq = (fcba->flcomp >> 17) & 7;
276
277 switch (read_freq) {
278 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700279 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700280 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700281 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700282 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700283 default:
284 fprintf(stderr, "Unknown descriptor version: %d\n",
285 read_freq);
286 exit(EXIT_FAILURE);
287 }
288}
289
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700290static void check_ifd_version(char *image, int size)
291{
292 if (is_platform_ifd_2())
293 ifd_version = IFD_VERSION_2;
294 else
295 ifd_version = get_ifd_version_from_fcba(image, size);
296
297 if (ifd_version == IFD_VERSION_1)
298 max_regions = MAX_REGIONS_OLD;
299 else
300 max_regions = MAX_REGIONS;
301}
302
Bill XIEfa5f9942017-09-12 11:22:29 +0800303static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700304{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500305 int base_mask;
306 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700307 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700308 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500309
310 if (ifd_version >= IFD_VERSION_2)
311 base_mask = 0x7fff;
312 else
313 base_mask = 0xfff;
314
315 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400317 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800318 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700319 exit (EXIT_FAILURE);
320 }
321
Bill XIE4651d452017-09-12 11:54:48 +0800322 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700323 region.base = (flreg & base_mask) << 12;
324 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700325 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500326
Chris Douglass03ce0142014-02-26 13:30:13 -0500327 if (region.size < 0)
328 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700329
330 return region;
331}
332
Bill XIEfa5f9942017-09-12 11:22:29 +0800333static void set_region(frba_t *frba, unsigned int region_type,
334 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500335{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400336 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800337 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500338 exit (EXIT_FAILURE);
339 }
Bill XIE4651d452017-09-12 11:54:48 +0800340
341 frba->flreg[region_type] =
342 (((region->limit >> 12) & 0x7fff) << 16) |
343 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500344}
345
Bill XIEfa5f9942017-09-12 11:22:29 +0800346static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700347{
Bill XIEfa5f9942017-09-12 11:22:29 +0800348 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700349 fprintf(stderr, "Invalid region type.\n");
350 exit (EXIT_FAILURE);
351 }
352
Chris Douglass03ce0142014-02-26 13:30:13 -0500353 return region_names[region_type].pretty;
354}
355
Bill XIEfa5f9942017-09-12 11:22:29 +0800356static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500357{
Bill XIEfa5f9942017-09-12 11:22:29 +0800358 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500359 fprintf(stderr, "Invalid region type.\n");
360 exit (EXIT_FAILURE);
361 }
362
363 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700364}
365
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500366static int region_num(const char *name)
367{
Bill XIEfa5f9942017-09-12 11:22:29 +0800368 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500369
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200370 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500371 if (strcasecmp(name, region_names[i].pretty) == 0)
372 return i;
373 if (strcasecmp(name, region_names[i].terse) == 0)
374 return i;
375 }
376
377 return -1;
378}
379
Bill XIEfa5f9942017-09-12 11:22:29 +0800380static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700381{
Bill XIEfa5f9942017-09-12 11:22:29 +0800382 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700383 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700384 exit (EXIT_FAILURE);
385 }
386
Bill XIE1bf65062017-09-12 11:31:37 +0800387 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700388}
389
Bill XIEfa5f9942017-09-12 11:22:29 +0800390static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700391{
392 region_t region = get_region(frba, num);
393 printf(" Flash Region %d (%s): %08x - %08x %s\n",
394 num, region_name(num), region.base, region.limit,
395 region.size < 1 ? "(unused)" : "");
396}
397
Bill XIEfa5f9942017-09-12 11:22:29 +0800398static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
399 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500400{
401 region_t region = get_region(frba, num);
402 snprintf(buf, bufsize, "%08x:%08x %s\n",
403 region.base, region.limit, region_name_short(num));
404}
405
Bill XIEfa5f9942017-09-12 11:22:29 +0800406static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700407{
Bill XIE4651d452017-09-12 11:54:48 +0800408 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530409 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700410 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800411 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530412 region = get_region(frba, i);
413 /* Skip unused & reserved Flash Region */
414 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
415 continue;
416
Bill XIE4651d452017-09-12 11:54:48 +0800417 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
418 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700419 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700420}
421
Bill XIEfa5f9942017-09-12 11:22:29 +0800422static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500423{
424 char buf[LAYOUT_LINELEN];
425 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800426 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500427
428 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
429 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
430 if (layout_fd == -1) {
431 perror("Could not open file");
432 exit(EXIT_FAILURE);
433 }
434
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200435 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200436 region_t region = get_region(frba, i);
437 /* is region invalid? */
438 if (region.size < 1)
439 continue;
440
Chris Douglass03ce0142014-02-26 13:30:13 -0500441 dump_region_layout(buf, bufsize, i, frba);
442 if (write(layout_fd, buf, strlen(buf)) < 0) {
443 perror("Could not write to file");
444 exit(EXIT_FAILURE);
445 }
446 }
447 close(layout_fd);
448 printf("Wrote layout to %s\n", layout_fname);
449}
450
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700451static void decode_spi_frequency(unsigned int freq)
452{
453 switch (freq) {
454 case SPI_FREQUENCY_20MHZ:
455 printf("20MHz");
456 break;
457 case SPI_FREQUENCY_33MHZ:
458 printf("33MHz");
459 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700460 case SPI_FREQUENCY_48MHZ:
461 printf("48MHz");
462 break;
463 case SPI_FREQUENCY_50MHZ_30MHZ:
464 switch (ifd_version) {
465 case IFD_VERSION_1:
466 printf("50MHz");
467 break;
468 case IFD_VERSION_2:
469 printf("30MHz");
470 break;
471 }
472 break;
473 case SPI_FREQUENCY_17MHZ:
474 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700475 break;
476 default:
477 printf("unknown<%x>MHz", freq);
478 }
479}
480
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700481static void decode_component_density(unsigned int density)
482{
483 switch (density) {
484 case COMPONENT_DENSITY_512KB:
485 printf("512KB");
486 break;
487 case COMPONENT_DENSITY_1MB:
488 printf("1MB");
489 break;
490 case COMPONENT_DENSITY_2MB:
491 printf("2MB");
492 break;
493 case COMPONENT_DENSITY_4MB:
494 printf("4MB");
495 break;
496 case COMPONENT_DENSITY_8MB:
497 printf("8MB");
498 break;
499 case COMPONENT_DENSITY_16MB:
500 printf("16MB");
501 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700502 case COMPONENT_DENSITY_32MB:
503 printf("32MB");
504 break;
505 case COMPONENT_DENSITY_64MB:
506 printf("64MB");
507 break;
508 case COMPONENT_DENSITY_UNUSED:
509 printf("UNUSED");
510 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700511 default:
512 printf("unknown<%x>MB", density);
513 }
514}
515
Subrata Banik26058dc2020-08-26 15:12:16 +0530516static int is_platform_with_pch(void)
517{
518 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
519 return 1;
520
521 return 0;
522}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530523
524/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
525static int is_platform_with_100x_series_pch(void)
526{
527 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
528 chipset <= CHIPSET_500_SERIES_TIGER_POINT)
529 return 1;
530
531 return 0;
532}
533
Bill XIEfa5f9942017-09-12 11:22:29 +0800534static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700535{
536 printf("\nFound Component Section\n");
537 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700538 printf(" Dual Output Fast Read Support: %ssupported\n",
539 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700540 printf(" Read ID/Read Status Clock Frequency: ");
541 decode_spi_frequency((fcba->flcomp >> 27) & 7);
542 printf("\n Write/Erase Clock Frequency: ");
543 decode_spi_frequency((fcba->flcomp >> 24) & 7);
544 printf("\n Fast Read Clock Frequency: ");
545 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700546 printf("\n Fast Read Support: %ssupported",
547 (fcba->flcomp & (1 << 20))?"":"not ");
548 printf("\n Read Clock Frequency: ");
549 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700550
551 switch (ifd_version) {
552 case IFD_VERSION_1:
553 printf("\n Component 2 Density: ");
554 decode_component_density((fcba->flcomp >> 3) & 7);
555 printf("\n Component 1 Density: ");
556 decode_component_density(fcba->flcomp & 7);
557 break;
558 case IFD_VERSION_2:
559 printf("\n Component 2 Density: ");
560 decode_component_density((fcba->flcomp >> 4) & 0xf);
561 printf("\n Component 1 Density: ");
562 decode_component_density(fcba->flcomp & 0xf);
563 break;
564 }
565
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700566 printf("\n");
567 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700568 printf(" Invalid Instruction 3: 0x%02x\n",
569 (fcba->flill >> 24) & 0xff);
570 printf(" Invalid Instruction 2: 0x%02x\n",
571 (fcba->flill >> 16) & 0xff);
572 printf(" Invalid Instruction 1: 0x%02x\n",
573 (fcba->flill >> 8) & 0xff);
574 printf(" Invalid Instruction 0: 0x%02x\n",
575 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530576 if (is_platform_with_100x_series_pch()) {
577 printf("FLILL1 0x%08x\n", fcba->flpb);
578 printf(" Invalid Instruction 7: 0x%02x\n",
579 (fcba->flpb >> 24) & 0xff);
580 printf(" Invalid Instruction 6: 0x%02x\n",
581 (fcba->flpb >> 16) & 0xff);
582 printf(" Invalid Instruction 5: 0x%02x\n",
583 (fcba->flpb >> 8) & 0xff);
584 printf(" Invalid Instruction 4: 0x%02x\n",
585 fcba->flpb & 0xff);
586 } else {
587 printf("FLPB 0x%08x\n", fcba->flpb);
588 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
589 (fcba->flpb & 0xfff) << 12);
590 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700591}
592
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200593static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700594{
Bill XIE4651d452017-09-12 11:54:48 +0800595 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200596 /* SoC Strap Length, aka PSL, aka ISL */
597 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
598
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700599 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200600 for (i = 0; i < SSL; i++)
601 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800602
603 if (ifd_version >= IFD_VERSION_2) {
604 printf("HAP bit is %sset\n",
605 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
606 } else if (chipset >= CHIPSET_ICH8
607 && chipset <= CHIPSET_ICH10) {
608 printf("ICH_MeDisable bit is %sset\n",
609 fpsba->pchstrp[0] & 1 ? "" : "not ");
610 } else {
611 printf("AltMeDisable bit is %sset\n",
612 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
613 }
614
Bill XIE4651d452017-09-12 11:54:48 +0800615 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700616}
617
618static void decode_flmstr(uint32_t flmstr)
619{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700620 int wr_shift, rd_shift;
621 if (ifd_version >= IFD_VERSION_2) {
622 wr_shift = FLMSTR_WR_SHIFT_V2;
623 rd_shift = FLMSTR_RD_SHIFT_V2;
624 } else {
625 wr_shift = FLMSTR_WR_SHIFT_V1;
626 rd_shift = FLMSTR_RD_SHIFT_V1;
627 }
628
629 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700630 if (ifd_version >= IFD_VERSION_2)
631 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700632 (flmstr & (1 << (wr_shift + 8))) ?
633 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700634 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700635 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700636 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700637 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700638 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700639 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700640 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700641 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700642 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700643 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700644
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700645 if (ifd_version >= IFD_VERSION_2)
646 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700647 (flmstr & (1 << (rd_shift + 8))) ?
648 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700649 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700650 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700651 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700652 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700653 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700654 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700655 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700656 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700657 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700658 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700659
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700660 /* Requestor ID doesn't exist for ifd 2 */
661 if (ifd_version < IFD_VERSION_2)
662 printf(" Requester ID: 0x%04x\n\n",
663 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700664}
665
Bill XIEfa5f9942017-09-12 11:22:29 +0800666static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700667{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700668 printf("Found Master Section\n");
669 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
670 decode_flmstr(fmba->flmstr1);
671 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
672 decode_flmstr(fmba->flmstr2);
673 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
674 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700675 if (ifd_version >= IFD_VERSION_2) {
676 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
677 decode_flmstr(fmba->flmstr5);
678 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700679}
680
Bill XIEfa5f9942017-09-12 11:22:29 +0800681static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700682{
Bill XIE612ec0e2017-08-30 16:10:27 +0800683 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700684 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800685 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
686 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800687
688 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
689 printf("MCH_MeDisable bit is %sset\n",
690 fmsba->data[0] & 1 ? "" : "not ");
691 printf("MCH_AltMeDisable bit is %sset\n",
692 fmsba->data[0] & (1 << 7) ? "" : "not ");
693 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700694}
695
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700696static void dump_jid(uint32_t jid)
697{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100698 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700699 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100700 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200701 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100702 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200703 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700704}
705
706static void dump_vscc(uint32_t vscc)
707{
708 printf(" Lower Erase Opcode: 0x%02x\n",
709 vscc >> 24);
710 printf(" Lower Write Enable on Write Status: 0x%02x\n",
711 vscc & (1 << 20) ? 0x06 : 0x50);
712 printf(" Lower Write Status Required: %s\n",
713 vscc & (1 << 19) ? "Yes" : "No");
714 printf(" Lower Write Granularity: %d bytes\n",
715 vscc & (1 << 18) ? 64 : 1);
716 printf(" Lower Block / Sector Erase Size: ");
717 switch ((vscc >> 16) & 0x3) {
718 case 0:
719 printf("256 Byte\n");
720 break;
721 case 1:
722 printf("4KB\n");
723 break;
724 case 2:
725 printf("8KB\n");
726 break;
727 case 3:
728 printf("64KB\n");
729 break;
730 }
731
732 printf(" Upper Erase Opcode: 0x%02x\n",
733 (vscc >> 8) & 0xff);
734 printf(" Upper Write Enable on Write Status: 0x%02x\n",
735 vscc & (1 << 4) ? 0x06 : 0x50);
736 printf(" Upper Write Status Required: %s\n",
737 vscc & (1 << 3) ? "Yes" : "No");
738 printf(" Upper Write Granularity: %d bytes\n",
739 vscc & (1 << 2) ? 64 : 1);
740 printf(" Upper Block / Sector Erase Size: ");
741 switch (vscc & 0x3) {
742 case 0:
743 printf("256 Byte\n");
744 break;
745 case 1:
746 printf("4KB\n");
747 break;
748 case 2:
749 printf("8KB\n");
750 break;
751 case 3:
752 printf("64KB\n");
753 break;
754 }
755}
756
Bill XIEfa5f9942017-09-12 11:22:29 +0800757static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700758{
759 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200760 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
761 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700762
763 printf("ME VSCC table:\n");
764 for (i = 0; i < num; i++) {
765 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
766 dump_jid(vtba->entry[i].jid);
767 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
768 dump_vscc(vtba->entry[i].vscc);
769 }
770 printf("\n");
771}
772
Bill XIEfa5f9942017-09-12 11:22:29 +0800773static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700774{
775 int i, j;
776 printf("OEM Section:\n");
777 for (i = 0; i < 4; i++) {
778 printf("%02x:", i << 4);
779 for (j = 0; j < 16; j++)
780 printf(" %02x", oem[(i<<4)+j]);
781 printf ("\n");
782 }
783 printf ("\n");
784}
785
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700786static void dump_fd(char *image, int size)
787{
Bill XIE612ec0e2017-08-30 16:10:27 +0800788 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700789 if (!fdb)
790 exit(EXIT_FAILURE);
791
Subrata Banik26058dc2020-08-26 15:12:16 +0530792 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
793 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700794 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530795 if (!is_platform_with_100x_series_pch())
796 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700797 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
798 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
799 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
800
801 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530802 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
803 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700804 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
805 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
806 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
807
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530808 if (!is_platform_with_100x_series_pch()) {
809 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
810 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
811 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
812 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700813
Stefan Tauner0d226142018-08-05 18:56:53 +0200814 char *flumap = find_flumap(image, size);
815 uint32_t flumap1 = *(uint32_t *)flumap;
816 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700817 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200818 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700819 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200820 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700821 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200822 (image + ((flumap1 & 0xff) << 4)),
823 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800824 dump_oem((const uint8_t *)image + 0xf00);
825
826 const frba_t *frba = find_frba(image, size);
827 const fcba_t *fcba = find_fcba(image, size);
828 const fpsba_t *fpsba = find_fpsba(image, size);
829 const fmba_t *fmba = find_fmba(image, size);
830 const fmsba_t *fmsba = find_fmsba(image, size);
831
832 if (frba && fcba && fpsba && fmba && fmsba) {
833 dump_frba(frba);
834 dump_fcba(fcba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200835 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800836 dump_fmba(fmba);
837 dump_fmsba(fmsba);
838 } else {
839 printf("FD is corrupted!\n");
840 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700841}
842
Bill XIEfa5f9942017-09-12 11:22:29 +0800843static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500844{
Bill XIE612ec0e2017-08-30 16:10:27 +0800845 const frba_t *frba = find_frba(image, size);
846 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500847 exit(EXIT_FAILURE);
848
Bill XIE612ec0e2017-08-30 16:10:27 +0800849 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500850}
851
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700852static void write_regions(char *image, int size)
853{
Bill XIEfa5f9942017-09-12 11:22:29 +0800854 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800855 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700856
Bill XIE612ec0e2017-08-30 16:10:27 +0800857 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700858 exit(EXIT_FAILURE);
859
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700860 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700861 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700862 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700863 if (region.size > 0) {
864 int region_fd;
865 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600866 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700867 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200868 if (region_fd < 0) {
869 perror("Error while trying to open file");
870 exit(EXIT_FAILURE);
871 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700872 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700873 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700874 close(region_fd);
875 }
876 }
877}
878
Mathew Kingc7ddc992019-08-08 14:59:25 -0600879static void validate_layout(char *image, int size)
880{
881 uint i, errors = 0;
882 struct fmap *fmap;
883 long int fmap_loc = fmap_find((uint8_t *)image, size);
884 const frba_t *frba = find_frba(image, size);
885
886 if (fmap_loc < 0 || !frba)
887 exit(EXIT_FAILURE);
888
889 fmap = (struct fmap *)(image + fmap_loc);
890
891 for (i = 0; i < max_regions; i++) {
892 if (region_names[i].fmapname == NULL)
893 continue;
894
895 region_t region = get_region(frba, i);
896
897 if (region.size == 0)
898 continue;
899
900 const struct fmap_area *area =
901 fmap_find_area(fmap, region_names[i].fmapname);
902
903 if (!area)
904 continue;
905
906 if ((uint)region.base != area->offset ||
907 (uint)region.size != area->size) {
908 printf("Region mismatch between %s and %s\n",
909 region_names[i].terse, area->name);
910 printf(" Descriptor region %s:\n", region_names[i].terse);
911 printf(" offset: 0x%08x\n", region.base);
912 printf(" length: 0x%08x\n", region.size);
913 printf(" FMAP area %s:\n", area->name);
914 printf(" offset: 0x%08x\n", area->offset);
915 printf(" length: 0x%08x\n", area->size);
916 errors++;
917 }
918 }
919
920 if (errors > 0)
921 exit(EXIT_FAILURE);
922}
923
Bill XIEfa5f9942017-09-12 11:22:29 +0800924static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700925{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700926 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100927 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700928
929 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100930 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600931 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700932 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200933 if (new_fd < 0) {
934 perror("Error while trying to open file");
935 exit(EXIT_FAILURE);
936 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700937 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700938 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700939 close(new_fd);
940}
941
Bill XIEfa5f9942017-09-12 11:22:29 +0800942static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700943 enum spi_frequency freq)
944{
Bill XIE612ec0e2017-08-30 16:10:27 +0800945 fcba_t *fcba = find_fcba(image, size);
946 if (!fcba)
947 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700948
949 /* clear bits 21-29 */
950 fcba->flcomp &= ~0x3fe00000;
951 /* Read ID and Read Status Clock Frequency */
952 fcba->flcomp |= freq << 27;
953 /* Write and Erase Clock Frequency */
954 fcba->flcomp |= freq << 24;
955 /* Fast Read Clock Frequency */
956 fcba->flcomp |= freq << 21;
957
958 write_image(filename, image, size);
959}
960
Bill XIEfa5f9942017-09-12 11:22:29 +0800961static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700962{
Bill XIE612ec0e2017-08-30 16:10:27 +0800963 fcba_t *fcba = find_fcba(image, size);
964 if (!fcba)
965 exit(EXIT_FAILURE);
966
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700967 int freq;
968
969 switch (ifd_version) {
970 case IFD_VERSION_1:
971 freq = SPI_FREQUENCY_20MHZ;
972 break;
973 case IFD_VERSION_2:
974 freq = SPI_FREQUENCY_17MHZ;
975 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700976 default:
977 freq = SPI_FREQUENCY_17MHZ;
978 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700979 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700980
981 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700982 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700983}
984
Bill XIEfa5f9942017-09-12 11:22:29 +0800985static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100986 unsigned int density)
987{
Bill XIE612ec0e2017-08-30 16:10:27 +0800988 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200989 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800990 if (!fcba)
991 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100992
993 printf("Setting chip density to ");
994 decode_component_density(density);
995 printf("\n");
996
997 switch (ifd_version) {
998 case IFD_VERSION_1:
999 /* fail if selected density is not supported by this version */
1000 if ( (density == COMPONENT_DENSITY_32MB) ||
1001 (density == COMPONENT_DENSITY_64MB) ||
1002 (density == COMPONENT_DENSITY_UNUSED) ) {
1003 printf("error: Selected density not supported in IFD version 1.\n");
1004 exit(EXIT_FAILURE);
1005 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001006 mask = 0x7;
1007 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001008 break;
1009 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001010 mask = 0xf;
1011 chip2_offset = 4;
1012 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001013 default:
1014 printf("error: Unknown IFD version\n");
1015 exit(EXIT_FAILURE);
1016 break;
1017 }
1018
1019 /* clear chip density for corresponding chip */
1020 switch (selected_chip) {
1021 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001022 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001023 break;
1024 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001025 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001026 break;
1027 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001028 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001029 break;
1030 }
1031
1032 /* set the new density */
1033 if (selected_chip == 1 || selected_chip == 0)
1034 fcba->flcomp |= (density); /* first chip */
1035 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001036 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001037
1038 write_image(filename, image, size);
1039}
1040
Duncan Laurie7775d672019-06-06 13:39:26 -07001041static int check_region(const frba_t *frba, unsigned int region_type)
1042{
1043 region_t region;
1044
1045 if (!frba)
1046 return 0;
1047
1048 region = get_region(frba, region_type);
1049 return !!((region.base < region.limit) && (region.size > 0));
1050}
1051
Bill XIEfa5f9942017-09-12 11:22:29 +08001052static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001053{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001054 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001055 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001056 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001057 if (!fmba)
1058 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001059
1060 if (ifd_version >= IFD_VERSION_2) {
1061 wr_shift = FLMSTR_WR_SHIFT_V2;
1062 rd_shift = FLMSTR_RD_SHIFT_V2;
1063
1064 /* Clear non-reserved bits */
1065 fmba->flmstr1 &= 0xff;
1066 fmba->flmstr2 &= 0xff;
1067 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001068 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001069 } else {
1070 wr_shift = FLMSTR_WR_SHIFT_V1;
1071 rd_shift = FLMSTR_RD_SHIFT_V1;
1072
1073 fmba->flmstr1 = 0;
1074 fmba->flmstr2 = 0;
1075 /* Requestor ID */
1076 fmba->flmstr3 = 0x118;
1077 }
1078
Andrey Petrov96ecb772016-10-31 19:31:54 -07001079 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001080 case PLATFORM_APL:
1081 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001082 /* CPU/BIOS can read descriptor and BIOS */
1083 fmba->flmstr1 |= 0x3 << rd_shift;
1084 /* CPU/BIOS can write BIOS */
1085 fmba->flmstr1 |= 0x2 << wr_shift;
1086 /* TXE can read descriptor, BIOS and Device Expansion */
1087 fmba->flmstr2 |= 0x23 << rd_shift;
1088 /* TXE can only write Device Expansion */
1089 fmba->flmstr2 |= 0x20 << wr_shift;
1090 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001091 case PLATFORM_CNL:
1092 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001093 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001094 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301095 case PLATFORM_JSL:
Subrata Banik46f80732020-03-14 15:01:42 +05301096 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001097 /* CPU/BIOS can read descriptor and BIOS. */
1098 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1099 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1100 /* CPU/BIOS can write BIOS. */
1101 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1102 /* ME can read descriptor and ME. */
1103 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1104 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001105 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001106 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1107 if (check_region(frba, REGION_GBE)) {
1108 /* BIOS can read/write GbE. */
1109 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1110 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1111 /* ME can read GbE. */
1112 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1113 /* GbE can read descriptor and read/write GbE.. */
1114 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1115 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1116 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1117 }
1118 if (check_region(frba, REGION_PDR)) {
1119 /* BIOS can read/write PDR. */
1120 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1121 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1122 }
1123 if (check_region(frba, REGION_EC)) {
1124 /* BIOS can read EC. */
1125 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1126 /* EC can read descriptor and read/write EC. */
1127 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1128 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1129 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1130 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001131 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001132 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001133 /* CPU/BIOS can read descriptor and BIOS. */
1134 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1135 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1136 /* CPU/BIOS can write BIOS. */
1137 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1138 /* ME can read descriptor and ME. */
1139 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1140 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1141 /* ME can write ME. */
1142 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1143 if (check_region(frba, REGION_GBE)) {
1144 /* BIOS can read GbE. */
1145 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1146 /* BIOS can write GbE. */
1147 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1148 /* ME can read GbE. */
1149 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1150 /* ME can write GbE. */
1151 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1152 /* GbE can write GbE. */
1153 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1154 /* GbE can read GbE. */
1155 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1156 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001157 break;
1158 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001159
1160 write_image(filename, image, size);
1161}
1162
Bill XIEfa5f9942017-09-12 11:22:29 +08001163static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001164{
Bill XIE612ec0e2017-08-30 16:10:27 +08001165 fmba_t *fmba = find_fmba(image, size);
1166 if (!fmba)
1167 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001168
1169 if (ifd_version >= IFD_VERSION_2) {
1170 /* Access bits for each region are read: 19:8 write: 31:20 */
1171 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1172 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1173 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001174 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001175 } else {
1176 fmba->flmstr1 = 0xffff0000;
1177 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001178 /* Keep chipset specific Requester ID */
1179 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001180 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001181
1182 write_image(filename, image, size);
1183}
1184
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001185static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1186 const unsigned int value)
1187{
1188 if (!fpsba || !fdb) {
1189 fprintf(stderr, "Internal error\n");
1190 exit(EXIT_FAILURE);
1191 }
1192
1193 /* SoC Strap Length, aka PSL, aka ISL */
1194 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1195 if (strap >= SSL) {
1196 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1197 exit(EXIT_FAILURE);
1198 }
1199 fpsba->pchstrp[strap] = value;
1200}
1201
Bill XIEb3e15a22017-09-07 18:34:50 +08001202/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001203static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001204{
1205 if (ifd_version >= IFD_VERSION_2) {
1206 printf("%sting the HAP bit to %s Intel ME...\n",
1207 altmedisable?"Set":"Unset",
1208 altmedisable?"disable":"enable");
1209 if (altmedisable)
1210 fpsba->pchstrp[0] |= (1 << 16);
1211 else
1212 fpsba->pchstrp[0] &= ~(1 << 16);
1213 } else {
1214 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1215 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1216 "and MCH_AltMeDisable to %s Intel ME...\n",
1217 altmedisable?"Set":"Unset",
1218 altmedisable?"disable":"enable");
1219 if (altmedisable) {
1220 /* MCH_MeDisable */
1221 fmsba->data[0] |= 1;
1222 /* MCH_AltMeDisable */
1223 fmsba->data[0] |= (1 << 7);
1224 /* ICH_MeDisable */
1225 fpsba->pchstrp[0] |= 1;
1226 } else {
1227 fmsba->data[0] &= ~1;
1228 fmsba->data[0] &= ~(1 << 7);
1229 fpsba->pchstrp[0] &= ~1;
1230 }
1231 } else {
1232 printf("%sting the AltMeDisable to %s Intel ME...\n",
1233 altmedisable?"Set":"Unset",
1234 altmedisable?"disable":"enable");
1235 if (altmedisable)
1236 fpsba->pchstrp[10] |= (1 << 7);
1237 else
1238 fpsba->pchstrp[10] &= ~(1 << 7);
1239 }
1240 }
1241}
1242
Jacob Garber595d9262019-06-27 17:33:10 -06001243static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001244 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001245{
Bill XIE612ec0e2017-08-30 16:10:27 +08001246 frba_t *frba = find_frba(image, size);
1247 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001248 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001249
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001250 region_t region = get_region(frba, region_type);
1251 if (region.size <= 0xfff) {
1252 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1253 region_name(region_type));
1254 exit(EXIT_FAILURE);
1255 }
1256
Scott Duplichanf2c98372014-12-12 21:03:06 -06001257 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001258 if (region_fd == -1) {
1259 perror("Could not open file");
1260 exit(EXIT_FAILURE);
1261 }
1262 struct stat buf;
1263 if (fstat(region_fd, &buf) == -1) {
1264 perror("Could not stat file");
1265 exit(EXIT_FAILURE);
1266 }
1267 int region_size = buf.st_size;
1268
1269 printf("File %s is %d bytes\n", region_fname, region_size);
1270
1271 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001272 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001273 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1274 " bytes. Not injecting.\n",
1275 region_name(region_type), region.size,
1276 region.size, region_size, region_size);
1277 exit(EXIT_FAILURE);
1278 }
1279
1280 int offset = 0;
1281 if ((region_type == 1) && (region_size < region.size)) {
1282 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1283 " bytes. Padding before injecting.\n",
1284 region_name(region_type), region.size,
1285 region.size, region_size, region_size);
1286 offset = region.size - region_size;
1287 memset(image + region.base, 0xff, offset);
1288 }
1289
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001290 if (size < region.base + offset + region_size) {
1291 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1292 size, region.base + offset + region_size);
1293 exit(EXIT_FAILURE);
1294 }
1295
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001296 if (read(region_fd, image + region.base + offset, region_size)
1297 != region_size) {
1298 perror("Could not read file");
1299 exit(EXIT_FAILURE);
1300 }
1301
1302 close(region_fd);
1303
1304 printf("Adding %s as the %s section of %s\n",
1305 region_fname, region_name(region_type), filename);
1306 write_image(filename, image, size);
1307}
1308
Jacob Garber595d9262019-06-27 17:33:10 -06001309static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001310{
1311 unsigned int y = 1;
1312 if (x == 0)
1313 return 0;
1314 while (y <= x)
1315 y = y << 1;
1316
1317 return y;
1318}
1319
1320/**
1321 * Determine if two memory regions overlap.
1322 *
1323 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001324 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001325 * @return 1 if the two regions overlap
1326 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001327static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001328{
Bill XIEfa5f9942017-09-12 11:22:29 +08001329 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001330 return 0;
1331
Nico Huber844eda02019-01-05 00:06:19 +01001332 /* r1 should be either completely below or completely above r2 */
1333 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001334}
1335
Jacob Garber595d9262019-06-27 17:33:10 -06001336static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001337 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001338{
1339 FILE *romlayout;
1340 char tempstr[256];
1341 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001342 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001343 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001344 region_t current_regions[MAX_REGIONS];
1345 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001346 int new_extent = 0;
1347 char *new_image;
1348
1349 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001350 frba_t *frba = find_frba(image, size);
1351 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001352 exit(EXIT_FAILURE);
1353
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001354 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001355 current_regions[i] = get_region(frba, i);
1356 new_regions[i] = get_region(frba, i);
1357 }
1358
1359 /* read new layout */
1360 romlayout = fopen(layout_fname, "r");
1361
1362 if (!romlayout) {
1363 perror("Could not read layout file.\n");
1364 exit(EXIT_FAILURE);
1365 }
1366
1367 while (!feof(romlayout)) {
1368 char *tstr1, *tstr2;
1369
Patrick Georgi802ad522014-08-09 17:12:23 +02001370 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001371 layout_region_name))
1372 continue;
1373
1374 region_number = region_num(layout_region_name);
1375 if (region_number < 0)
1376 continue;
1377
1378 tstr1 = strtok(tempstr, ":");
1379 tstr2 = strtok(NULL, ":");
1380 if (!tstr1 || !tstr2) {
1381 fprintf(stderr, "Could not parse layout file.\n");
1382 exit(EXIT_FAILURE);
1383 }
1384 new_regions[region_number].base = strtol(tstr1,
1385 (char **)NULL, 16);
1386 new_regions[region_number].limit = strtol(tstr2,
1387 (char **)NULL, 16);
1388 new_regions[region_number].size =
1389 new_regions[region_number].limit -
1390 new_regions[region_number].base + 1;
1391
1392 if (new_regions[region_number].size < 0)
1393 new_regions[region_number].size = 0;
1394 }
1395 fclose(romlayout);
1396
1397 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001398 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001399 if (new_regions[i].size == 0)
1400 continue;
1401
1402 if (new_regions[i].size < current_regions[i].size) {
1403 printf("DANGER: Region %s is shrinking.\n",
1404 region_name(i));
1405 printf(" The region will be truncated to fit.\n");
1406 printf(" This may result in an unusable image.\n");
1407 }
1408
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001409 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001410 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001411 fprintf(stderr, "Regions would overlap.\n");
1412 exit(EXIT_FAILURE);
1413 }
1414 }
1415
1416 /* detect if the image size should grow */
1417 if (new_extent < new_regions[i].limit)
1418 new_extent = new_regions[i].limit;
1419 }
1420
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001421 /* check if the image is actually a Flash Descriptor region */
1422 if (size == new_regions[0].size) {
1423 printf("The image is a single Flash Descriptor:\n");
1424 printf(" Only the descriptor will be modified\n");
1425 new_extent = size;
1426 } else {
1427 new_extent = next_pow2(new_extent - 1);
1428 if (new_extent != size) {
1429 printf("The image has changed in size.\n");
1430 printf("The old image is %d bytes.\n", size);
1431 printf("The new image is %d bytes.\n", new_extent);
1432 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001433 }
1434
1435 /* copy regions to a new image */
1436 new_image = malloc(new_extent);
1437 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001438 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001439 int copy_size = new_regions[i].size;
1440 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001441 const region_t *current = &current_regions[i];
1442 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001443
Bill XIEfa5f9942017-09-12 11:22:29 +08001444 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001445 continue;
1446
Bill XIEfa5f9942017-09-12 11:22:29 +08001447 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001448 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001449 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001450 if (i == REGION_BIOS)
1451 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001452 }
1453
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001454 if ((i == REGION_BIOS) && (new->size < current->size)) {
1455 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001456 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001457 }
1458
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001459 if (size < current->base + offset_current + copy_size) {
1460 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1461 region_name(i));
1462 continue;
1463 };
1464
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001465 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1466 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001467 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1468 offset_current, current->limit, current->size);
1469 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1470 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001471
Bill XIEfa5f9942017-09-12 11:22:29 +08001472 memcpy(new_image + new->base + offset_new,
1473 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001474 copy_size);
1475 }
1476
1477 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001478 frba = find_frba(new_image, new_extent);
1479 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001480 exit(EXIT_FAILURE);
1481
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001482 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001483 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001484 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001485
1486 write_image(filename, new_image, new_extent);
1487 free(new_image);
1488}
1489
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001490static void print_version(void)
1491{
1492 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1493 printf("Copyright (C) 2011 Google Inc.\n\n");
1494 printf
1495 ("This program is free software: you can redistribute it and/or modify\n"
1496 "it under the terms of the GNU General Public License as published by\n"
1497 "the Free Software Foundation, version 2 of the License.\n\n"
1498 "This program is distributed in the hope that it will be useful,\n"
1499 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1500 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001501 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001502}
1503
1504static void print_usage(const char *name)
1505{
1506 printf("usage: %s [-vhdix?] <filename>\n", name);
1507 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001508 " -d | --dump: dump intel firmware descriptor\n"
1509 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1510 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1511 " -x | --extract: extract intel fd modules\n"
1512 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1513 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001514 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001515 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1516 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1517 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1518 " can only be used once per run:\n"
1519 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1520 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1521 " Dual Output Fast Read Support\n"
1522 " -l | --lock Lock firmware descriptor and ME region\n"
1523 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001524 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1525 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001526 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301527 " adl - Alder Lake\n"
1528 " aplk - Apollo Lake\n"
1529 " cnl - Cannon Lake\n"
1530 " glk - Gemini Lake\n"
1531 " icl - Ice Lake\n"
1532 " jsl - Jasper Lake\n"
1533 " sklkbl - Sky Lake/Kaby Lake\n"
1534 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001535 " -S | --setpchstrap Write a PCH strap\n"
1536 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001537 " -v | --version: print the version\n"
1538 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001539 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1540 "\n");
1541}
1542
1543int main(int argc, char *argv[])
1544{
1545 int opt, option_index = 0;
1546 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001547 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001548 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001549 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001550 char *region_type_string = NULL, *region_fname = NULL;
1551 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001552 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001553 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001554 unsigned int value = 0;
1555 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001556 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001557 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1558
Bill XIEfa5f9942017-09-12 11:22:29 +08001559 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001560 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001561 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001562 {"extract", 0, NULL, 'x'},
1563 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001564 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001565 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001566 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001567 {"density", 1, NULL, 'D'},
1568 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001569 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001570 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001571 {"lock", 0, NULL, 'l'},
1572 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001573 {"version", 0, NULL, 'v'},
1574 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001575 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001576 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001577 {"setpchstrap", 1, NULL, 'S'},
1578 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001579 {0, 0, 0, 0}
1580 };
1581
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001582 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 -07001583 long_options, &option_index)) != EOF) {
1584 switch (opt) {
1585 case 'd':
1586 mode_dump = 1;
1587 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001588 case 'S':
1589 mode_setstrap = 1;
1590 pchstrap = strtoul(optarg, NULL, 0);
1591 break;
1592 case 'V':
1593 value = strtoul(optarg, NULL, 0);
1594 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001595 case 'f':
1596 mode_layout = 1;
1597 layout_fname = strdup(optarg);
1598 if (!layout_fname) {
1599 fprintf(stderr, "No layout file specified\n");
1600 print_usage(argv[0]);
1601 exit(EXIT_FAILURE);
1602 }
1603 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001604 case 'x':
1605 mode_extract = 1;
1606 break;
1607 case 'i':
1608 // separate type and file name
1609 region_type_string = strdup(optarg);
1610 region_fname = strchr(region_type_string, ':');
1611 if (!region_fname) {
1612 print_usage(argv[0]);
1613 exit(EXIT_FAILURE);
1614 }
1615 region_fname[0] = '\0';
1616 region_fname++;
1617 // Descriptor, BIOS, ME, GbE, Platform
1618 // valid type?
1619 if (!strcasecmp("Descriptor", region_type_string))
1620 region_type = 0;
1621 else if (!strcasecmp("BIOS", region_type_string))
1622 region_type = 1;
1623 else if (!strcasecmp("ME", region_type_string))
1624 region_type = 2;
1625 else if (!strcasecmp("GbE", region_type_string))
1626 region_type = 3;
1627 else if (!strcasecmp("Platform", region_type_string))
1628 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001629 else if (!strcasecmp("EC", region_type_string))
1630 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001631 if (region_type == -1) {
1632 fprintf(stderr, "No such region type: '%s'\n\n",
1633 region_type_string);
1634 print_usage(argv[0]);
1635 exit(EXIT_FAILURE);
1636 }
1637 mode_inject = 1;
1638 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001639 case 'n':
1640 mode_newlayout = 1;
1641 layout_fname = strdup(optarg);
1642 if (!layout_fname) {
1643 fprintf(stderr, "No layout file specified\n");
1644 print_usage(argv[0]);
1645 exit(EXIT_FAILURE);
1646 }
1647 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001648 case 'O':
1649 new_filename = strdup(optarg);
1650 if (!new_filename) {
1651 fprintf(stderr, "No output filename specified\n");
1652 print_usage(argv[0]);
1653 exit(EXIT_FAILURE);
1654 }
1655 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001656 case 'D':
1657 mode_density = 1;
1658 new_density = strtoul(optarg, NULL, 0);
1659 switch (new_density) {
1660 case 512:
1661 new_density = COMPONENT_DENSITY_512KB;
1662 break;
1663 case 1:
1664 new_density = COMPONENT_DENSITY_1MB;
1665 break;
1666 case 2:
1667 new_density = COMPONENT_DENSITY_2MB;
1668 break;
1669 case 4:
1670 new_density = COMPONENT_DENSITY_4MB;
1671 break;
1672 case 8:
1673 new_density = COMPONENT_DENSITY_8MB;
1674 break;
1675 case 16:
1676 new_density = COMPONENT_DENSITY_16MB;
1677 break;
1678 case 32:
1679 new_density = COMPONENT_DENSITY_32MB;
1680 break;
1681 case 64:
1682 new_density = COMPONENT_DENSITY_64MB;
1683 break;
1684 case 0:
1685 new_density = COMPONENT_DENSITY_UNUSED;
1686 break;
1687 default:
1688 printf("error: Unknown density\n");
1689 print_usage(argv[0]);
1690 exit(EXIT_FAILURE);
1691 }
1692 break;
1693 case 'C':
1694 selected_chip = strtol(optarg, NULL, 0);
1695 if (selected_chip > 2) {
1696 fprintf(stderr, "error: Invalid chip selection\n");
1697 print_usage(argv[0]);
1698 exit(EXIT_FAILURE);
1699 }
1700 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001701 case 'M':
1702 mode_altmedisable = 1;
1703 altmedisable = strtol(optarg, NULL, 0);
1704 if (altmedisable > 1) {
1705 fprintf(stderr, "error: Illegal value\n");
1706 print_usage(argv[0]);
1707 exit(EXIT_FAILURE);
1708 }
1709 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001710 case 's':
1711 // Parse the requested SPI frequency
1712 inputfreq = strtol(optarg, NULL, 0);
1713 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001714 case 17:
1715 spifreq = SPI_FREQUENCY_17MHZ;
1716 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001717 case 20:
1718 spifreq = SPI_FREQUENCY_20MHZ;
1719 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001720 case 30:
1721 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1722 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001723 case 33:
1724 spifreq = SPI_FREQUENCY_33MHZ;
1725 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001726 case 48:
1727 spifreq = SPI_FREQUENCY_48MHZ;
1728 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001729 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001730 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001731 break;
1732 default:
1733 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1734 inputfreq);
1735 print_usage(argv[0]);
1736 exit(EXIT_FAILURE);
1737 }
1738 mode_spifreq = 1;
1739 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001740 case 'e':
1741 mode_em100 = 1;
1742 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001743 case 'l':
1744 mode_locked = 1;
1745 if (mode_unlocked == 1) {
1746 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1747 exit(EXIT_FAILURE);
1748 }
1749 break;
1750 case 'u':
1751 mode_unlocked = 1;
1752 if (mode_locked == 1) {
1753 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1754 exit(EXIT_FAILURE);
1755 }
1756 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001757 case 'p':
1758 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001759 platform = PLATFORM_APL;
1760 } else if (!strcmp(optarg, "cnl")) {
1761 platform = PLATFORM_CNL;
1762 } else if (!strcmp(optarg, "glk")) {
1763 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301764 } else if (!strcmp(optarg, "icl")) {
1765 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301766 } else if (!strcmp(optarg, "jsl")) {
1767 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001768 } else if (!strcmp(optarg, "sklkbl")) {
1769 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001770 } else if (!strcmp(optarg, "tgl")) {
1771 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301772 } else if (!strcmp(optarg, "adl")) {
1773 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001774 } else {
1775 fprintf(stderr, "Unknown platform: %s\n", optarg);
1776 exit(EXIT_FAILURE);
1777 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001778 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001779 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001780 case 't':
1781 mode_validate = 1;
1782 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001783 case 'v':
1784 print_version();
1785 exit(EXIT_SUCCESS);
1786 break;
1787 case 'h':
1788 case '?':
1789 default:
1790 print_usage(argv[0]);
1791 exit(EXIT_SUCCESS);
1792 break;
1793 }
1794 }
1795
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001796 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001797 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001798 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001799 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001800 print_usage(argv[0]);
1801 exit(EXIT_FAILURE);
1802 }
1803
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001804 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001805 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001806 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001807 fprintf(stderr, "You need to specify a mode.\n\n");
1808 print_usage(argv[0]);
1809 exit(EXIT_FAILURE);
1810 }
1811
1812 if (optind + 1 != argc) {
1813 fprintf(stderr, "You need to specify a file.\n\n");
1814 print_usage(argv[0]);
1815 exit(EXIT_FAILURE);
1816 }
1817
1818 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001819 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001820 if (bios_fd == -1) {
1821 perror("Could not open file");
1822 exit(EXIT_FAILURE);
1823 }
1824 struct stat buf;
1825 if (fstat(bios_fd, &buf) == -1) {
1826 perror("Could not stat file");
1827 exit(EXIT_FAILURE);
1828 }
1829 int size = buf.st_size;
1830
1831 printf("File %s is %d bytes\n", filename, size);
1832
1833 char *image = malloc(size);
1834 if (!image) {
1835 printf("Out of memory.\n");
1836 exit(EXIT_FAILURE);
1837 }
1838
1839 if (read(bios_fd, image, size) != size) {
1840 perror("Could not read file");
1841 exit(EXIT_FAILURE);
1842 }
1843
1844 close(bios_fd);
1845
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001846 // generate new filename
1847 if (new_filename == NULL) {
1848 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1849 if (!new_filename) {
1850 printf("Out of memory.\n");
1851 exit(EXIT_FAILURE);
1852 }
1853 // - 5: leave room for ".new\0"
1854 strcpy(new_filename, filename);
1855 strcat(new_filename, ".new");
1856 }
1857
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001858 check_ifd_version(image, size);
1859
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001860 if (mode_dump)
1861 dump_fd(image, size);
1862
Chris Douglass03ce0142014-02-26 13:30:13 -05001863 if (mode_layout)
1864 dump_layout(image, size, layout_fname);
1865
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001866 if (mode_extract)
1867 write_regions(image, size);
1868
Mathew Kingc7ddc992019-08-08 14:59:25 -06001869 if (mode_validate)
1870 validate_layout(image, size);
1871
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001872 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001873 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001874 region_fname);
1875
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001876 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001877 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001878
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001879 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001880 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001881
Jan Tatjefa317512016-03-11 00:52:07 +01001882 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001883 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001884
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001885 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001886 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001887
Alexander Couzensd12ea112016-09-10 13:33:05 +02001888 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001889 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001890
1891 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001892 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001893
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001894 if (mode_setstrap) {
1895 fpsba_t *fpsba = find_fpsba(image, size);
1896 const fdbar_t *fdb = find_fd(image, size);
1897 set_pchstrap(fpsba, fdb, pchstrap, value);
1898 write_image(new_filename, image, size);
1899 }
1900
Bill XIEb3e15a22017-09-07 18:34:50 +08001901 if (mode_altmedisable) {
1902 fpsba_t *fpsba = find_fpsba(image, size);
1903 fmsba_t *fmsba = find_fmsba(image, size);
1904 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001905 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001906 }
1907
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001908 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001909 free(image);
1910
1911 return 0;
1912}