blob: fa7817a3bc3ff6e442bbf9cd5fd4dc0d85efe88a [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}
Bill XIEfa5f9942017-09-12 11:22:29 +0800523static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700524{
525 printf("\nFound Component Section\n");
526 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700527 printf(" Dual Output Fast Read Support: %ssupported\n",
528 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700529 printf(" Read ID/Read Status Clock Frequency: ");
530 decode_spi_frequency((fcba->flcomp >> 27) & 7);
531 printf("\n Write/Erase Clock Frequency: ");
532 decode_spi_frequency((fcba->flcomp >> 24) & 7);
533 printf("\n Fast Read Clock Frequency: ");
534 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700535 printf("\n Fast Read Support: %ssupported",
536 (fcba->flcomp & (1 << 20))?"":"not ");
537 printf("\n Read Clock Frequency: ");
538 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700539
540 switch (ifd_version) {
541 case IFD_VERSION_1:
542 printf("\n Component 2 Density: ");
543 decode_component_density((fcba->flcomp >> 3) & 7);
544 printf("\n Component 1 Density: ");
545 decode_component_density(fcba->flcomp & 7);
546 break;
547 case IFD_VERSION_2:
548 printf("\n Component 2 Density: ");
549 decode_component_density((fcba->flcomp >> 4) & 0xf);
550 printf("\n Component 1 Density: ");
551 decode_component_density(fcba->flcomp & 0xf);
552 break;
553 }
554
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700555 printf("\n");
556 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700557 printf(" Invalid Instruction 3: 0x%02x\n",
558 (fcba->flill >> 24) & 0xff);
559 printf(" Invalid Instruction 2: 0x%02x\n",
560 (fcba->flill >> 16) & 0xff);
561 printf(" Invalid Instruction 1: 0x%02x\n",
562 (fcba->flill >> 8) & 0xff);
563 printf(" Invalid Instruction 0: 0x%02x\n",
564 fcba->flill & 0xff);
565 printf("FLPB 0x%08x\n", fcba->flpb);
566 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
567 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700568}
569
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200570static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700571{
Bill XIE4651d452017-09-12 11:54:48 +0800572 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200573 /* SoC Strap Length, aka PSL, aka ISL */
574 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
575
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700576 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200577 for (i = 0; i < SSL; i++)
578 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800579
580 if (ifd_version >= IFD_VERSION_2) {
581 printf("HAP bit is %sset\n",
582 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
583 } else if (chipset >= CHIPSET_ICH8
584 && chipset <= CHIPSET_ICH10) {
585 printf("ICH_MeDisable bit is %sset\n",
586 fpsba->pchstrp[0] & 1 ? "" : "not ");
587 } else {
588 printf("AltMeDisable bit is %sset\n",
589 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
590 }
591
Bill XIE4651d452017-09-12 11:54:48 +0800592 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700593}
594
595static void decode_flmstr(uint32_t flmstr)
596{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700597 int wr_shift, rd_shift;
598 if (ifd_version >= IFD_VERSION_2) {
599 wr_shift = FLMSTR_WR_SHIFT_V2;
600 rd_shift = FLMSTR_RD_SHIFT_V2;
601 } else {
602 wr_shift = FLMSTR_WR_SHIFT_V1;
603 rd_shift = FLMSTR_RD_SHIFT_V1;
604 }
605
606 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700607 if (ifd_version >= IFD_VERSION_2)
608 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700609 (flmstr & (1 << (wr_shift + 8))) ?
610 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700611 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700612 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700613 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700614 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700615 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700616 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700617 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700618 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700619 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700620 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700621
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700622 if (ifd_version >= IFD_VERSION_2)
623 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700624 (flmstr & (1 << (rd_shift + 8))) ?
625 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700626 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700627 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700628 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700629 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700630 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700631 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700632 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700633 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700634 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700635 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700636
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700637 /* Requestor ID doesn't exist for ifd 2 */
638 if (ifd_version < IFD_VERSION_2)
639 printf(" Requester ID: 0x%04x\n\n",
640 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700641}
642
Bill XIEfa5f9942017-09-12 11:22:29 +0800643static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700644{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700645 printf("Found Master Section\n");
646 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
647 decode_flmstr(fmba->flmstr1);
648 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
649 decode_flmstr(fmba->flmstr2);
650 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
651 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700652 if (ifd_version >= IFD_VERSION_2) {
653 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
654 decode_flmstr(fmba->flmstr5);
655 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700656}
657
Bill XIEfa5f9942017-09-12 11:22:29 +0800658static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700659{
Bill XIE612ec0e2017-08-30 16:10:27 +0800660 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700661 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800662 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
663 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800664
665 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
666 printf("MCH_MeDisable bit is %sset\n",
667 fmsba->data[0] & 1 ? "" : "not ");
668 printf("MCH_AltMeDisable bit is %sset\n",
669 fmsba->data[0] & (1 << 7) ? "" : "not ");
670 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700671}
672
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700673static void dump_jid(uint32_t jid)
674{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100675 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700676 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100677 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200678 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100679 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200680 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700681}
682
683static void dump_vscc(uint32_t vscc)
684{
685 printf(" Lower Erase Opcode: 0x%02x\n",
686 vscc >> 24);
687 printf(" Lower Write Enable on Write Status: 0x%02x\n",
688 vscc & (1 << 20) ? 0x06 : 0x50);
689 printf(" Lower Write Status Required: %s\n",
690 vscc & (1 << 19) ? "Yes" : "No");
691 printf(" Lower Write Granularity: %d bytes\n",
692 vscc & (1 << 18) ? 64 : 1);
693 printf(" Lower Block / Sector Erase Size: ");
694 switch ((vscc >> 16) & 0x3) {
695 case 0:
696 printf("256 Byte\n");
697 break;
698 case 1:
699 printf("4KB\n");
700 break;
701 case 2:
702 printf("8KB\n");
703 break;
704 case 3:
705 printf("64KB\n");
706 break;
707 }
708
709 printf(" Upper Erase Opcode: 0x%02x\n",
710 (vscc >> 8) & 0xff);
711 printf(" Upper Write Enable on Write Status: 0x%02x\n",
712 vscc & (1 << 4) ? 0x06 : 0x50);
713 printf(" Upper Write Status Required: %s\n",
714 vscc & (1 << 3) ? "Yes" : "No");
715 printf(" Upper Write Granularity: %d bytes\n",
716 vscc & (1 << 2) ? 64 : 1);
717 printf(" Upper Block / Sector Erase Size: ");
718 switch (vscc & 0x3) {
719 case 0:
720 printf("256 Byte\n");
721 break;
722 case 1:
723 printf("4KB\n");
724 break;
725 case 2:
726 printf("8KB\n");
727 break;
728 case 3:
729 printf("64KB\n");
730 break;
731 }
732}
733
Bill XIEfa5f9942017-09-12 11:22:29 +0800734static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700735{
736 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200737 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
738 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700739
740 printf("ME VSCC table:\n");
741 for (i = 0; i < num; i++) {
742 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
743 dump_jid(vtba->entry[i].jid);
744 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
745 dump_vscc(vtba->entry[i].vscc);
746 }
747 printf("\n");
748}
749
Bill XIEfa5f9942017-09-12 11:22:29 +0800750static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700751{
752 int i, j;
753 printf("OEM Section:\n");
754 for (i = 0; i < 4; i++) {
755 printf("%02x:", i << 4);
756 for (j = 0; j < 16; j++)
757 printf(" %02x", oem[(i<<4)+j]);
758 printf ("\n");
759 }
760 printf ("\n");
761}
762
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700763static void dump_fd(char *image, int size)
764{
Bill XIE612ec0e2017-08-30 16:10:27 +0800765 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700766 if (!fdb)
767 exit(EXIT_FAILURE);
768
Subrata Banik26058dc2020-08-26 15:12:16 +0530769 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
770 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700771 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
772 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
773 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
774 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
775 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
776
777 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
778 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
779 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
780 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
781 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
782
783 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
784 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
785 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
786
Stefan Tauner0d226142018-08-05 18:56:53 +0200787 char *flumap = find_flumap(image, size);
788 uint32_t flumap1 = *(uint32_t *)flumap;
789 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700790 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200791 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700792 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200793 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700794 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200795 (image + ((flumap1 & 0xff) << 4)),
796 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800797 dump_oem((const uint8_t *)image + 0xf00);
798
799 const frba_t *frba = find_frba(image, size);
800 const fcba_t *fcba = find_fcba(image, size);
801 const fpsba_t *fpsba = find_fpsba(image, size);
802 const fmba_t *fmba = find_fmba(image, size);
803 const fmsba_t *fmsba = find_fmsba(image, size);
804
805 if (frba && fcba && fpsba && fmba && fmsba) {
806 dump_frba(frba);
807 dump_fcba(fcba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200808 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800809 dump_fmba(fmba);
810 dump_fmsba(fmsba);
811 } else {
812 printf("FD is corrupted!\n");
813 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700814}
815
Bill XIEfa5f9942017-09-12 11:22:29 +0800816static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500817{
Bill XIE612ec0e2017-08-30 16:10:27 +0800818 const frba_t *frba = find_frba(image, size);
819 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500820 exit(EXIT_FAILURE);
821
Bill XIE612ec0e2017-08-30 16:10:27 +0800822 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500823}
824
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700825static void write_regions(char *image, int size)
826{
Bill XIEfa5f9942017-09-12 11:22:29 +0800827 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800828 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700829
Bill XIE612ec0e2017-08-30 16:10:27 +0800830 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700831 exit(EXIT_FAILURE);
832
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700833 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700834 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700835 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700836 if (region.size > 0) {
837 int region_fd;
838 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600839 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700840 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200841 if (region_fd < 0) {
842 perror("Error while trying to open file");
843 exit(EXIT_FAILURE);
844 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700845 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700846 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700847 close(region_fd);
848 }
849 }
850}
851
Mathew Kingc7ddc992019-08-08 14:59:25 -0600852static void validate_layout(char *image, int size)
853{
854 uint i, errors = 0;
855 struct fmap *fmap;
856 long int fmap_loc = fmap_find((uint8_t *)image, size);
857 const frba_t *frba = find_frba(image, size);
858
859 if (fmap_loc < 0 || !frba)
860 exit(EXIT_FAILURE);
861
862 fmap = (struct fmap *)(image + fmap_loc);
863
864 for (i = 0; i < max_regions; i++) {
865 if (region_names[i].fmapname == NULL)
866 continue;
867
868 region_t region = get_region(frba, i);
869
870 if (region.size == 0)
871 continue;
872
873 const struct fmap_area *area =
874 fmap_find_area(fmap, region_names[i].fmapname);
875
876 if (!area)
877 continue;
878
879 if ((uint)region.base != area->offset ||
880 (uint)region.size != area->size) {
881 printf("Region mismatch between %s and %s\n",
882 region_names[i].terse, area->name);
883 printf(" Descriptor region %s:\n", region_names[i].terse);
884 printf(" offset: 0x%08x\n", region.base);
885 printf(" length: 0x%08x\n", region.size);
886 printf(" FMAP area %s:\n", area->name);
887 printf(" offset: 0x%08x\n", area->offset);
888 printf(" length: 0x%08x\n", area->size);
889 errors++;
890 }
891 }
892
893 if (errors > 0)
894 exit(EXIT_FAILURE);
895}
896
Bill XIEfa5f9942017-09-12 11:22:29 +0800897static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700898{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700899 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100900 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700901
902 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100903 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600904 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700905 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200906 if (new_fd < 0) {
907 perror("Error while trying to open file");
908 exit(EXIT_FAILURE);
909 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700910 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700911 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700912 close(new_fd);
913}
914
Bill XIEfa5f9942017-09-12 11:22:29 +0800915static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700916 enum spi_frequency freq)
917{
Bill XIE612ec0e2017-08-30 16:10:27 +0800918 fcba_t *fcba = find_fcba(image, size);
919 if (!fcba)
920 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700921
922 /* clear bits 21-29 */
923 fcba->flcomp &= ~0x3fe00000;
924 /* Read ID and Read Status Clock Frequency */
925 fcba->flcomp |= freq << 27;
926 /* Write and Erase Clock Frequency */
927 fcba->flcomp |= freq << 24;
928 /* Fast Read Clock Frequency */
929 fcba->flcomp |= freq << 21;
930
931 write_image(filename, image, size);
932}
933
Bill XIEfa5f9942017-09-12 11:22:29 +0800934static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700935{
Bill XIE612ec0e2017-08-30 16:10:27 +0800936 fcba_t *fcba = find_fcba(image, size);
937 if (!fcba)
938 exit(EXIT_FAILURE);
939
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700940 int freq;
941
942 switch (ifd_version) {
943 case IFD_VERSION_1:
944 freq = SPI_FREQUENCY_20MHZ;
945 break;
946 case IFD_VERSION_2:
947 freq = SPI_FREQUENCY_17MHZ;
948 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700949 default:
950 freq = SPI_FREQUENCY_17MHZ;
951 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700952 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700953
954 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700955 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700956}
957
Bill XIEfa5f9942017-09-12 11:22:29 +0800958static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100959 unsigned int density)
960{
Bill XIE612ec0e2017-08-30 16:10:27 +0800961 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200962 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800963 if (!fcba)
964 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100965
966 printf("Setting chip density to ");
967 decode_component_density(density);
968 printf("\n");
969
970 switch (ifd_version) {
971 case IFD_VERSION_1:
972 /* fail if selected density is not supported by this version */
973 if ( (density == COMPONENT_DENSITY_32MB) ||
974 (density == COMPONENT_DENSITY_64MB) ||
975 (density == COMPONENT_DENSITY_UNUSED) ) {
976 printf("error: Selected density not supported in IFD version 1.\n");
977 exit(EXIT_FAILURE);
978 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200979 mask = 0x7;
980 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100981 break;
982 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200983 mask = 0xf;
984 chip2_offset = 4;
985 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100986 default:
987 printf("error: Unknown IFD version\n");
988 exit(EXIT_FAILURE);
989 break;
990 }
991
992 /* clear chip density for corresponding chip */
993 switch (selected_chip) {
994 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200995 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100996 break;
997 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200998 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100999 break;
1000 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001001 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001002 break;
1003 }
1004
1005 /* set the new density */
1006 if (selected_chip == 1 || selected_chip == 0)
1007 fcba->flcomp |= (density); /* first chip */
1008 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001009 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001010
1011 write_image(filename, image, size);
1012}
1013
Duncan Laurie7775d672019-06-06 13:39:26 -07001014static int check_region(const frba_t *frba, unsigned int region_type)
1015{
1016 region_t region;
1017
1018 if (!frba)
1019 return 0;
1020
1021 region = get_region(frba, region_type);
1022 return !!((region.base < region.limit) && (region.size > 0));
1023}
1024
Bill XIEfa5f9942017-09-12 11:22:29 +08001025static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001026{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001027 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001028 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001029 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001030 if (!fmba)
1031 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001032
1033 if (ifd_version >= IFD_VERSION_2) {
1034 wr_shift = FLMSTR_WR_SHIFT_V2;
1035 rd_shift = FLMSTR_RD_SHIFT_V2;
1036
1037 /* Clear non-reserved bits */
1038 fmba->flmstr1 &= 0xff;
1039 fmba->flmstr2 &= 0xff;
1040 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001041 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001042 } else {
1043 wr_shift = FLMSTR_WR_SHIFT_V1;
1044 rd_shift = FLMSTR_RD_SHIFT_V1;
1045
1046 fmba->flmstr1 = 0;
1047 fmba->flmstr2 = 0;
1048 /* Requestor ID */
1049 fmba->flmstr3 = 0x118;
1050 }
1051
Andrey Petrov96ecb772016-10-31 19:31:54 -07001052 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001053 case PLATFORM_APL:
1054 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001055 /* CPU/BIOS can read descriptor and BIOS */
1056 fmba->flmstr1 |= 0x3 << rd_shift;
1057 /* CPU/BIOS can write BIOS */
1058 fmba->flmstr1 |= 0x2 << wr_shift;
1059 /* TXE can read descriptor, BIOS and Device Expansion */
1060 fmba->flmstr2 |= 0x23 << rd_shift;
1061 /* TXE can only write Device Expansion */
1062 fmba->flmstr2 |= 0x20 << wr_shift;
1063 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001064 case PLATFORM_CNL:
1065 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001066 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001067 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301068 case PLATFORM_JSL:
Subrata Banik46f80732020-03-14 15:01:42 +05301069 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001070 /* CPU/BIOS can read descriptor and BIOS. */
1071 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1072 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1073 /* CPU/BIOS can write BIOS. */
1074 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1075 /* ME can read descriptor and ME. */
1076 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1077 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001078 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001079 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1080 if (check_region(frba, REGION_GBE)) {
1081 /* BIOS can read/write GbE. */
1082 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1083 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1084 /* ME can read GbE. */
1085 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1086 /* GbE can read descriptor and read/write GbE.. */
1087 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1088 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1089 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1090 }
1091 if (check_region(frba, REGION_PDR)) {
1092 /* BIOS can read/write PDR. */
1093 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1094 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1095 }
1096 if (check_region(frba, REGION_EC)) {
1097 /* BIOS can read EC. */
1098 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1099 /* EC can read descriptor and read/write EC. */
1100 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1101 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1102 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1103 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001104 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001105 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001106 /* CPU/BIOS can read descriptor and BIOS. */
1107 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1108 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1109 /* CPU/BIOS can write BIOS. */
1110 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1111 /* ME can read descriptor and ME. */
1112 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1113 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1114 /* ME can write ME. */
1115 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1116 if (check_region(frba, REGION_GBE)) {
1117 /* BIOS can read GbE. */
1118 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1119 /* BIOS can write GbE. */
1120 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1121 /* ME can read GbE. */
1122 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1123 /* ME can write GbE. */
1124 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1125 /* GbE can write GbE. */
1126 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1127 /* GbE can read GbE. */
1128 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1129 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001130 break;
1131 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001132
1133 write_image(filename, image, size);
1134}
1135
Bill XIEfa5f9942017-09-12 11:22:29 +08001136static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001137{
Bill XIE612ec0e2017-08-30 16:10:27 +08001138 fmba_t *fmba = find_fmba(image, size);
1139 if (!fmba)
1140 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001141
1142 if (ifd_version >= IFD_VERSION_2) {
1143 /* Access bits for each region are read: 19:8 write: 31:20 */
1144 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1145 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1146 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001147 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001148 } else {
1149 fmba->flmstr1 = 0xffff0000;
1150 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001151 /* Keep chipset specific Requester ID */
1152 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001153 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001154
1155 write_image(filename, image, size);
1156}
1157
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001158static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1159 const unsigned int value)
1160{
1161 if (!fpsba || !fdb) {
1162 fprintf(stderr, "Internal error\n");
1163 exit(EXIT_FAILURE);
1164 }
1165
1166 /* SoC Strap Length, aka PSL, aka ISL */
1167 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1168 if (strap >= SSL) {
1169 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1170 exit(EXIT_FAILURE);
1171 }
1172 fpsba->pchstrp[strap] = value;
1173}
1174
Bill XIEb3e15a22017-09-07 18:34:50 +08001175/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001176static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001177{
1178 if (ifd_version >= IFD_VERSION_2) {
1179 printf("%sting the HAP bit to %s Intel ME...\n",
1180 altmedisable?"Set":"Unset",
1181 altmedisable?"disable":"enable");
1182 if (altmedisable)
1183 fpsba->pchstrp[0] |= (1 << 16);
1184 else
1185 fpsba->pchstrp[0] &= ~(1 << 16);
1186 } else {
1187 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1188 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1189 "and MCH_AltMeDisable to %s Intel ME...\n",
1190 altmedisable?"Set":"Unset",
1191 altmedisable?"disable":"enable");
1192 if (altmedisable) {
1193 /* MCH_MeDisable */
1194 fmsba->data[0] |= 1;
1195 /* MCH_AltMeDisable */
1196 fmsba->data[0] |= (1 << 7);
1197 /* ICH_MeDisable */
1198 fpsba->pchstrp[0] |= 1;
1199 } else {
1200 fmsba->data[0] &= ~1;
1201 fmsba->data[0] &= ~(1 << 7);
1202 fpsba->pchstrp[0] &= ~1;
1203 }
1204 } else {
1205 printf("%sting the AltMeDisable to %s Intel ME...\n",
1206 altmedisable?"Set":"Unset",
1207 altmedisable?"disable":"enable");
1208 if (altmedisable)
1209 fpsba->pchstrp[10] |= (1 << 7);
1210 else
1211 fpsba->pchstrp[10] &= ~(1 << 7);
1212 }
1213 }
1214}
1215
Jacob Garber595d9262019-06-27 17:33:10 -06001216static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001217 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001218{
Bill XIE612ec0e2017-08-30 16:10:27 +08001219 frba_t *frba = find_frba(image, size);
1220 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001221 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001222
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001223 region_t region = get_region(frba, region_type);
1224 if (region.size <= 0xfff) {
1225 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1226 region_name(region_type));
1227 exit(EXIT_FAILURE);
1228 }
1229
Scott Duplichanf2c98372014-12-12 21:03:06 -06001230 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001231 if (region_fd == -1) {
1232 perror("Could not open file");
1233 exit(EXIT_FAILURE);
1234 }
1235 struct stat buf;
1236 if (fstat(region_fd, &buf) == -1) {
1237 perror("Could not stat file");
1238 exit(EXIT_FAILURE);
1239 }
1240 int region_size = buf.st_size;
1241
1242 printf("File %s is %d bytes\n", region_fname, region_size);
1243
1244 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001245 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001246 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1247 " bytes. Not injecting.\n",
1248 region_name(region_type), region.size,
1249 region.size, region_size, region_size);
1250 exit(EXIT_FAILURE);
1251 }
1252
1253 int offset = 0;
1254 if ((region_type == 1) && (region_size < region.size)) {
1255 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1256 " bytes. Padding before injecting.\n",
1257 region_name(region_type), region.size,
1258 region.size, region_size, region_size);
1259 offset = region.size - region_size;
1260 memset(image + region.base, 0xff, offset);
1261 }
1262
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001263 if (size < region.base + offset + region_size) {
1264 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1265 size, region.base + offset + region_size);
1266 exit(EXIT_FAILURE);
1267 }
1268
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001269 if (read(region_fd, image + region.base + offset, region_size)
1270 != region_size) {
1271 perror("Could not read file");
1272 exit(EXIT_FAILURE);
1273 }
1274
1275 close(region_fd);
1276
1277 printf("Adding %s as the %s section of %s\n",
1278 region_fname, region_name(region_type), filename);
1279 write_image(filename, image, size);
1280}
1281
Jacob Garber595d9262019-06-27 17:33:10 -06001282static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001283{
1284 unsigned int y = 1;
1285 if (x == 0)
1286 return 0;
1287 while (y <= x)
1288 y = y << 1;
1289
1290 return y;
1291}
1292
1293/**
1294 * Determine if two memory regions overlap.
1295 *
1296 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001297 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001298 * @return 1 if the two regions overlap
1299 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001300static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001301{
Bill XIEfa5f9942017-09-12 11:22:29 +08001302 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001303 return 0;
1304
Nico Huber844eda02019-01-05 00:06:19 +01001305 /* r1 should be either completely below or completely above r2 */
1306 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001307}
1308
Jacob Garber595d9262019-06-27 17:33:10 -06001309static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001310 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001311{
1312 FILE *romlayout;
1313 char tempstr[256];
1314 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001315 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001316 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001317 region_t current_regions[MAX_REGIONS];
1318 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001319 int new_extent = 0;
1320 char *new_image;
1321
1322 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001323 frba_t *frba = find_frba(image, size);
1324 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001325 exit(EXIT_FAILURE);
1326
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001327 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001328 current_regions[i] = get_region(frba, i);
1329 new_regions[i] = get_region(frba, i);
1330 }
1331
1332 /* read new layout */
1333 romlayout = fopen(layout_fname, "r");
1334
1335 if (!romlayout) {
1336 perror("Could not read layout file.\n");
1337 exit(EXIT_FAILURE);
1338 }
1339
1340 while (!feof(romlayout)) {
1341 char *tstr1, *tstr2;
1342
Patrick Georgi802ad522014-08-09 17:12:23 +02001343 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001344 layout_region_name))
1345 continue;
1346
1347 region_number = region_num(layout_region_name);
1348 if (region_number < 0)
1349 continue;
1350
1351 tstr1 = strtok(tempstr, ":");
1352 tstr2 = strtok(NULL, ":");
1353 if (!tstr1 || !tstr2) {
1354 fprintf(stderr, "Could not parse layout file.\n");
1355 exit(EXIT_FAILURE);
1356 }
1357 new_regions[region_number].base = strtol(tstr1,
1358 (char **)NULL, 16);
1359 new_regions[region_number].limit = strtol(tstr2,
1360 (char **)NULL, 16);
1361 new_regions[region_number].size =
1362 new_regions[region_number].limit -
1363 new_regions[region_number].base + 1;
1364
1365 if (new_regions[region_number].size < 0)
1366 new_regions[region_number].size = 0;
1367 }
1368 fclose(romlayout);
1369
1370 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001371 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001372 if (new_regions[i].size == 0)
1373 continue;
1374
1375 if (new_regions[i].size < current_regions[i].size) {
1376 printf("DANGER: Region %s is shrinking.\n",
1377 region_name(i));
1378 printf(" The region will be truncated to fit.\n");
1379 printf(" This may result in an unusable image.\n");
1380 }
1381
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001382 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001383 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001384 fprintf(stderr, "Regions would overlap.\n");
1385 exit(EXIT_FAILURE);
1386 }
1387 }
1388
1389 /* detect if the image size should grow */
1390 if (new_extent < new_regions[i].limit)
1391 new_extent = new_regions[i].limit;
1392 }
1393
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001394 /* check if the image is actually a Flash Descriptor region */
1395 if (size == new_regions[0].size) {
1396 printf("The image is a single Flash Descriptor:\n");
1397 printf(" Only the descriptor will be modified\n");
1398 new_extent = size;
1399 } else {
1400 new_extent = next_pow2(new_extent - 1);
1401 if (new_extent != size) {
1402 printf("The image has changed in size.\n");
1403 printf("The old image is %d bytes.\n", size);
1404 printf("The new image is %d bytes.\n", new_extent);
1405 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001406 }
1407
1408 /* copy regions to a new image */
1409 new_image = malloc(new_extent);
1410 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001411 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001412 int copy_size = new_regions[i].size;
1413 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001414 const region_t *current = &current_regions[i];
1415 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001416
Bill XIEfa5f9942017-09-12 11:22:29 +08001417 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001418 continue;
1419
Bill XIEfa5f9942017-09-12 11:22:29 +08001420 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001421 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001422 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001423 if (i == REGION_BIOS)
1424 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001425 }
1426
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001427 if ((i == REGION_BIOS) && (new->size < current->size)) {
1428 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001429 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001430 }
1431
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001432 if (size < current->base + offset_current + copy_size) {
1433 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1434 region_name(i));
1435 continue;
1436 };
1437
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001438 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1439 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001440 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1441 offset_current, current->limit, current->size);
1442 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1443 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001444
Bill XIEfa5f9942017-09-12 11:22:29 +08001445 memcpy(new_image + new->base + offset_new,
1446 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001447 copy_size);
1448 }
1449
1450 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001451 frba = find_frba(new_image, new_extent);
1452 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001453 exit(EXIT_FAILURE);
1454
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001455 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001456 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001457 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001458
1459 write_image(filename, new_image, new_extent);
1460 free(new_image);
1461}
1462
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001463static void print_version(void)
1464{
1465 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1466 printf("Copyright (C) 2011 Google Inc.\n\n");
1467 printf
1468 ("This program is free software: you can redistribute it and/or modify\n"
1469 "it under the terms of the GNU General Public License as published by\n"
1470 "the Free Software Foundation, version 2 of the License.\n\n"
1471 "This program is distributed in the hope that it will be useful,\n"
1472 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1473 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001474 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001475}
1476
1477static void print_usage(const char *name)
1478{
1479 printf("usage: %s [-vhdix?] <filename>\n", name);
1480 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001481 " -d | --dump: dump intel firmware descriptor\n"
1482 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1483 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1484 " -x | --extract: extract intel fd modules\n"
1485 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1486 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001487 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001488 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1489 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1490 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1491 " can only be used once per run:\n"
1492 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1493 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1494 " Dual Output Fast Read Support\n"
1495 " -l | --lock Lock firmware descriptor and ME region\n"
1496 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001497 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1498 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001499 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301500 " adl - Alder Lake\n"
1501 " aplk - Apollo Lake\n"
1502 " cnl - Cannon Lake\n"
1503 " glk - Gemini Lake\n"
1504 " icl - Ice Lake\n"
1505 " jsl - Jasper Lake\n"
1506 " sklkbl - Sky Lake/Kaby Lake\n"
1507 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001508 " -S | --setpchstrap Write a PCH strap\n"
1509 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001510 " -v | --version: print the version\n"
1511 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001512 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1513 "\n");
1514}
1515
1516int main(int argc, char *argv[])
1517{
1518 int opt, option_index = 0;
1519 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001520 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001521 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001522 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001523 char *region_type_string = NULL, *region_fname = NULL;
1524 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001525 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001526 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001527 unsigned int value = 0;
1528 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001529 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001530 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1531
Bill XIEfa5f9942017-09-12 11:22:29 +08001532 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001533 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001534 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001535 {"extract", 0, NULL, 'x'},
1536 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001537 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001538 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001539 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001540 {"density", 1, NULL, 'D'},
1541 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001542 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001543 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001544 {"lock", 0, NULL, 'l'},
1545 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001546 {"version", 0, NULL, 'v'},
1547 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001548 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001549 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001550 {"setpchstrap", 1, NULL, 'S'},
1551 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001552 {0, 0, 0, 0}
1553 };
1554
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001555 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 -07001556 long_options, &option_index)) != EOF) {
1557 switch (opt) {
1558 case 'd':
1559 mode_dump = 1;
1560 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001561 case 'S':
1562 mode_setstrap = 1;
1563 pchstrap = strtoul(optarg, NULL, 0);
1564 break;
1565 case 'V':
1566 value = strtoul(optarg, NULL, 0);
1567 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001568 case 'f':
1569 mode_layout = 1;
1570 layout_fname = strdup(optarg);
1571 if (!layout_fname) {
1572 fprintf(stderr, "No layout file specified\n");
1573 print_usage(argv[0]);
1574 exit(EXIT_FAILURE);
1575 }
1576 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001577 case 'x':
1578 mode_extract = 1;
1579 break;
1580 case 'i':
1581 // separate type and file name
1582 region_type_string = strdup(optarg);
1583 region_fname = strchr(region_type_string, ':');
1584 if (!region_fname) {
1585 print_usage(argv[0]);
1586 exit(EXIT_FAILURE);
1587 }
1588 region_fname[0] = '\0';
1589 region_fname++;
1590 // Descriptor, BIOS, ME, GbE, Platform
1591 // valid type?
1592 if (!strcasecmp("Descriptor", region_type_string))
1593 region_type = 0;
1594 else if (!strcasecmp("BIOS", region_type_string))
1595 region_type = 1;
1596 else if (!strcasecmp("ME", region_type_string))
1597 region_type = 2;
1598 else if (!strcasecmp("GbE", region_type_string))
1599 region_type = 3;
1600 else if (!strcasecmp("Platform", region_type_string))
1601 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001602 else if (!strcasecmp("EC", region_type_string))
1603 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001604 if (region_type == -1) {
1605 fprintf(stderr, "No such region type: '%s'\n\n",
1606 region_type_string);
1607 print_usage(argv[0]);
1608 exit(EXIT_FAILURE);
1609 }
1610 mode_inject = 1;
1611 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001612 case 'n':
1613 mode_newlayout = 1;
1614 layout_fname = strdup(optarg);
1615 if (!layout_fname) {
1616 fprintf(stderr, "No layout file specified\n");
1617 print_usage(argv[0]);
1618 exit(EXIT_FAILURE);
1619 }
1620 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001621 case 'O':
1622 new_filename = strdup(optarg);
1623 if (!new_filename) {
1624 fprintf(stderr, "No output filename specified\n");
1625 print_usage(argv[0]);
1626 exit(EXIT_FAILURE);
1627 }
1628 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001629 case 'D':
1630 mode_density = 1;
1631 new_density = strtoul(optarg, NULL, 0);
1632 switch (new_density) {
1633 case 512:
1634 new_density = COMPONENT_DENSITY_512KB;
1635 break;
1636 case 1:
1637 new_density = COMPONENT_DENSITY_1MB;
1638 break;
1639 case 2:
1640 new_density = COMPONENT_DENSITY_2MB;
1641 break;
1642 case 4:
1643 new_density = COMPONENT_DENSITY_4MB;
1644 break;
1645 case 8:
1646 new_density = COMPONENT_DENSITY_8MB;
1647 break;
1648 case 16:
1649 new_density = COMPONENT_DENSITY_16MB;
1650 break;
1651 case 32:
1652 new_density = COMPONENT_DENSITY_32MB;
1653 break;
1654 case 64:
1655 new_density = COMPONENT_DENSITY_64MB;
1656 break;
1657 case 0:
1658 new_density = COMPONENT_DENSITY_UNUSED;
1659 break;
1660 default:
1661 printf("error: Unknown density\n");
1662 print_usage(argv[0]);
1663 exit(EXIT_FAILURE);
1664 }
1665 break;
1666 case 'C':
1667 selected_chip = strtol(optarg, NULL, 0);
1668 if (selected_chip > 2) {
1669 fprintf(stderr, "error: Invalid chip selection\n");
1670 print_usage(argv[0]);
1671 exit(EXIT_FAILURE);
1672 }
1673 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001674 case 'M':
1675 mode_altmedisable = 1;
1676 altmedisable = strtol(optarg, NULL, 0);
1677 if (altmedisable > 1) {
1678 fprintf(stderr, "error: Illegal value\n");
1679 print_usage(argv[0]);
1680 exit(EXIT_FAILURE);
1681 }
1682 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001683 case 's':
1684 // Parse the requested SPI frequency
1685 inputfreq = strtol(optarg, NULL, 0);
1686 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001687 case 17:
1688 spifreq = SPI_FREQUENCY_17MHZ;
1689 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001690 case 20:
1691 spifreq = SPI_FREQUENCY_20MHZ;
1692 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001693 case 30:
1694 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1695 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001696 case 33:
1697 spifreq = SPI_FREQUENCY_33MHZ;
1698 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001699 case 48:
1700 spifreq = SPI_FREQUENCY_48MHZ;
1701 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001702 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001703 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001704 break;
1705 default:
1706 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1707 inputfreq);
1708 print_usage(argv[0]);
1709 exit(EXIT_FAILURE);
1710 }
1711 mode_spifreq = 1;
1712 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001713 case 'e':
1714 mode_em100 = 1;
1715 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001716 case 'l':
1717 mode_locked = 1;
1718 if (mode_unlocked == 1) {
1719 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1720 exit(EXIT_FAILURE);
1721 }
1722 break;
1723 case 'u':
1724 mode_unlocked = 1;
1725 if (mode_locked == 1) {
1726 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1727 exit(EXIT_FAILURE);
1728 }
1729 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001730 case 'p':
1731 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001732 platform = PLATFORM_APL;
1733 } else if (!strcmp(optarg, "cnl")) {
1734 platform = PLATFORM_CNL;
1735 } else if (!strcmp(optarg, "glk")) {
1736 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301737 } else if (!strcmp(optarg, "icl")) {
1738 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301739 } else if (!strcmp(optarg, "jsl")) {
1740 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001741 } else if (!strcmp(optarg, "sklkbl")) {
1742 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001743 } else if (!strcmp(optarg, "tgl")) {
1744 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301745 } else if (!strcmp(optarg, "adl")) {
1746 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001747 } else {
1748 fprintf(stderr, "Unknown platform: %s\n", optarg);
1749 exit(EXIT_FAILURE);
1750 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001751 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001752 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001753 case 't':
1754 mode_validate = 1;
1755 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001756 case 'v':
1757 print_version();
1758 exit(EXIT_SUCCESS);
1759 break;
1760 case 'h':
1761 case '?':
1762 default:
1763 print_usage(argv[0]);
1764 exit(EXIT_SUCCESS);
1765 break;
1766 }
1767 }
1768
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001769 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001770 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001771 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001772 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001773 print_usage(argv[0]);
1774 exit(EXIT_FAILURE);
1775 }
1776
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001777 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001778 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001779 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001780 fprintf(stderr, "You need to specify a mode.\n\n");
1781 print_usage(argv[0]);
1782 exit(EXIT_FAILURE);
1783 }
1784
1785 if (optind + 1 != argc) {
1786 fprintf(stderr, "You need to specify a file.\n\n");
1787 print_usage(argv[0]);
1788 exit(EXIT_FAILURE);
1789 }
1790
1791 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001792 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001793 if (bios_fd == -1) {
1794 perror("Could not open file");
1795 exit(EXIT_FAILURE);
1796 }
1797 struct stat buf;
1798 if (fstat(bios_fd, &buf) == -1) {
1799 perror("Could not stat file");
1800 exit(EXIT_FAILURE);
1801 }
1802 int size = buf.st_size;
1803
1804 printf("File %s is %d bytes\n", filename, size);
1805
1806 char *image = malloc(size);
1807 if (!image) {
1808 printf("Out of memory.\n");
1809 exit(EXIT_FAILURE);
1810 }
1811
1812 if (read(bios_fd, image, size) != size) {
1813 perror("Could not read file");
1814 exit(EXIT_FAILURE);
1815 }
1816
1817 close(bios_fd);
1818
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001819 // generate new filename
1820 if (new_filename == NULL) {
1821 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1822 if (!new_filename) {
1823 printf("Out of memory.\n");
1824 exit(EXIT_FAILURE);
1825 }
1826 // - 5: leave room for ".new\0"
1827 strcpy(new_filename, filename);
1828 strcat(new_filename, ".new");
1829 }
1830
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001831 check_ifd_version(image, size);
1832
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001833 if (mode_dump)
1834 dump_fd(image, size);
1835
Chris Douglass03ce0142014-02-26 13:30:13 -05001836 if (mode_layout)
1837 dump_layout(image, size, layout_fname);
1838
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001839 if (mode_extract)
1840 write_regions(image, size);
1841
Mathew Kingc7ddc992019-08-08 14:59:25 -06001842 if (mode_validate)
1843 validate_layout(image, size);
1844
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001845 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001846 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001847 region_fname);
1848
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001849 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001850 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001851
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001852 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001853 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001854
Jan Tatjefa317512016-03-11 00:52:07 +01001855 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001856 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001857
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001858 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001859 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001860
Alexander Couzensd12ea112016-09-10 13:33:05 +02001861 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001862 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001863
1864 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001865 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001866
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001867 if (mode_setstrap) {
1868 fpsba_t *fpsba = find_fpsba(image, size);
1869 const fdbar_t *fdb = find_fd(image, size);
1870 set_pchstrap(fpsba, fdb, pchstrap, value);
1871 write_image(new_filename, image, size);
1872 }
1873
Bill XIEb3e15a22017-09-07 18:34:50 +08001874 if (mode_altmedisable) {
1875 fpsba_t *fpsba = find_fpsba(image, size);
1876 fmsba_t *fmsba = find_fmsba(image, size);
1877 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001878 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001879 }
1880
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001881 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001882 free(image);
1883
1884 return 0;
1885}