blob: 98afa4bbcfda106761f2f501740c32bc68efca00 [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
Jeff Dalyabd4b962022-01-06 00:52:30 -050031/**
32 * PLATFORM_HAS_GBE_REGION - some platforms do not support the PCH GbE LAN region
33 */
34#define PLATFORM_HAS_GBE_REGION (platform != PLATFORM_DNV)
35
36/*
37 * PLATFORM_HAS_EC_REGION - some platforms do not support the EC region
38 */
39#define PLATFORM_HAS_EC_REGION (ifd_version >= IFD_VERSION_2 && platform != PLATFORM_DNV)
40
41/*
42 * PLATFORM_HAS_10GBE_X_REGION - some platforms have 1 or more 10GbE LAN regions
43 */
44#define PLATFORM_HAS_10GBE_0_REGION (platform == PLATFORM_DNV)
45#define PLATFORM_HAS_10GBE_1_REGION (platform == PLATFORM_DNV)
46
Patrick Rudolph98ecaa42022-10-24 15:06:15 +020047static int max_regions_from_fdbar(const fdbar_t *fdb);
48
Duncan Laurie1f7fd722015-06-22 11:14:48 -070049static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080050static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080051static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010052static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070053static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050054
Duncan Laurie1f7fd722015-06-22 11:14:48 -070055static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060056 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
57 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
58 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
59 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
60 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
Jeff Daly3623eca2022-01-05 23:51:40 -050061 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
62 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
63 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060064 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050065 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
66 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
67 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
68 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
69 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
70 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
71 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050072};
73
Bill XIEb3e15a22017-09-07 18:34:50 +080074/* port from flashrom */
75static const char *const ich_chipset_names[] = {
76 "Unknown ICH",
Bill XIEb3e15a22017-09-07 18:34:50 +080077 "ICH8",
78 "ICH9",
79 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053080 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080081 "5 series Ibex Peak",
82 "6 series Cougar Point",
83 "7 series Panther Point",
84 "8 series Lynx Point",
85 "Baytrail",
86 "8 series Lynx Point LP",
87 "8 series Wellsburg",
88 "9 series Wildcat Point",
89 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053090 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053091 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053092 "Jasper Lake: N6xxx, N51xx, N45xx",
93 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053094 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +053095 "300 series Cannon Point",
96 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +053097 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080098 "C620 series Lewisburg",
Patrick Rudolph19209002022-10-22 10:34:05 +020099 "Denverton: C39xx",
Bill XIEb3e15a22017-09-07 18:34:50 +0800100 NULL
101};
102
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700103static fdbar_t *find_fd(char *image, int size)
104{
105 int i, found = 0;
106
107 /* Scan for FD signature */
108 for (i = 0; i < (size - 4); i += 4) {
109 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
110 found = 1;
111 break; // signature found.
112 }
113 }
114
115 if (!found) {
116 printf("No Flash Descriptor found in this image\n");
117 return NULL;
118 }
119
Bill XIE612ec0e2017-08-30 16:10:27 +0800120 fdbar_t *fdb = (fdbar_t *) (image + i);
121 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
122}
123
Stefan Tauner0d226142018-08-05 18:56:53 +0200124static char *find_flumap(char *image, int size)
125{
126 /* The upper map is located in the word before the 256B-long OEM section
127 * at the end of the 4kB-long flash descriptor. In the official
128 * documentation this is defined as FDBAR + 0xEFC. However, starting
129 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
130 * has moved 16 bytes back to offset 0x10 of the image. Although
131 * official documentation still maintains the offset relative to FDBAR
132 * this is wrong and a simple fixed offset from the start of the image
133 * works.
134 */
135 char *flumap = image + 4096 - 256 - 4;
136 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
137}
138
Bill XIE612ec0e2017-08-30 16:10:27 +0800139static fcba_t *find_fcba(char *image, int size)
140{
141 fdbar_t *fdb = find_fd(image, size);
142 if (!fdb)
143 return NULL;
144 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
145 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
146
147}
148
149static fmba_t *find_fmba(char *image, int size)
150{
151 fdbar_t *fdb = find_fd(image, size);
152 if (!fdb)
153 return NULL;
154 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
155 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
156}
157
158static frba_t *find_frba(char *image, int size)
159{
160 fdbar_t *fdb = find_fd(image, size);
161 if (!fdb)
162 return NULL;
163 frba_t *frba =
164 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
165 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
166}
167
168static fpsba_t *find_fpsba(char *image, int size)
169{
170 fdbar_t *fdb = find_fd(image, size);
171 if (!fdb)
172 return NULL;
173 fpsba_t *fpsba =
174 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200175
176 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
177 if ((((char *)fpsba) + SSL) >= (image + size))
178 return NULL;
179 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800180}
181
182static fmsba_t *find_fmsba(char *image, int size)
183{
184 fdbar_t *fdb = find_fd(image, size);
185 if (!fdb)
186 return NULL;
187 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
188 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700189}
190
Bill XIEb3e15a22017-09-07 18:34:50 +0800191/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530192static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800193{
Subrata Banik8c082e52021-06-10 23:02:29 +0530194 const fdbar_t *fdb = find_fd(image, size);
195 if (!fdb)
196 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800197 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
198 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
199 uint32_t isl = (fdb->flmap1 >> 24);
Subrata Banik89db2252020-08-26 14:49:17 +0530200
201 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800202 if (iccriba == 0x00) {
203 if (msl == 0 && isl <= 2)
204 return CHIPSET_ICH8;
205 else if (isl <= 2)
206 return CHIPSET_ICH9;
207 else if (isl <= 10)
208 return CHIPSET_ICH10;
209 else if (isl <= 16)
210 return CHIPSET_5_SERIES_IBEX_PEAK;
211 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
212 return CHIPSET_5_SERIES_IBEX_PEAK;
213 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
214 if (msl == 0 && isl <= 17)
215 return CHIPSET_BAYTRAIL;
216 else if (msl <= 1 && isl <= 18)
217 return CHIPSET_6_SERIES_COUGAR_POINT;
218 else if (msl <= 1 && isl <= 21)
219 return CHIPSET_8_SERIES_LYNX_POINT;
220 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
221 return CHIPSET_9_SERIES_WILDCAT_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800222 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200223 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800224}
225
Subrata Banik8c082e52021-06-10 23:02:29 +0530226static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
227{
228 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530229 case PLATFORM_APL:
230 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530231 case PLATFORM_GLK:
232 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
233 case PLATFORM_JSL:
234 return CHIPSET_N_SERIES_JASPER_LAKE;
235 case PLATFORM_EHL:
236 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200237 case PLATFORM_SKLKBL:
238 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530239 case PLATFORM_CNL:
240 return CHIPSET_300_SERIES_CANNON_POINT;
241 case PLATFORM_TGL:
242 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800243 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +0530244 case PLATFORM_MTL:
Subrata Banik8c082e52021-06-10 23:02:29 +0530245 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
246 case PLATFORM_ICL:
247 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800248 case PLATFORM_LBG:
249 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500250 case PLATFORM_DNV:
251 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200252 case PLATFORM_WBG:
253 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530254 default:
255 return CHIPSET_PCH_UNKNOWN;
256 }
257}
258
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700259/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700260 * Some newer platforms have re-defined the FCBA field that was used to
261 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
262 * have the required FCBA field, but are IFD v2 and return true if current
263 * platform is one of them.
264 */
265static int is_platform_ifd_2(void)
266{
267 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530268 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700269 PLATFORM_GLK,
270 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800271 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500272 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530273 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700274 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530275 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700276 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530277 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200278 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800279 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530280 PLATFORM_MTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200281 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700282 };
283 unsigned int i;
284
285 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
286 if (platform == ifd_2_platforms[i])
287 return 1;
288 }
289
290 return 0;
291}
292
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700293static void check_ifd_version(char *image, int size)
294{
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200295 const fdbar_t *fdb = find_fd(image, size);
296
Subrata Banik8c082e52021-06-10 23:02:29 +0530297 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530298 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200299 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
300 ifd_version = IFD_VERSION_1_5;
301 else
302 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200303 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530304 } else {
305 ifd_version = IFD_VERSION_1;
306 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200307 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530308 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700309}
310
Bill XIEfa5f9942017-09-12 11:22:29 +0800311static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700312{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500313 int base_mask;
314 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700315 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500317
318 if (ifd_version >= IFD_VERSION_2)
319 base_mask = 0x7fff;
320 else
321 base_mask = 0xfff;
322
323 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700324
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400325 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800326 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700327 exit (EXIT_FAILURE);
328 }
329
Bill XIE4651d452017-09-12 11:54:48 +0800330 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700331 region.base = (flreg & base_mask) << 12;
332 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500334
Chris Douglass03ce0142014-02-26 13:30:13 -0500335 if (region.size < 0)
336 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700337
338 return region;
339}
340
Bill XIEfa5f9942017-09-12 11:22:29 +0800341static void set_region(frba_t *frba, unsigned int region_type,
342 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500343{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400344 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800345 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500346 exit (EXIT_FAILURE);
347 }
Bill XIE4651d452017-09-12 11:54:48 +0800348
349 frba->flreg[region_type] =
350 (((region->limit >> 12) & 0x7fff) << 16) |
351 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500352}
353
Bill XIEfa5f9942017-09-12 11:22:29 +0800354static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355{
Bill XIEfa5f9942017-09-12 11:22:29 +0800356 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700357 fprintf(stderr, "Invalid region type.\n");
358 exit (EXIT_FAILURE);
359 }
360
Chris Douglass03ce0142014-02-26 13:30:13 -0500361 return region_names[region_type].pretty;
362}
363
Patrick Rudolphef5ebdb2022-10-22 11:19:02 +0200364static const char *region_name_fmap(unsigned int region_type)
365{
366 if (region_type >= max_regions) {
367 fprintf(stderr, "Invalid region type.\n");
368 exit(EXIT_FAILURE);
369 }
370
371 return region_names[region_type].fmapname;
372}
373
Bill XIEfa5f9942017-09-12 11:22:29 +0800374static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500375{
Bill XIEfa5f9942017-09-12 11:22:29 +0800376 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500377 fprintf(stderr, "Invalid region type.\n");
378 exit (EXIT_FAILURE);
379 }
380
381 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700382}
383
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500384static int region_num(const char *name)
385{
Bill XIEfa5f9942017-09-12 11:22:29 +0800386 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500387
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200388 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500389 if (strcasecmp(name, region_names[i].pretty) == 0)
390 return i;
391 if (strcasecmp(name, region_names[i].terse) == 0)
392 return i;
393 }
394
395 return -1;
396}
397
Bill XIEfa5f9942017-09-12 11:22:29 +0800398static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700399{
Bill XIEfa5f9942017-09-12 11:22:29 +0800400 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700401 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700402 exit (EXIT_FAILURE);
403 }
404
Bill XIE1bf65062017-09-12 11:31:37 +0800405 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700406}
407
Bill XIEfa5f9942017-09-12 11:22:29 +0800408static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700409{
410 region_t region = get_region(frba, num);
411 printf(" Flash Region %d (%s): %08x - %08x %s\n",
412 num, region_name(num), region.base, region.limit,
413 region.size < 1 ? "(unused)" : "");
414}
415
Bill XIEfa5f9942017-09-12 11:22:29 +0800416static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
417 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500418{
419 region_t region = get_region(frba, num);
420 snprintf(buf, bufsize, "%08x:%08x %s\n",
421 region.base, region.limit, region_name_short(num));
422}
423
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200424static int sort_compare(const void *a, const void *b)
425{
426 return *(size_t *)a - *(size_t *)b;
427}
428
429/*
430 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
431 *
432 * It's platform specific which regions are used or are reserved.
433 * The 'SPI programming guide' as the name says is a guide only,
434 * not a specification what the hardware actually does.
435 * The best to do is not to rely on the guide, but detect how many
436 * regions are present in the IFD and expose them all.
437 *
438 * Very early IFDv2 chipsets, sometimes unofficially referred to as
439 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
440 * operating on an IFDv1.5 detect how much space is actually present
441 * in the IFD.
442 */
443static int max_regions_from_fdbar(const fdbar_t *fdb)
444{
445 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
446 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
447 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
448 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
449 const size_t flumap = 4096 - 256 - 4;
450 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
451
452 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
453
454 for (size_t i = 0; i < 4; i++) {
455 /*
456 * Find FRBA in the sorted array and determine the size of the
457 * region by the start of the next region. Every region requires
458 * 4 bytes of space.
459 */
460 if (sorted[i] == frba)
461 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
462 }
463 /* Never reaches this point */
464 return 0;
465}
466
Bill XIEfa5f9942017-09-12 11:22:29 +0800467static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700468{
Bill XIE4651d452017-09-12 11:54:48 +0800469 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530470 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700471 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800472 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530473 region = get_region(frba, i);
474 /* Skip unused & reserved Flash Region */
475 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
476 continue;
477
Bill XIE4651d452017-09-12 11:54:48 +0800478 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
479 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700480 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700481}
482
Bill XIEfa5f9942017-09-12 11:22:29 +0800483static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500484{
485 char buf[LAYOUT_LINELEN];
486 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800487 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500488
489 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
490 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
491 if (layout_fd == -1) {
492 perror("Could not open file");
493 exit(EXIT_FAILURE);
494 }
495
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200496 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200497 region_t region = get_region(frba, i);
498 /* is region invalid? */
499 if (region.size < 1)
500 continue;
501
Chris Douglass03ce0142014-02-26 13:30:13 -0500502 dump_region_layout(buf, bufsize, i, frba);
503 if (write(layout_fd, buf, strlen(buf)) < 0) {
504 perror("Could not write to file");
505 exit(EXIT_FAILURE);
506 }
507 }
508 close(layout_fd);
509 printf("Wrote layout to %s\n", layout_fname);
510}
511
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530512static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700513{
514 switch (freq) {
515 case SPI_FREQUENCY_20MHZ:
516 printf("20MHz");
517 break;
518 case SPI_FREQUENCY_33MHZ:
519 printf("33MHz");
520 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700521 case SPI_FREQUENCY_48MHZ:
522 printf("48MHz");
523 break;
524 case SPI_FREQUENCY_50MHZ_30MHZ:
525 switch (ifd_version) {
526 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200527 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700528 printf("50MHz");
529 break;
530 case IFD_VERSION_2:
531 printf("30MHz");
532 break;
533 }
534 break;
535 case SPI_FREQUENCY_17MHZ:
536 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700537 break;
538 default:
539 printf("unknown<%x>MHz", freq);
540 }
541}
542
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530543static void _decode_spi_frequency_500_series(unsigned int freq)
544{
545 switch (freq) {
546 case SPI_FREQUENCY_100MHZ:
547 printf("100MHz");
548 break;
549 case SPI_FREQUENCY_50MHZ:
550 printf("50MHz");
551 break;
552 case SPI_FREQUENCY_500SERIES_33MHZ:
553 printf("33MHz");
554 break;
555 case SPI_FREQUENCY_25MHZ:
556 printf("25MHz");
557 break;
558 case SPI_FREQUENCY_14MHZ:
559 printf("14MHz");
560 break;
561 default:
562 printf("unknown<%x>MHz", freq);
563 }
564}
565
566static void decode_spi_frequency(unsigned int freq)
567{
Subrata Banika5f47812020-09-29 11:43:01 +0530568 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530569 _decode_spi_frequency_500_series(freq);
570 else
571 _decode_spi_frequency(freq);
572}
573
Subrata Banike5d39922020-08-26 16:01:42 +0530574static void _decode_espi_frequency(unsigned int freq)
575{
576 switch (freq) {
577 case ESPI_FREQUENCY_20MHZ:
578 printf("20MHz");
579 break;
580 case ESPI_FREQUENCY_24MHZ:
581 printf("24MHz");
582 break;
583 case ESPI_FREQUENCY_30MHZ:
584 printf("30MHz");
585 break;
586 case ESPI_FREQUENCY_48MHZ:
587 printf("48MHz");
588 break;
589 case ESPI_FREQUENCY_60MHZ:
590 printf("60MHz");
591 break;
592 case ESPI_FREQUENCY_17MHZ:
593 printf("17MHz");
594 break;
595 default:
596 printf("unknown<%x>MHz", freq);
597 }
598}
599
600static void _decode_espi_frequency_500_series(unsigned int freq)
601{
602 switch (freq) {
603 case ESPI_FREQUENCY_500SERIES_20MHZ:
604 printf("20MHz");
605 break;
606 case ESPI_FREQUENCY_500SERIES_24MHZ:
607 printf("24MHz");
608 break;
609 case ESPI_FREQUENCY_500SERIES_25MHZ:
610 printf("25MHz");
611 break;
612 case ESPI_FREQUENCY_500SERIES_48MHZ:
613 printf("48MHz");
614 break;
615 case ESPI_FREQUENCY_500SERIES_60MHZ:
616 printf("60MHz");
617 break;
618 default:
619 printf("unknown<%x>MHz", freq);
620 }
621}
622
623static void decode_espi_frequency(unsigned int freq)
624{
Subrata Banika5f47812020-09-29 11:43:01 +0530625 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530626 _decode_espi_frequency_500_series(freq);
627 else
628 _decode_espi_frequency(freq);
629}
630
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700631static void decode_component_density(unsigned int density)
632{
633 switch (density) {
634 case COMPONENT_DENSITY_512KB:
635 printf("512KB");
636 break;
637 case COMPONENT_DENSITY_1MB:
638 printf("1MB");
639 break;
640 case COMPONENT_DENSITY_2MB:
641 printf("2MB");
642 break;
643 case COMPONENT_DENSITY_4MB:
644 printf("4MB");
645 break;
646 case COMPONENT_DENSITY_8MB:
647 printf("8MB");
648 break;
649 case COMPONENT_DENSITY_16MB:
650 printf("16MB");
651 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700652 case COMPONENT_DENSITY_32MB:
653 printf("32MB");
654 break;
655 case COMPONENT_DENSITY_64MB:
656 printf("64MB");
657 break;
658 case COMPONENT_DENSITY_UNUSED:
659 printf("UNUSED");
660 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700661 default:
662 printf("unknown<%x>MB", density);
663 }
664}
665
Subrata Banik26058dc2020-08-26 15:12:16 +0530666static int is_platform_with_pch(void)
667{
668 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
669 return 1;
670
671 return 0;
672}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530673
674/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
675static int is_platform_with_100x_series_pch(void)
676{
677 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530678 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530679 return 1;
680
681 return 0;
682}
683
Subrata Banike5d39922020-08-26 16:01:42 +0530684static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700685{
Subrata Banike5d39922020-08-26 16:01:42 +0530686 unsigned int freq;
687
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700688 printf("\nFound Component Section\n");
689 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700690 printf(" Dual Output Fast Read Support: %ssupported\n",
691 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700692 printf(" Read ID/Read Status Clock Frequency: ");
693 decode_spi_frequency((fcba->flcomp >> 27) & 7);
694 printf("\n Write/Erase Clock Frequency: ");
695 decode_spi_frequency((fcba->flcomp >> 24) & 7);
696 printf("\n Fast Read Clock Frequency: ");
697 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700698 printf("\n Fast Read Support: %ssupported",
699 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530700 if (is_platform_with_100x_series_pch() &&
701 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
702 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530703 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530704 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
705 else
706 freq = (fcba->flcomp >> 17) & 7;
707 decode_espi_frequency(freq);
708 } else {
709 printf("\n Read Clock Frequency: ");
710 decode_spi_frequency((fcba->flcomp >> 17) & 7);
711 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700712
713 switch (ifd_version) {
714 case IFD_VERSION_1:
715 printf("\n Component 2 Density: ");
716 decode_component_density((fcba->flcomp >> 3) & 7);
717 printf("\n Component 1 Density: ");
718 decode_component_density(fcba->flcomp & 7);
719 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200720 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700721 case IFD_VERSION_2:
722 printf("\n Component 2 Density: ");
723 decode_component_density((fcba->flcomp >> 4) & 0xf);
724 printf("\n Component 1 Density: ");
725 decode_component_density(fcba->flcomp & 0xf);
726 break;
727 }
728
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700729 printf("\n");
730 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700731 printf(" Invalid Instruction 3: 0x%02x\n",
732 (fcba->flill >> 24) & 0xff);
733 printf(" Invalid Instruction 2: 0x%02x\n",
734 (fcba->flill >> 16) & 0xff);
735 printf(" Invalid Instruction 1: 0x%02x\n",
736 (fcba->flill >> 8) & 0xff);
737 printf(" Invalid Instruction 0: 0x%02x\n",
738 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530739 if (is_platform_with_100x_series_pch()) {
740 printf("FLILL1 0x%08x\n", fcba->flpb);
741 printf(" Invalid Instruction 7: 0x%02x\n",
742 (fcba->flpb >> 24) & 0xff);
743 printf(" Invalid Instruction 6: 0x%02x\n",
744 (fcba->flpb >> 16) & 0xff);
745 printf(" Invalid Instruction 5: 0x%02x\n",
746 (fcba->flpb >> 8) & 0xff);
747 printf(" Invalid Instruction 4: 0x%02x\n",
748 fcba->flpb & 0xff);
749 } else {
750 printf("FLPB 0x%08x\n", fcba->flpb);
751 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
752 (fcba->flpb & 0xfff) << 12);
753 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700754}
755
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200756static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700757{
Bill XIE4651d452017-09-12 11:54:48 +0800758 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200759 /* SoC Straps, aka PSL, aka ISL */
760 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200761
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700762 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200763 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200764 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800765
766 if (ifd_version >= IFD_VERSION_2) {
767 printf("HAP bit is %sset\n",
768 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
769 } else if (chipset >= CHIPSET_ICH8
770 && chipset <= CHIPSET_ICH10) {
771 printf("ICH_MeDisable bit is %sset\n",
772 fpsba->pchstrp[0] & 1 ? "" : "not ");
773 } else {
774 printf("AltMeDisable bit is %sset\n",
775 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
776 }
777
Bill XIE4651d452017-09-12 11:54:48 +0800778 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700779}
780
781static void decode_flmstr(uint32_t flmstr)
782{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700783 int wr_shift, rd_shift;
784 if (ifd_version >= IFD_VERSION_2) {
785 wr_shift = FLMSTR_WR_SHIFT_V2;
786 rd_shift = FLMSTR_RD_SHIFT_V2;
787 } else {
788 wr_shift = FLMSTR_WR_SHIFT_V1;
789 rd_shift = FLMSTR_RD_SHIFT_V1;
790 }
791
792 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500793 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700794 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700795 (flmstr & (1 << (wr_shift + 8))) ?
796 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700797 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700798 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500799 if (PLATFORM_HAS_GBE_REGION) {
800 printf(" GbE Region Write Access: %s\n",
801 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
802 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700803 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700804 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700805 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700806 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700807 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700808 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500809 if (PLATFORM_HAS_10GBE_0_REGION) {
810 printf(" 10GbE_0 Write Access: %s\n",
811 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
812 }
813 if (PLATFORM_HAS_10GBE_1_REGION) {
814 printf(" 10GbE_1 Write Access: %s\n",
815 (flmstr & (1 << 4)) ? "enabled" : "disabled");
816 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700817
Jeff Dalyabd4b962022-01-06 00:52:30 -0500818 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700819 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700820 (flmstr & (1 << (rd_shift + 8))) ?
821 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700822 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700823 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500824 if (PLATFORM_HAS_GBE_REGION) {
825 printf(" GbE Region Read Access: %s\n",
826 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
827 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700828 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700829 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700830 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700831 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700832 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700833 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500834 if (PLATFORM_HAS_10GBE_0_REGION) {
835 printf(" 10GbE_0 Read Access: %s\n",
836 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
837 }
838 if (PLATFORM_HAS_10GBE_1_REGION) {
839 printf(" 10GbE_1 Read Access: %s\n",
840 (flmstr & (1 << 0)) ? "enabled" : "disabled");
841 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700842
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700843 /* Requestor ID doesn't exist for ifd 2 */
844 if (ifd_version < IFD_VERSION_2)
845 printf(" Requester ID: 0x%04x\n\n",
846 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700847}
848
Bill XIEfa5f9942017-09-12 11:22:29 +0800849static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700850{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700851 printf("Found Master Section\n");
852 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
853 decode_flmstr(fmba->flmstr1);
854 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
855 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500856 if (PLATFORM_HAS_GBE_REGION) {
857 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
858 decode_flmstr(fmba->flmstr3);
859 if (ifd_version >= IFD_VERSION_2) {
860 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
861 decode_flmstr(fmba->flmstr5);
862 }
863 } else {
864 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
865 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700866 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700867}
868
Bill XIEfa5f9942017-09-12 11:22:29 +0800869static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700870{
Bill XIE612ec0e2017-08-30 16:10:27 +0800871 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700872 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800873 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
874 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800875
876 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
877 printf("MCH_MeDisable bit is %sset\n",
878 fmsba->data[0] & 1 ? "" : "not ");
879 printf("MCH_AltMeDisable bit is %sset\n",
880 fmsba->data[0] & (1 << 7) ? "" : "not ");
881 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700882}
883
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700884static void dump_jid(uint32_t jid)
885{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100886 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700887 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100888 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200889 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100890 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200891 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700892}
893
894static void dump_vscc(uint32_t vscc)
895{
896 printf(" Lower Erase Opcode: 0x%02x\n",
897 vscc >> 24);
898 printf(" Lower Write Enable on Write Status: 0x%02x\n",
899 vscc & (1 << 20) ? 0x06 : 0x50);
900 printf(" Lower Write Status Required: %s\n",
901 vscc & (1 << 19) ? "Yes" : "No");
902 printf(" Lower Write Granularity: %d bytes\n",
903 vscc & (1 << 18) ? 64 : 1);
904 printf(" Lower Block / Sector Erase Size: ");
905 switch ((vscc >> 16) & 0x3) {
906 case 0:
907 printf("256 Byte\n");
908 break;
909 case 1:
910 printf("4KB\n");
911 break;
912 case 2:
913 printf("8KB\n");
914 break;
915 case 3:
916 printf("64KB\n");
917 break;
918 }
919
920 printf(" Upper Erase Opcode: 0x%02x\n",
921 (vscc >> 8) & 0xff);
922 printf(" Upper Write Enable on Write Status: 0x%02x\n",
923 vscc & (1 << 4) ? 0x06 : 0x50);
924 printf(" Upper Write Status Required: %s\n",
925 vscc & (1 << 3) ? "Yes" : "No");
926 printf(" Upper Write Granularity: %d bytes\n",
927 vscc & (1 << 2) ? 64 : 1);
928 printf(" Upper Block / Sector Erase Size: ");
929 switch (vscc & 0x3) {
930 case 0:
931 printf("256 Byte\n");
932 break;
933 case 1:
934 printf("4KB\n");
935 break;
936 case 2:
937 printf("8KB\n");
938 break;
939 case 3:
940 printf("64KB\n");
941 break;
942 }
943}
944
Bill XIEfa5f9942017-09-12 11:22:29 +0800945static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700946{
947 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200948 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
949 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700950
951 printf("ME VSCC table:\n");
952 for (i = 0; i < num; i++) {
953 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
954 dump_jid(vtba->entry[i].jid);
955 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
956 dump_vscc(vtba->entry[i].vscc);
957 }
958 printf("\n");
959}
960
Bill XIEfa5f9942017-09-12 11:22:29 +0800961static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700962{
963 int i, j;
964 printf("OEM Section:\n");
965 for (i = 0; i < 4; i++) {
966 printf("%02x:", i << 4);
967 for (j = 0; j < 16; j++)
968 printf(" %02x", oem[(i<<4)+j]);
969 printf ("\n");
970 }
971 printf ("\n");
972}
973
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700974static void dump_fd(char *image, int size)
975{
Bill XIE612ec0e2017-08-30 16:10:27 +0800976 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700977 if (!fdb)
978 exit(EXIT_FAILURE);
979
Subrata Banik26058dc2020-08-26 15:12:16 +0530980 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
981 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700982 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530983 if (!is_platform_with_100x_series_pch())
984 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700985 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
986 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
987 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
988
989 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530990 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
991 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700992 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
993 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
994 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
995
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530996 if (!is_platform_with_100x_series_pch()) {
997 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
998 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
999 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
1000 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001001
Subrata Banika5f47812020-09-29 11:43:01 +05301002 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +05301003 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
1004 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
1005 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
1006 }
1007
Stefan Tauner0d226142018-08-05 18:56:53 +02001008 char *flumap = find_flumap(image, size);
1009 uint32_t flumap1 = *(uint32_t *)flumap;
1010 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001011 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001012 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001013 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001014 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001015 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +02001016 (image + ((flumap1 & 0xff) << 4)),
1017 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +08001018 dump_oem((const uint8_t *)image + 0xf00);
1019
1020 const frba_t *frba = find_frba(image, size);
1021 const fcba_t *fcba = find_fcba(image, size);
1022 const fpsba_t *fpsba = find_fpsba(image, size);
1023 const fmba_t *fmba = find_fmba(image, size);
1024 const fmsba_t *fmsba = find_fmsba(image, size);
1025
1026 if (frba && fcba && fpsba && fmba && fmsba) {
1027 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +05301028 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001029 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +08001030 dump_fmba(fmba);
1031 dump_fmsba(fmsba);
1032 } else {
1033 printf("FD is corrupted!\n");
1034 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001035}
1036
Bill XIEfa5f9942017-09-12 11:22:29 +08001037static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -05001038{
Bill XIE612ec0e2017-08-30 16:10:27 +08001039 const frba_t *frba = find_frba(image, size);
1040 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -05001041 exit(EXIT_FAILURE);
1042
Bill XIE612ec0e2017-08-30 16:10:27 +08001043 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05001044}
1045
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001046static void write_regions(char *image, int size)
1047{
Bill XIEfa5f9942017-09-12 11:22:29 +08001048 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +08001049 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001050
Bill XIE612ec0e2017-08-30 16:10:27 +08001051 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001052 exit(EXIT_FAILURE);
1053
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001054 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001055 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001056 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001057 if (region.size > 0) {
1058 int region_fd;
1059 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -06001060 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001061 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001062 if (region_fd < 0) {
1063 perror("Error while trying to open file");
1064 exit(EXIT_FAILURE);
1065 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001066 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001067 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001068 close(region_fd);
1069 }
1070 }
1071}
1072
Mathew Kingc7ddc992019-08-08 14:59:25 -06001073static void validate_layout(char *image, int size)
1074{
1075 uint i, errors = 0;
1076 struct fmap *fmap;
1077 long int fmap_loc = fmap_find((uint8_t *)image, size);
1078 const frba_t *frba = find_frba(image, size);
1079
1080 if (fmap_loc < 0 || !frba)
1081 exit(EXIT_FAILURE);
1082
1083 fmap = (struct fmap *)(image + fmap_loc);
1084
1085 for (i = 0; i < max_regions; i++) {
Patrick Rudolphef5ebdb2022-10-22 11:19:02 +02001086 if (region_name_fmap(i) == NULL)
Mathew Kingc7ddc992019-08-08 14:59:25 -06001087 continue;
1088
1089 region_t region = get_region(frba, i);
1090
1091 if (region.size == 0)
1092 continue;
1093
1094 const struct fmap_area *area =
Patrick Rudolphef5ebdb2022-10-22 11:19:02 +02001095 fmap_find_area(fmap, region_name_fmap(i));
Mathew Kingc7ddc992019-08-08 14:59:25 -06001096
1097 if (!area)
1098 continue;
1099
1100 if ((uint)region.base != area->offset ||
1101 (uint)region.size != area->size) {
1102 printf("Region mismatch between %s and %s\n",
1103 region_names[i].terse, area->name);
1104 printf(" Descriptor region %s:\n", region_names[i].terse);
1105 printf(" offset: 0x%08x\n", region.base);
1106 printf(" length: 0x%08x\n", region.size);
1107 printf(" FMAP area %s:\n", area->name);
1108 printf(" offset: 0x%08x\n", area->offset);
1109 printf(" length: 0x%08x\n", area->size);
1110 errors++;
1111 }
1112 }
1113
1114 if (errors > 0)
1115 exit(EXIT_FAILURE);
1116}
1117
Bill XIEfa5f9942017-09-12 11:22:29 +08001118static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001119{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001120 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001121 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001122
1123 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001124 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001125 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001126 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001127 if (new_fd < 0) {
1128 perror("Error while trying to open file");
1129 exit(EXIT_FAILURE);
1130 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001131 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001132 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001133 close(new_fd);
1134}
1135
Bill XIEfa5f9942017-09-12 11:22:29 +08001136static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001137 enum spi_frequency freq)
1138{
Bill XIE612ec0e2017-08-30 16:10:27 +08001139 fcba_t *fcba = find_fcba(image, size);
1140 if (!fcba)
1141 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001142
1143 /* clear bits 21-29 */
1144 fcba->flcomp &= ~0x3fe00000;
1145 /* Read ID and Read Status Clock Frequency */
1146 fcba->flcomp |= freq << 27;
1147 /* Write and Erase Clock Frequency */
1148 fcba->flcomp |= freq << 24;
1149 /* Fast Read Clock Frequency */
1150 fcba->flcomp |= freq << 21;
1151
1152 write_image(filename, image, size);
1153}
1154
Bill XIEfa5f9942017-09-12 11:22:29 +08001155static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001156{
Bill XIE612ec0e2017-08-30 16:10:27 +08001157 fcba_t *fcba = find_fcba(image, size);
1158 if (!fcba)
1159 exit(EXIT_FAILURE);
1160
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001161 int freq;
1162
1163 switch (ifd_version) {
1164 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001165 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001166 freq = SPI_FREQUENCY_20MHZ;
1167 break;
1168 case IFD_VERSION_2:
1169 freq = SPI_FREQUENCY_17MHZ;
1170 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001171 default:
1172 freq = SPI_FREQUENCY_17MHZ;
1173 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001174 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001175
1176 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001177 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001178}
1179
Bill XIEfa5f9942017-09-12 11:22:29 +08001180static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001181 unsigned int density)
1182{
Bill XIE612ec0e2017-08-30 16:10:27 +08001183 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001184 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001185 if (!fcba)
1186 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001187
1188 printf("Setting chip density to ");
1189 decode_component_density(density);
1190 printf("\n");
1191
1192 switch (ifd_version) {
1193 case IFD_VERSION_1:
1194 /* fail if selected density is not supported by this version */
1195 if ( (density == COMPONENT_DENSITY_32MB) ||
1196 (density == COMPONENT_DENSITY_64MB) ||
1197 (density == COMPONENT_DENSITY_UNUSED) ) {
1198 printf("error: Selected density not supported in IFD version 1.\n");
1199 exit(EXIT_FAILURE);
1200 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001201 mask = 0x7;
1202 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001203 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001204 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001205 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001206 mask = 0xf;
1207 chip2_offset = 4;
1208 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001209 default:
1210 printf("error: Unknown IFD version\n");
1211 exit(EXIT_FAILURE);
1212 break;
1213 }
1214
1215 /* clear chip density for corresponding chip */
1216 switch (selected_chip) {
1217 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001218 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001219 break;
1220 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001221 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001222 break;
1223 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001224 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001225 break;
1226 }
1227
1228 /* set the new density */
1229 if (selected_chip == 1 || selected_chip == 0)
1230 fcba->flcomp |= (density); /* first chip */
1231 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001232 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001233
1234 write_image(filename, image, size);
1235}
1236
Duncan Laurie7775d672019-06-06 13:39:26 -07001237static int check_region(const frba_t *frba, unsigned int region_type)
1238{
1239 region_t region;
1240
1241 if (!frba)
1242 return 0;
1243
1244 region = get_region(frba, region_type);
1245 return !!((region.base < region.limit) && (region.size > 0));
1246}
1247
Bill XIEfa5f9942017-09-12 11:22:29 +08001248static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001249{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001250 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001251 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001252 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001253 if (!fmba)
1254 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001255
1256 if (ifd_version >= IFD_VERSION_2) {
1257 wr_shift = FLMSTR_WR_SHIFT_V2;
1258 rd_shift = FLMSTR_RD_SHIFT_V2;
1259
1260 /* Clear non-reserved bits */
1261 fmba->flmstr1 &= 0xff;
1262 fmba->flmstr2 &= 0xff;
1263 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001264 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001265 } else {
1266 wr_shift = FLMSTR_WR_SHIFT_V1;
1267 rd_shift = FLMSTR_RD_SHIFT_V1;
1268
1269 fmba->flmstr1 = 0;
1270 fmba->flmstr2 = 0;
1271 /* Requestor ID */
1272 fmba->flmstr3 = 0x118;
1273 }
1274
Andrey Petrov96ecb772016-10-31 19:31:54 -07001275 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001276 case PLATFORM_APL:
1277 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001278 /* CPU/BIOS can read descriptor and BIOS */
1279 fmba->flmstr1 |= 0x3 << rd_shift;
1280 /* CPU/BIOS can write BIOS */
1281 fmba->flmstr1 |= 0x2 << wr_shift;
1282 /* TXE can read descriptor, BIOS and Device Expansion */
1283 fmba->flmstr2 |= 0x23 << rd_shift;
1284 /* TXE can only write Device Expansion */
1285 fmba->flmstr2 |= 0x20 << wr_shift;
1286 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001287 case PLATFORM_CNL:
1288 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001289 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001290 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301291 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001292 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301293 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001294 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301295 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001296 /* CPU/BIOS can read descriptor and BIOS. */
1297 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1298 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1299 /* CPU/BIOS can write BIOS. */
1300 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1301 /* ME can read descriptor and ME. */
1302 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1303 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001304 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001305 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1306 if (check_region(frba, REGION_GBE)) {
1307 /* BIOS can read/write GbE. */
1308 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1309 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1310 /* ME can read GbE. */
1311 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1312 /* GbE can read descriptor and read/write GbE.. */
1313 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1314 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1315 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1316 }
1317 if (check_region(frba, REGION_PDR)) {
1318 /* BIOS can read/write PDR. */
1319 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1320 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1321 }
1322 if (check_region(frba, REGION_EC)) {
1323 /* BIOS can read EC. */
1324 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1325 /* EC can read descriptor and read/write EC. */
1326 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1327 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1328 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1329 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001330 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001331 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001332 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001333 /* CPU/BIOS can read descriptor and BIOS. */
1334 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1335 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1336 /* CPU/BIOS can write BIOS. */
1337 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1338 /* ME can read descriptor and ME. */
1339 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1340 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1341 /* ME can write ME. */
1342 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1343 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001344 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001345 /* CPU/BIOS can read descriptor and BIOS. */
1346 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1347 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1348 /* CPU/BIOS can write BIOS. */
1349 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1350 /* ME can read descriptor and ME. */
1351 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1352 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1353 /* ME can write ME. */
1354 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1355 if (check_region(frba, REGION_GBE)) {
1356 /* BIOS can read GbE. */
1357 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1358 /* BIOS can write GbE. */
1359 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1360 /* ME can read GbE. */
1361 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1362 /* ME can write GbE. */
1363 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1364 /* GbE can write GbE. */
1365 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1366 /* GbE can read GbE. */
1367 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1368 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001369 break;
1370 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001371
1372 write_image(filename, image, size);
1373}
1374
Usha P412679d2020-10-15 11:25:08 +05301375static void enable_cpu_read_me(const char *filename, char *image, int size)
1376{
1377 int rd_shift;
1378 fmba_t *fmba = find_fmba(image, size);
1379
1380 if (!fmba)
1381 exit(EXIT_FAILURE);
1382
1383 if (ifd_version >= IFD_VERSION_2)
1384 rd_shift = FLMSTR_RD_SHIFT_V2;
1385 else
1386 rd_shift = FLMSTR_RD_SHIFT_V1;
1387
1388 /* CPU/BIOS can read ME. */
1389 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1390
1391 write_image(filename, image, size);
1392}
1393
Bill XIEfa5f9942017-09-12 11:22:29 +08001394static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001395{
Bill XIE612ec0e2017-08-30 16:10:27 +08001396 fmba_t *fmba = find_fmba(image, size);
1397 if (!fmba)
1398 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001399
1400 if (ifd_version >= IFD_VERSION_2) {
1401 /* Access bits for each region are read: 19:8 write: 31:20 */
1402 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1403 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1404 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001405 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001406 } else {
1407 fmba->flmstr1 = 0xffff0000;
1408 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001409 /* Keep chipset specific Requester ID */
1410 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001411 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001412
1413 write_image(filename, image, size);
1414}
1415
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001416static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1417 const unsigned int value)
1418{
1419 if (!fpsba || !fdb) {
1420 fprintf(stderr, "Internal error\n");
1421 exit(EXIT_FAILURE);
1422 }
1423
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001424 /* SoC Strap, aka PSL, aka ISL */
1425 int SS = (fdb->flmap1 >> 24) & 0xff;
1426 if (strap >= SS) {
1427 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001428 exit(EXIT_FAILURE);
1429 }
1430 fpsba->pchstrp[strap] = value;
1431}
1432
Bill XIEb3e15a22017-09-07 18:34:50 +08001433/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001434static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001435{
1436 if (ifd_version >= IFD_VERSION_2) {
1437 printf("%sting the HAP bit to %s Intel ME...\n",
1438 altmedisable?"Set":"Unset",
1439 altmedisable?"disable":"enable");
1440 if (altmedisable)
1441 fpsba->pchstrp[0] |= (1 << 16);
1442 else
1443 fpsba->pchstrp[0] &= ~(1 << 16);
1444 } else {
1445 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1446 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1447 "and MCH_AltMeDisable to %s Intel ME...\n",
1448 altmedisable?"Set":"Unset",
1449 altmedisable?"disable":"enable");
1450 if (altmedisable) {
1451 /* MCH_MeDisable */
1452 fmsba->data[0] |= 1;
1453 /* MCH_AltMeDisable */
1454 fmsba->data[0] |= (1 << 7);
1455 /* ICH_MeDisable */
1456 fpsba->pchstrp[0] |= 1;
1457 } else {
1458 fmsba->data[0] &= ~1;
1459 fmsba->data[0] &= ~(1 << 7);
1460 fpsba->pchstrp[0] &= ~1;
1461 }
1462 } else {
1463 printf("%sting the AltMeDisable to %s Intel ME...\n",
1464 altmedisable?"Set":"Unset",
1465 altmedisable?"disable":"enable");
1466 if (altmedisable)
1467 fpsba->pchstrp[10] |= (1 << 7);
1468 else
1469 fpsba->pchstrp[10] &= ~(1 << 7);
1470 }
1471 }
1472}
1473
Jacob Garber595d9262019-06-27 17:33:10 -06001474static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001475 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001476{
Bill XIE612ec0e2017-08-30 16:10:27 +08001477 frba_t *frba = find_frba(image, size);
1478 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001479 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001480
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001481 region_t region = get_region(frba, region_type);
1482 if (region.size <= 0xfff) {
1483 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1484 region_name(region_type));
1485 exit(EXIT_FAILURE);
1486 }
1487
Scott Duplichanf2c98372014-12-12 21:03:06 -06001488 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001489 if (region_fd == -1) {
1490 perror("Could not open file");
1491 exit(EXIT_FAILURE);
1492 }
1493 struct stat buf;
1494 if (fstat(region_fd, &buf) == -1) {
1495 perror("Could not stat file");
1496 exit(EXIT_FAILURE);
1497 }
1498 int region_size = buf.st_size;
1499
1500 printf("File %s is %d bytes\n", region_fname, region_size);
1501
1502 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001503 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001504 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1505 " bytes. Not injecting.\n",
1506 region_name(region_type), region.size,
1507 region.size, region_size, region_size);
1508 exit(EXIT_FAILURE);
1509 }
1510
1511 int offset = 0;
1512 if ((region_type == 1) && (region_size < region.size)) {
1513 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1514 " bytes. Padding before injecting.\n",
1515 region_name(region_type), region.size,
1516 region.size, region_size, region_size);
1517 offset = region.size - region_size;
1518 memset(image + region.base, 0xff, offset);
1519 }
1520
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001521 if (size < region.base + offset + region_size) {
1522 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1523 size, region.base + offset + region_size);
1524 exit(EXIT_FAILURE);
1525 }
1526
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001527 if (read(region_fd, image + region.base + offset, region_size)
1528 != region_size) {
1529 perror("Could not read file");
1530 exit(EXIT_FAILURE);
1531 }
1532
1533 close(region_fd);
1534
1535 printf("Adding %s as the %s section of %s\n",
1536 region_fname, region_name(region_type), filename);
1537 write_image(filename, image, size);
1538}
1539
Jacob Garber595d9262019-06-27 17:33:10 -06001540static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001541{
1542 unsigned int y = 1;
1543 if (x == 0)
1544 return 0;
1545 while (y <= x)
1546 y = y << 1;
1547
1548 return y;
1549}
1550
1551/**
1552 * Determine if two memory regions overlap.
1553 *
1554 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001555 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001556 * @return 1 if the two regions overlap
1557 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001558static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001559{
Bill XIEfa5f9942017-09-12 11:22:29 +08001560 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001561 return 0;
1562
Nico Huber844eda02019-01-05 00:06:19 +01001563 /* r1 should be either completely below or completely above r2 */
1564 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001565}
1566
Jacob Garber595d9262019-06-27 17:33:10 -06001567static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001568 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001569{
1570 FILE *romlayout;
1571 char tempstr[256];
1572 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001573 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001574 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001575 region_t current_regions[MAX_REGIONS];
1576 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001577 int new_extent = 0;
1578 char *new_image;
1579
1580 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001581 frba_t *frba = find_frba(image, size);
1582 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001583 exit(EXIT_FAILURE);
1584
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001585 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001586 current_regions[i] = get_region(frba, i);
1587 new_regions[i] = get_region(frba, i);
1588 }
1589
1590 /* read new layout */
1591 romlayout = fopen(layout_fname, "r");
1592
1593 if (!romlayout) {
1594 perror("Could not read layout file.\n");
1595 exit(EXIT_FAILURE);
1596 }
1597
1598 while (!feof(romlayout)) {
1599 char *tstr1, *tstr2;
1600
Patrick Georgi802ad522014-08-09 17:12:23 +02001601 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001602 layout_region_name))
1603 continue;
1604
1605 region_number = region_num(layout_region_name);
1606 if (region_number < 0)
1607 continue;
1608
1609 tstr1 = strtok(tempstr, ":");
1610 tstr2 = strtok(NULL, ":");
1611 if (!tstr1 || !tstr2) {
1612 fprintf(stderr, "Could not parse layout file.\n");
1613 exit(EXIT_FAILURE);
1614 }
1615 new_regions[region_number].base = strtol(tstr1,
1616 (char **)NULL, 16);
1617 new_regions[region_number].limit = strtol(tstr2,
1618 (char **)NULL, 16);
1619 new_regions[region_number].size =
1620 new_regions[region_number].limit -
1621 new_regions[region_number].base + 1;
1622
1623 if (new_regions[region_number].size < 0)
1624 new_regions[region_number].size = 0;
1625 }
1626 fclose(romlayout);
1627
1628 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001629 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001630 if (new_regions[i].size == 0)
1631 continue;
1632
1633 if (new_regions[i].size < current_regions[i].size) {
1634 printf("DANGER: Region %s is shrinking.\n",
1635 region_name(i));
1636 printf(" The region will be truncated to fit.\n");
1637 printf(" This may result in an unusable image.\n");
1638 }
1639
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001640 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001641 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001642 fprintf(stderr, "Regions would overlap.\n");
1643 exit(EXIT_FAILURE);
1644 }
1645 }
1646
1647 /* detect if the image size should grow */
1648 if (new_extent < new_regions[i].limit)
1649 new_extent = new_regions[i].limit;
1650 }
1651
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001652 /* check if the image is actually a Flash Descriptor region */
1653 if (size == new_regions[0].size) {
1654 printf("The image is a single Flash Descriptor:\n");
1655 printf(" Only the descriptor will be modified\n");
1656 new_extent = size;
1657 } else {
1658 new_extent = next_pow2(new_extent - 1);
1659 if (new_extent != size) {
1660 printf("The image has changed in size.\n");
1661 printf("The old image is %d bytes.\n", size);
1662 printf("The new image is %d bytes.\n", new_extent);
1663 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001664 }
1665
1666 /* copy regions to a new image */
1667 new_image = malloc(new_extent);
1668 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001669 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001670 int copy_size = new_regions[i].size;
1671 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001672 const region_t *current = &current_regions[i];
1673 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001674
Bill XIEfa5f9942017-09-12 11:22:29 +08001675 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001676 continue;
1677
Bill XIEfa5f9942017-09-12 11:22:29 +08001678 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001679 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001680 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001681 if (i == REGION_BIOS)
1682 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001683 }
1684
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001685 if ((i == REGION_BIOS) && (new->size < current->size)) {
1686 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001687 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001688 }
1689
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001690 if (size < current->base + offset_current + copy_size) {
1691 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1692 region_name(i));
1693 continue;
1694 };
1695
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001696 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1697 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001698 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1699 offset_current, current->limit, current->size);
1700 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1701 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001702
Bill XIEfa5f9942017-09-12 11:22:29 +08001703 memcpy(new_image + new->base + offset_new,
1704 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001705 copy_size);
1706 }
1707
1708 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001709 frba = find_frba(new_image, new_extent);
1710 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001711 exit(EXIT_FAILURE);
1712
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001713 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001714 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001715 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001716
1717 write_image(filename, new_image, new_extent);
1718 free(new_image);
1719}
1720
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001721static void print_version(void)
1722{
1723 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1724 printf("Copyright (C) 2011 Google Inc.\n\n");
1725 printf
1726 ("This program is free software: you can redistribute it and/or modify\n"
1727 "it under the terms of the GNU General Public License as published by\n"
1728 "the Free Software Foundation, version 2 of the License.\n\n"
1729 "This program is distributed in the hope that it will be useful,\n"
1730 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1731 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001732 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001733}
1734
1735static void print_usage(const char *name)
1736{
1737 printf("usage: %s [-vhdix?] <filename>\n", name);
1738 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001739 " -d | --dump: dump intel firmware descriptor\n"
1740 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1741 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1742 " -x | --extract: extract intel fd modules\n"
1743 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1744 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001745 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001746 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1747 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1748 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1749 " can only be used once per run:\n"
1750 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1751 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1752 " Dual Output Fast Read Support\n"
1753 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301754 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001755 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001756 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1757 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001758 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301759 " adl - Alder Lake\n"
1760 " aplk - Apollo Lake\n"
1761 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001762 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001763 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001764 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301765 " glk - Gemini Lake\n"
1766 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001767 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301768 " jsl - Jasper Lake\n"
1769 " sklkbl - Sky Lake/Kaby Lake\n"
1770 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02001771 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001772 " -S | --setpchstrap Write a PCH strap\n"
1773 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001774 " -v | --version: print the version\n"
1775 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001776 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1777 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001778 "\n");
1779}
1780
1781int main(int argc, char *argv[])
1782{
1783 int opt, option_index = 0;
1784 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001785 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001786 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301787 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001788 char *region_type_string = NULL, *region_fname = NULL;
1789 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001790 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001791 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001792 unsigned int value = 0;
1793 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001794 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001795 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1796
Bill XIEfa5f9942017-09-12 11:22:29 +08001797 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001798 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001799 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001800 {"extract", 0, NULL, 'x'},
1801 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001802 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001803 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001804 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001805 {"density", 1, NULL, 'D'},
1806 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001807 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001808 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001809 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301810 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001811 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001812 {"version", 0, NULL, 'v'},
1813 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001814 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001815 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001816 {"setpchstrap", 1, NULL, 'S'},
1817 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001818 {0, 0, 0, 0}
1819 };
1820
Usha P412679d2020-10-15 11:25:08 +05301821 while ((opt = getopt_long(argc, argv, "S:V:df:D:C:M:xi:n:O:s:p:elruvth?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001822 long_options, &option_index)) != EOF) {
1823 switch (opt) {
1824 case 'd':
1825 mode_dump = 1;
1826 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001827 case 'S':
1828 mode_setstrap = 1;
1829 pchstrap = strtoul(optarg, NULL, 0);
1830 break;
1831 case 'V':
1832 value = strtoul(optarg, NULL, 0);
1833 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001834 case 'f':
1835 mode_layout = 1;
1836 layout_fname = strdup(optarg);
1837 if (!layout_fname) {
1838 fprintf(stderr, "No layout file specified\n");
1839 print_usage(argv[0]);
1840 exit(EXIT_FAILURE);
1841 }
1842 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001843 case 'x':
1844 mode_extract = 1;
1845 break;
1846 case 'i':
1847 // separate type and file name
1848 region_type_string = strdup(optarg);
1849 region_fname = strchr(region_type_string, ':');
1850 if (!region_fname) {
1851 print_usage(argv[0]);
1852 exit(EXIT_FAILURE);
1853 }
1854 region_fname[0] = '\0';
1855 region_fname++;
1856 // Descriptor, BIOS, ME, GbE, Platform
1857 // valid type?
1858 if (!strcasecmp("Descriptor", region_type_string))
1859 region_type = 0;
1860 else if (!strcasecmp("BIOS", region_type_string))
1861 region_type = 1;
1862 else if (!strcasecmp("ME", region_type_string))
1863 region_type = 2;
1864 else if (!strcasecmp("GbE", region_type_string))
1865 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001866 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001867 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001868 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001869 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001870 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001871 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001872 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001873 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001874 else if (!strcasecmp("EC", region_type_string))
1875 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001876 else if (!strcasecmp("Device Exp2", region_type_string))
1877 region_type = 9;
1878 else if (!strcasecmp("IE", region_type_string))
1879 region_type = 10;
1880 else if (!strcasecmp("10GbE_0", region_type_string))
1881 region_type = 11;
1882 else if (!strcasecmp("10GbE_1", region_type_string))
1883 region_type = 12;
1884 else if (!strcasecmp("PTT", region_type_string))
1885 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001886 if (region_type == -1) {
1887 fprintf(stderr, "No such region type: '%s'\n\n",
1888 region_type_string);
1889 print_usage(argv[0]);
1890 exit(EXIT_FAILURE);
1891 }
1892 mode_inject = 1;
1893 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001894 case 'n':
1895 mode_newlayout = 1;
1896 layout_fname = strdup(optarg);
1897 if (!layout_fname) {
1898 fprintf(stderr, "No layout file specified\n");
1899 print_usage(argv[0]);
1900 exit(EXIT_FAILURE);
1901 }
1902 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001903 case 'O':
1904 new_filename = strdup(optarg);
1905 if (!new_filename) {
1906 fprintf(stderr, "No output filename specified\n");
1907 print_usage(argv[0]);
1908 exit(EXIT_FAILURE);
1909 }
1910 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001911 case 'D':
1912 mode_density = 1;
1913 new_density = strtoul(optarg, NULL, 0);
1914 switch (new_density) {
1915 case 512:
1916 new_density = COMPONENT_DENSITY_512KB;
1917 break;
1918 case 1:
1919 new_density = COMPONENT_DENSITY_1MB;
1920 break;
1921 case 2:
1922 new_density = COMPONENT_DENSITY_2MB;
1923 break;
1924 case 4:
1925 new_density = COMPONENT_DENSITY_4MB;
1926 break;
1927 case 8:
1928 new_density = COMPONENT_DENSITY_8MB;
1929 break;
1930 case 16:
1931 new_density = COMPONENT_DENSITY_16MB;
1932 break;
1933 case 32:
1934 new_density = COMPONENT_DENSITY_32MB;
1935 break;
1936 case 64:
1937 new_density = COMPONENT_DENSITY_64MB;
1938 break;
1939 case 0:
1940 new_density = COMPONENT_DENSITY_UNUSED;
1941 break;
1942 default:
1943 printf("error: Unknown density\n");
1944 print_usage(argv[0]);
1945 exit(EXIT_FAILURE);
1946 }
1947 break;
1948 case 'C':
1949 selected_chip = strtol(optarg, NULL, 0);
1950 if (selected_chip > 2) {
1951 fprintf(stderr, "error: Invalid chip selection\n");
1952 print_usage(argv[0]);
1953 exit(EXIT_FAILURE);
1954 }
1955 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001956 case 'M':
1957 mode_altmedisable = 1;
1958 altmedisable = strtol(optarg, NULL, 0);
1959 if (altmedisable > 1) {
1960 fprintf(stderr, "error: Illegal value\n");
1961 print_usage(argv[0]);
1962 exit(EXIT_FAILURE);
1963 }
1964 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001965 case 's':
1966 // Parse the requested SPI frequency
1967 inputfreq = strtol(optarg, NULL, 0);
1968 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001969 case 17:
1970 spifreq = SPI_FREQUENCY_17MHZ;
1971 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001972 case 20:
1973 spifreq = SPI_FREQUENCY_20MHZ;
1974 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001975 case 30:
1976 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1977 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001978 case 33:
1979 spifreq = SPI_FREQUENCY_33MHZ;
1980 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001981 case 48:
1982 spifreq = SPI_FREQUENCY_48MHZ;
1983 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001984 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001985 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001986 break;
1987 default:
1988 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1989 inputfreq);
1990 print_usage(argv[0]);
1991 exit(EXIT_FAILURE);
1992 }
1993 mode_spifreq = 1;
1994 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001995 case 'e':
1996 mode_em100 = 1;
1997 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001998 case 'l':
1999 mode_locked = 1;
2000 if (mode_unlocked == 1) {
2001 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2002 exit(EXIT_FAILURE);
2003 }
2004 break;
Usha P412679d2020-10-15 11:25:08 +05302005 case 'r':
2006 mode_read = 1;
2007 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002008 case 'u':
2009 mode_unlocked = 1;
2010 if (mode_locked == 1) {
2011 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2012 exit(EXIT_FAILURE);
2013 }
2014 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002015 case 'p':
2016 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002017 platform = PLATFORM_APL;
2018 } else if (!strcmp(optarg, "cnl")) {
2019 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002020 } else if (!strcmp(optarg, "lbg")) {
2021 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002022 } else if (!strcmp(optarg, "dnv")) {
2023 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002024 } else if (!strcmp(optarg, "ehl")) {
2025 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002026 } else if (!strcmp(optarg, "glk")) {
2027 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302028 } else if (!strcmp(optarg, "icl")) {
2029 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302030 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002031 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002032 } else if (!strcmp(optarg, "sklkbl")) {
2033 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002034 } else if (!strcmp(optarg, "tgl")) {
2035 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302036 } else if (!strcmp(optarg, "adl")) {
2037 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002038 } else if (!strcmp(optarg, "ifd2")) {
2039 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302040 } else if (!strcmp(optarg, "mtl")) {
2041 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002042 } else if (!strcmp(optarg, "wbg")) {
2043 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002044 } else {
2045 fprintf(stderr, "Unknown platform: %s\n", optarg);
2046 exit(EXIT_FAILURE);
2047 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002048 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07002049 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002050 case 't':
2051 mode_validate = 1;
2052 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002053 case 'v':
2054 print_version();
2055 exit(EXIT_SUCCESS);
2056 break;
2057 case 'h':
2058 case '?':
2059 default:
2060 print_usage(argv[0]);
2061 exit(EXIT_SUCCESS);
2062 break;
2063 }
2064 }
2065
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002066 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002067 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05002068 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002069 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002070 print_usage(argv[0]);
2071 exit(EXIT_FAILURE);
2072 }
2073
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002074 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002075 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06002076 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002077 fprintf(stderr, "You need to specify a mode.\n\n");
2078 print_usage(argv[0]);
2079 exit(EXIT_FAILURE);
2080 }
2081
2082 if (optind + 1 != argc) {
2083 fprintf(stderr, "You need to specify a file.\n\n");
2084 print_usage(argv[0]);
2085 exit(EXIT_FAILURE);
2086 }
2087
2088 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002089 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002090 if (bios_fd == -1) {
2091 perror("Could not open file");
2092 exit(EXIT_FAILURE);
2093 }
2094 struct stat buf;
2095 if (fstat(bios_fd, &buf) == -1) {
2096 perror("Could not stat file");
2097 exit(EXIT_FAILURE);
2098 }
2099 int size = buf.st_size;
2100
2101 printf("File %s is %d bytes\n", filename, size);
2102
2103 char *image = malloc(size);
2104 if (!image) {
2105 printf("Out of memory.\n");
2106 exit(EXIT_FAILURE);
2107 }
2108
2109 if (read(bios_fd, image, size) != size) {
2110 perror("Could not read file");
2111 exit(EXIT_FAILURE);
2112 }
2113
2114 close(bios_fd);
2115
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002116 // generate new filename
2117 if (new_filename == NULL) {
2118 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2119 if (!new_filename) {
2120 printf("Out of memory.\n");
2121 exit(EXIT_FAILURE);
2122 }
2123 // - 5: leave room for ".new\0"
2124 strcpy(new_filename, filename);
2125 strcat(new_filename, ".new");
2126 }
2127
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002128 check_ifd_version(image, size);
2129
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002130 if (mode_dump)
2131 dump_fd(image, size);
2132
Chris Douglass03ce0142014-02-26 13:30:13 -05002133 if (mode_layout)
2134 dump_layout(image, size, layout_fname);
2135
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002136 if (mode_extract)
2137 write_regions(image, size);
2138
Mathew Kingc7ddc992019-08-08 14:59:25 -06002139 if (mode_validate)
2140 validate_layout(image, size);
2141
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002142 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002143 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002144 region_fname);
2145
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002146 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002147 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002148
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002149 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002150 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002151
Jan Tatjefa317512016-03-11 00:52:07 +01002152 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002153 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002154
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002155 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002156 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002157
Alexander Couzensd12ea112016-09-10 13:33:05 +02002158 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002159 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002160
Usha P412679d2020-10-15 11:25:08 +05302161 if (mode_read)
2162 enable_cpu_read_me(new_filename, image, size);
2163
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002164 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002165 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002166
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002167 if (mode_setstrap) {
2168 fpsba_t *fpsba = find_fpsba(image, size);
2169 const fdbar_t *fdb = find_fd(image, size);
2170 set_pchstrap(fpsba, fdb, pchstrap, value);
2171 write_image(new_filename, image, size);
2172 }
2173
Bill XIEb3e15a22017-09-07 18:34:50 +08002174 if (mode_altmedisable) {
2175 fpsba_t *fpsba = find_fpsba(image, size);
2176 fmsba_t *fmsba = find_fmsba(image, size);
2177 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002178 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002179 }
2180
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002181 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002182 free(image);
2183
2184 return 0;
2185}