blob: 1ddb6b7fe194bb242287ff9bb8bf1aa097737be4 [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",
77 "ICH",
78 "ICH2345",
79 "ICH6",
80 "SCH U",
81 "Atom E6xx",
82 "Atom S1220 S1240 S1260",
83 "ICH7",
84 "ICH8",
85 "ICH9",
86 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053087 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080088 "5 series Ibex Peak",
89 "6 series Cougar Point",
90 "7 series Panther Point",
91 "8 series Lynx Point",
92 "Baytrail",
93 "8 series Lynx Point LP",
94 "8 series Wellsburg",
95 "9 series Wildcat Point",
96 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053097 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053098 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053099 "Jasper Lake: N6xxx, N51xx, N45xx",
100 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +0530101 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +0530102 "300 series Cannon Point",
103 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +0530104 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +0800105 "C620 series Lewisburg",
106 NULL
107};
108
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700109static fdbar_t *find_fd(char *image, int size)
110{
111 int i, found = 0;
112
113 /* Scan for FD signature */
114 for (i = 0; i < (size - 4); i += 4) {
115 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
116 found = 1;
117 break; // signature found.
118 }
119 }
120
121 if (!found) {
122 printf("No Flash Descriptor found in this image\n");
123 return NULL;
124 }
125
Bill XIE612ec0e2017-08-30 16:10:27 +0800126 fdbar_t *fdb = (fdbar_t *) (image + i);
127 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
128}
129
Stefan Tauner0d226142018-08-05 18:56:53 +0200130static char *find_flumap(char *image, int size)
131{
132 /* The upper map is located in the word before the 256B-long OEM section
133 * at the end of the 4kB-long flash descriptor. In the official
134 * documentation this is defined as FDBAR + 0xEFC. However, starting
135 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
136 * has moved 16 bytes back to offset 0x10 of the image. Although
137 * official documentation still maintains the offset relative to FDBAR
138 * this is wrong and a simple fixed offset from the start of the image
139 * works.
140 */
141 char *flumap = image + 4096 - 256 - 4;
142 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
143}
144
Bill XIE612ec0e2017-08-30 16:10:27 +0800145static fcba_t *find_fcba(char *image, int size)
146{
147 fdbar_t *fdb = find_fd(image, size);
148 if (!fdb)
149 return NULL;
150 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
151 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
152
153}
154
155static fmba_t *find_fmba(char *image, int size)
156{
157 fdbar_t *fdb = find_fd(image, size);
158 if (!fdb)
159 return NULL;
160 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
161 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
162}
163
164static frba_t *find_frba(char *image, int size)
165{
166 fdbar_t *fdb = find_fd(image, size);
167 if (!fdb)
168 return NULL;
169 frba_t *frba =
170 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
171 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
172}
173
174static fpsba_t *find_fpsba(char *image, int size)
175{
176 fdbar_t *fdb = find_fd(image, size);
177 if (!fdb)
178 return NULL;
179 fpsba_t *fpsba =
180 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200181
182 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
183 if ((((char *)fpsba) + SSL) >= (image + size))
184 return NULL;
185 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800186}
187
188static fmsba_t *find_fmsba(char *image, int size)
189{
190 fdbar_t *fdb = find_fd(image, size);
191 if (!fdb)
192 return NULL;
193 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
194 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700195}
196
Bill XIEb3e15a22017-09-07 18:34:50 +0800197/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530198static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800199{
Subrata Banik8c082e52021-06-10 23:02:29 +0530200 const fdbar_t *fdb = find_fd(image, size);
201 if (!fdb)
202 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800203 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
204 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
205 uint32_t isl = (fdb->flmap1 >> 24);
206 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
Subrata Banik89db2252020-08-26 14:49:17 +0530207
208 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800209 if (iccriba == 0x00) {
210 if (msl == 0 && isl <= 2)
211 return CHIPSET_ICH8;
212 else if (isl <= 2)
213 return CHIPSET_ICH9;
214 else if (isl <= 10)
215 return CHIPSET_ICH10;
216 else if (isl <= 16)
217 return CHIPSET_5_SERIES_IBEX_PEAK;
218 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
219 return CHIPSET_5_SERIES_IBEX_PEAK;
220 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
221 if (msl == 0 && isl <= 17)
222 return CHIPSET_BAYTRAIL;
223 else if (msl <= 1 && isl <= 18)
224 return CHIPSET_6_SERIES_COUGAR_POINT;
225 else if (msl <= 1 && isl <= 21)
226 return CHIPSET_8_SERIES_LYNX_POINT;
227 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
228 return CHIPSET_9_SERIES_WILDCAT_POINT;
229 } else if (nm == 6) {
230 return CHIPSET_C620_SERIES_LEWISBURG;
Bill XIEb3e15a22017-09-07 18:34:50 +0800231 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200232 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800233}
234
Subrata Banik8c082e52021-06-10 23:02:29 +0530235static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
236{
237 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530238 case PLATFORM_APL:
239 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530240 case PLATFORM_GLK:
241 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
242 case PLATFORM_JSL:
243 return CHIPSET_N_SERIES_JASPER_LAKE;
244 case PLATFORM_EHL:
245 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200246 case PLATFORM_SKLKBL:
247 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530248 case PLATFORM_CNL:
249 return CHIPSET_300_SERIES_CANNON_POINT;
250 case PLATFORM_TGL:
251 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800252 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +0530253 case PLATFORM_MTL:
Subrata Banik8c082e52021-06-10 23:02:29 +0530254 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
255 case PLATFORM_ICL:
256 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800257 case PLATFORM_LBG:
258 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500259 case PLATFORM_DNV:
260 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200261 case PLATFORM_WBG:
262 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530263 default:
264 return CHIPSET_PCH_UNKNOWN;
265 }
266}
267
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700268/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700269 * Some newer platforms have re-defined the FCBA field that was used to
270 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
271 * have the required FCBA field, but are IFD v2 and return true if current
272 * platform is one of them.
273 */
274static int is_platform_ifd_2(void)
275{
276 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530277 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700278 PLATFORM_GLK,
279 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800280 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500281 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530282 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700283 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530284 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700285 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530286 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200287 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800288 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530289 PLATFORM_MTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200290 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700291 };
292 unsigned int i;
293
294 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
295 if (platform == ifd_2_platforms[i])
296 return 1;
297 }
298
299 return 0;
300}
301
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700302static void check_ifd_version(char *image, int size)
303{
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200304 const fdbar_t *fdb = find_fd(image, size);
305
Subrata Banik8c082e52021-06-10 23:02:29 +0530306 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530307 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200308 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
309 ifd_version = IFD_VERSION_1_5;
310 else
311 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200312 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530313 } else {
314 ifd_version = IFD_VERSION_1;
315 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200316 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530317 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700318}
319
Bill XIEfa5f9942017-09-12 11:22:29 +0800320static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700321{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500322 int base_mask;
323 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700324 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700325 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500326
327 if (ifd_version >= IFD_VERSION_2)
328 base_mask = 0x7fff;
329 else
330 base_mask = 0xfff;
331
332 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400334 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800335 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700336 exit (EXIT_FAILURE);
337 }
338
Bill XIE4651d452017-09-12 11:54:48 +0800339 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700340 region.base = (flreg & base_mask) << 12;
341 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700342 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500343
Chris Douglass03ce0142014-02-26 13:30:13 -0500344 if (region.size < 0)
345 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700346
347 return region;
348}
349
Bill XIEfa5f9942017-09-12 11:22:29 +0800350static void set_region(frba_t *frba, unsigned int region_type,
351 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500352{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400353 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800354 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500355 exit (EXIT_FAILURE);
356 }
Bill XIE4651d452017-09-12 11:54:48 +0800357
358 frba->flreg[region_type] =
359 (((region->limit >> 12) & 0x7fff) << 16) |
360 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500361}
362
Bill XIEfa5f9942017-09-12 11:22:29 +0800363static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700364{
Bill XIEfa5f9942017-09-12 11:22:29 +0800365 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700366 fprintf(stderr, "Invalid region type.\n");
367 exit (EXIT_FAILURE);
368 }
369
Chris Douglass03ce0142014-02-26 13:30:13 -0500370 return region_names[region_type].pretty;
371}
372
Bill XIEfa5f9942017-09-12 11:22:29 +0800373static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500374{
Bill XIEfa5f9942017-09-12 11:22:29 +0800375 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500376 fprintf(stderr, "Invalid region type.\n");
377 exit (EXIT_FAILURE);
378 }
379
380 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700381}
382
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500383static int region_num(const char *name)
384{
Bill XIEfa5f9942017-09-12 11:22:29 +0800385 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500386
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200387 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500388 if (strcasecmp(name, region_names[i].pretty) == 0)
389 return i;
390 if (strcasecmp(name, region_names[i].terse) == 0)
391 return i;
392 }
393
394 return -1;
395}
396
Bill XIEfa5f9942017-09-12 11:22:29 +0800397static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700398{
Bill XIEfa5f9942017-09-12 11:22:29 +0800399 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700400 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700401 exit (EXIT_FAILURE);
402 }
403
Bill XIE1bf65062017-09-12 11:31:37 +0800404 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700405}
406
Bill XIEfa5f9942017-09-12 11:22:29 +0800407static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700408{
409 region_t region = get_region(frba, num);
410 printf(" Flash Region %d (%s): %08x - %08x %s\n",
411 num, region_name(num), region.base, region.limit,
412 region.size < 1 ? "(unused)" : "");
413}
414
Bill XIEfa5f9942017-09-12 11:22:29 +0800415static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
416 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500417{
418 region_t region = get_region(frba, num);
419 snprintf(buf, bufsize, "%08x:%08x %s\n",
420 region.base, region.limit, region_name_short(num));
421}
422
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200423static int sort_compare(const void *a, const void *b)
424{
425 return *(size_t *)a - *(size_t *)b;
426}
427
428/*
429 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
430 *
431 * It's platform specific which regions are used or are reserved.
432 * The 'SPI programming guide' as the name says is a guide only,
433 * not a specification what the hardware actually does.
434 * The best to do is not to rely on the guide, but detect how many
435 * regions are present in the IFD and expose them all.
436 *
437 * Very early IFDv2 chipsets, sometimes unofficially referred to as
438 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
439 * operating on an IFDv1.5 detect how much space is actually present
440 * in the IFD.
441 */
442static int max_regions_from_fdbar(const fdbar_t *fdb)
443{
444 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
445 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
446 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
447 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
448 const size_t flumap = 4096 - 256 - 4;
449 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
450
451 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
452
453 for (size_t i = 0; i < 4; i++) {
454 /*
455 * Find FRBA in the sorted array and determine the size of the
456 * region by the start of the next region. Every region requires
457 * 4 bytes of space.
458 */
459 if (sorted[i] == frba)
460 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
461 }
462 /* Never reaches this point */
463 return 0;
464}
465
Bill XIEfa5f9942017-09-12 11:22:29 +0800466static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700467{
Bill XIE4651d452017-09-12 11:54:48 +0800468 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530469 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700470 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800471 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530472 region = get_region(frba, i);
473 /* Skip unused & reserved Flash Region */
474 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
475 continue;
476
Bill XIE4651d452017-09-12 11:54:48 +0800477 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
478 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700479 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700480}
481
Bill XIEfa5f9942017-09-12 11:22:29 +0800482static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500483{
484 char buf[LAYOUT_LINELEN];
485 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800486 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500487
488 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
489 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
490 if (layout_fd == -1) {
491 perror("Could not open file");
492 exit(EXIT_FAILURE);
493 }
494
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200495 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200496 region_t region = get_region(frba, i);
497 /* is region invalid? */
498 if (region.size < 1)
499 continue;
500
Chris Douglass03ce0142014-02-26 13:30:13 -0500501 dump_region_layout(buf, bufsize, i, frba);
502 if (write(layout_fd, buf, strlen(buf)) < 0) {
503 perror("Could not write to file");
504 exit(EXIT_FAILURE);
505 }
506 }
507 close(layout_fd);
508 printf("Wrote layout to %s\n", layout_fname);
509}
510
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530511static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700512{
513 switch (freq) {
514 case SPI_FREQUENCY_20MHZ:
515 printf("20MHz");
516 break;
517 case SPI_FREQUENCY_33MHZ:
518 printf("33MHz");
519 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700520 case SPI_FREQUENCY_48MHZ:
521 printf("48MHz");
522 break;
523 case SPI_FREQUENCY_50MHZ_30MHZ:
524 switch (ifd_version) {
525 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200526 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700527 printf("50MHz");
528 break;
529 case IFD_VERSION_2:
530 printf("30MHz");
531 break;
532 }
533 break;
534 case SPI_FREQUENCY_17MHZ:
535 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700536 break;
537 default:
538 printf("unknown<%x>MHz", freq);
539 }
540}
541
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530542static void _decode_spi_frequency_500_series(unsigned int freq)
543{
544 switch (freq) {
545 case SPI_FREQUENCY_100MHZ:
546 printf("100MHz");
547 break;
548 case SPI_FREQUENCY_50MHZ:
549 printf("50MHz");
550 break;
551 case SPI_FREQUENCY_500SERIES_33MHZ:
552 printf("33MHz");
553 break;
554 case SPI_FREQUENCY_25MHZ:
555 printf("25MHz");
556 break;
557 case SPI_FREQUENCY_14MHZ:
558 printf("14MHz");
559 break;
560 default:
561 printf("unknown<%x>MHz", freq);
562 }
563}
564
565static void decode_spi_frequency(unsigned int freq)
566{
Subrata Banika5f47812020-09-29 11:43:01 +0530567 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530568 _decode_spi_frequency_500_series(freq);
569 else
570 _decode_spi_frequency(freq);
571}
572
Subrata Banike5d39922020-08-26 16:01:42 +0530573static void _decode_espi_frequency(unsigned int freq)
574{
575 switch (freq) {
576 case ESPI_FREQUENCY_20MHZ:
577 printf("20MHz");
578 break;
579 case ESPI_FREQUENCY_24MHZ:
580 printf("24MHz");
581 break;
582 case ESPI_FREQUENCY_30MHZ:
583 printf("30MHz");
584 break;
585 case ESPI_FREQUENCY_48MHZ:
586 printf("48MHz");
587 break;
588 case ESPI_FREQUENCY_60MHZ:
589 printf("60MHz");
590 break;
591 case ESPI_FREQUENCY_17MHZ:
592 printf("17MHz");
593 break;
594 default:
595 printf("unknown<%x>MHz", freq);
596 }
597}
598
599static void _decode_espi_frequency_500_series(unsigned int freq)
600{
601 switch (freq) {
602 case ESPI_FREQUENCY_500SERIES_20MHZ:
603 printf("20MHz");
604 break;
605 case ESPI_FREQUENCY_500SERIES_24MHZ:
606 printf("24MHz");
607 break;
608 case ESPI_FREQUENCY_500SERIES_25MHZ:
609 printf("25MHz");
610 break;
611 case ESPI_FREQUENCY_500SERIES_48MHZ:
612 printf("48MHz");
613 break;
614 case ESPI_FREQUENCY_500SERIES_60MHZ:
615 printf("60MHz");
616 break;
617 default:
618 printf("unknown<%x>MHz", freq);
619 }
620}
621
622static void decode_espi_frequency(unsigned int freq)
623{
Subrata Banika5f47812020-09-29 11:43:01 +0530624 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530625 _decode_espi_frequency_500_series(freq);
626 else
627 _decode_espi_frequency(freq);
628}
629
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700630static void decode_component_density(unsigned int density)
631{
632 switch (density) {
633 case COMPONENT_DENSITY_512KB:
634 printf("512KB");
635 break;
636 case COMPONENT_DENSITY_1MB:
637 printf("1MB");
638 break;
639 case COMPONENT_DENSITY_2MB:
640 printf("2MB");
641 break;
642 case COMPONENT_DENSITY_4MB:
643 printf("4MB");
644 break;
645 case COMPONENT_DENSITY_8MB:
646 printf("8MB");
647 break;
648 case COMPONENT_DENSITY_16MB:
649 printf("16MB");
650 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700651 case COMPONENT_DENSITY_32MB:
652 printf("32MB");
653 break;
654 case COMPONENT_DENSITY_64MB:
655 printf("64MB");
656 break;
657 case COMPONENT_DENSITY_UNUSED:
658 printf("UNUSED");
659 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700660 default:
661 printf("unknown<%x>MB", density);
662 }
663}
664
Subrata Banik26058dc2020-08-26 15:12:16 +0530665static int is_platform_with_pch(void)
666{
667 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
668 return 1;
669
670 return 0;
671}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530672
673/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
674static int is_platform_with_100x_series_pch(void)
675{
676 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530677 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530678 return 1;
679
680 return 0;
681}
682
Subrata Banike5d39922020-08-26 16:01:42 +0530683static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700684{
Subrata Banike5d39922020-08-26 16:01:42 +0530685 unsigned int freq;
686
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700687 printf("\nFound Component Section\n");
688 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700689 printf(" Dual Output Fast Read Support: %ssupported\n",
690 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700691 printf(" Read ID/Read Status Clock Frequency: ");
692 decode_spi_frequency((fcba->flcomp >> 27) & 7);
693 printf("\n Write/Erase Clock Frequency: ");
694 decode_spi_frequency((fcba->flcomp >> 24) & 7);
695 printf("\n Fast Read Clock Frequency: ");
696 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700697 printf("\n Fast Read Support: %ssupported",
698 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530699 if (is_platform_with_100x_series_pch() &&
700 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
701 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530702 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530703 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
704 else
705 freq = (fcba->flcomp >> 17) & 7;
706 decode_espi_frequency(freq);
707 } else {
708 printf("\n Read Clock Frequency: ");
709 decode_spi_frequency((fcba->flcomp >> 17) & 7);
710 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700711
712 switch (ifd_version) {
713 case IFD_VERSION_1:
714 printf("\n Component 2 Density: ");
715 decode_component_density((fcba->flcomp >> 3) & 7);
716 printf("\n Component 1 Density: ");
717 decode_component_density(fcba->flcomp & 7);
718 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200719 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700720 case IFD_VERSION_2:
721 printf("\n Component 2 Density: ");
722 decode_component_density((fcba->flcomp >> 4) & 0xf);
723 printf("\n Component 1 Density: ");
724 decode_component_density(fcba->flcomp & 0xf);
725 break;
726 }
727
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700728 printf("\n");
729 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700730 printf(" Invalid Instruction 3: 0x%02x\n",
731 (fcba->flill >> 24) & 0xff);
732 printf(" Invalid Instruction 2: 0x%02x\n",
733 (fcba->flill >> 16) & 0xff);
734 printf(" Invalid Instruction 1: 0x%02x\n",
735 (fcba->flill >> 8) & 0xff);
736 printf(" Invalid Instruction 0: 0x%02x\n",
737 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530738 if (is_platform_with_100x_series_pch()) {
739 printf("FLILL1 0x%08x\n", fcba->flpb);
740 printf(" Invalid Instruction 7: 0x%02x\n",
741 (fcba->flpb >> 24) & 0xff);
742 printf(" Invalid Instruction 6: 0x%02x\n",
743 (fcba->flpb >> 16) & 0xff);
744 printf(" Invalid Instruction 5: 0x%02x\n",
745 (fcba->flpb >> 8) & 0xff);
746 printf(" Invalid Instruction 4: 0x%02x\n",
747 fcba->flpb & 0xff);
748 } else {
749 printf("FLPB 0x%08x\n", fcba->flpb);
750 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
751 (fcba->flpb & 0xfff) << 12);
752 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700753}
754
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200755static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700756{
Bill XIE4651d452017-09-12 11:54:48 +0800757 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200758 /* SoC Straps, aka PSL, aka ISL */
759 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200760
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700761 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200762 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200763 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800764
765 if (ifd_version >= IFD_VERSION_2) {
766 printf("HAP bit is %sset\n",
767 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
768 } else if (chipset >= CHIPSET_ICH8
769 && chipset <= CHIPSET_ICH10) {
770 printf("ICH_MeDisable bit is %sset\n",
771 fpsba->pchstrp[0] & 1 ? "" : "not ");
772 } else {
773 printf("AltMeDisable bit is %sset\n",
774 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
775 }
776
Bill XIE4651d452017-09-12 11:54:48 +0800777 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700778}
779
780static void decode_flmstr(uint32_t flmstr)
781{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700782 int wr_shift, rd_shift;
783 if (ifd_version >= IFD_VERSION_2) {
784 wr_shift = FLMSTR_WR_SHIFT_V2;
785 rd_shift = FLMSTR_RD_SHIFT_V2;
786 } else {
787 wr_shift = FLMSTR_WR_SHIFT_V1;
788 rd_shift = FLMSTR_RD_SHIFT_V1;
789 }
790
791 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500792 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700793 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700794 (flmstr & (1 << (wr_shift + 8))) ?
795 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700796 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700797 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500798 if (PLATFORM_HAS_GBE_REGION) {
799 printf(" GbE Region Write Access: %s\n",
800 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
801 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700802 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700803 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700804 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700805 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700806 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700807 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500808 if (PLATFORM_HAS_10GBE_0_REGION) {
809 printf(" 10GbE_0 Write Access: %s\n",
810 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
811 }
812 if (PLATFORM_HAS_10GBE_1_REGION) {
813 printf(" 10GbE_1 Write Access: %s\n",
814 (flmstr & (1 << 4)) ? "enabled" : "disabled");
815 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700816
Jeff Dalyabd4b962022-01-06 00:52:30 -0500817 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700818 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700819 (flmstr & (1 << (rd_shift + 8))) ?
820 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700821 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700822 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500823 if (PLATFORM_HAS_GBE_REGION) {
824 printf(" GbE Region Read Access: %s\n",
825 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
826 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700827 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700828 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700829 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700830 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700831 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700832 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500833 if (PLATFORM_HAS_10GBE_0_REGION) {
834 printf(" 10GbE_0 Read Access: %s\n",
835 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
836 }
837 if (PLATFORM_HAS_10GBE_1_REGION) {
838 printf(" 10GbE_1 Read Access: %s\n",
839 (flmstr & (1 << 0)) ? "enabled" : "disabled");
840 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700841
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700842 /* Requestor ID doesn't exist for ifd 2 */
843 if (ifd_version < IFD_VERSION_2)
844 printf(" Requester ID: 0x%04x\n\n",
845 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700846}
847
Bill XIEfa5f9942017-09-12 11:22:29 +0800848static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700849{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700850 printf("Found Master Section\n");
851 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
852 decode_flmstr(fmba->flmstr1);
853 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
854 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500855 if (PLATFORM_HAS_GBE_REGION) {
856 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
857 decode_flmstr(fmba->flmstr3);
858 if (ifd_version >= IFD_VERSION_2) {
859 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
860 decode_flmstr(fmba->flmstr5);
861 }
862 } else {
863 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
864 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700865 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700866}
867
Bill XIEfa5f9942017-09-12 11:22:29 +0800868static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700869{
Bill XIE612ec0e2017-08-30 16:10:27 +0800870 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700871 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800872 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
873 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800874
875 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
876 printf("MCH_MeDisable bit is %sset\n",
877 fmsba->data[0] & 1 ? "" : "not ");
878 printf("MCH_AltMeDisable bit is %sset\n",
879 fmsba->data[0] & (1 << 7) ? "" : "not ");
880 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700881}
882
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700883static void dump_jid(uint32_t jid)
884{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100885 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700886 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100887 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200888 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100889 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200890 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700891}
892
893static void dump_vscc(uint32_t vscc)
894{
895 printf(" Lower Erase Opcode: 0x%02x\n",
896 vscc >> 24);
897 printf(" Lower Write Enable on Write Status: 0x%02x\n",
898 vscc & (1 << 20) ? 0x06 : 0x50);
899 printf(" Lower Write Status Required: %s\n",
900 vscc & (1 << 19) ? "Yes" : "No");
901 printf(" Lower Write Granularity: %d bytes\n",
902 vscc & (1 << 18) ? 64 : 1);
903 printf(" Lower Block / Sector Erase Size: ");
904 switch ((vscc >> 16) & 0x3) {
905 case 0:
906 printf("256 Byte\n");
907 break;
908 case 1:
909 printf("4KB\n");
910 break;
911 case 2:
912 printf("8KB\n");
913 break;
914 case 3:
915 printf("64KB\n");
916 break;
917 }
918
919 printf(" Upper Erase Opcode: 0x%02x\n",
920 (vscc >> 8) & 0xff);
921 printf(" Upper Write Enable on Write Status: 0x%02x\n",
922 vscc & (1 << 4) ? 0x06 : 0x50);
923 printf(" Upper Write Status Required: %s\n",
924 vscc & (1 << 3) ? "Yes" : "No");
925 printf(" Upper Write Granularity: %d bytes\n",
926 vscc & (1 << 2) ? 64 : 1);
927 printf(" Upper Block / Sector Erase Size: ");
928 switch (vscc & 0x3) {
929 case 0:
930 printf("256 Byte\n");
931 break;
932 case 1:
933 printf("4KB\n");
934 break;
935 case 2:
936 printf("8KB\n");
937 break;
938 case 3:
939 printf("64KB\n");
940 break;
941 }
942}
943
Bill XIEfa5f9942017-09-12 11:22:29 +0800944static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700945{
946 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200947 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
948 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700949
950 printf("ME VSCC table:\n");
951 for (i = 0; i < num; i++) {
952 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
953 dump_jid(vtba->entry[i].jid);
954 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
955 dump_vscc(vtba->entry[i].vscc);
956 }
957 printf("\n");
958}
959
Bill XIEfa5f9942017-09-12 11:22:29 +0800960static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700961{
962 int i, j;
963 printf("OEM Section:\n");
964 for (i = 0; i < 4; i++) {
965 printf("%02x:", i << 4);
966 for (j = 0; j < 16; j++)
967 printf(" %02x", oem[(i<<4)+j]);
968 printf ("\n");
969 }
970 printf ("\n");
971}
972
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700973static void dump_fd(char *image, int size)
974{
Bill XIE612ec0e2017-08-30 16:10:27 +0800975 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700976 if (!fdb)
977 exit(EXIT_FAILURE);
978
Subrata Banik26058dc2020-08-26 15:12:16 +0530979 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
980 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700981 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530982 if (!is_platform_with_100x_series_pch())
983 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700984 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
985 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
986 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
987
988 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530989 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
990 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700991 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
992 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
993 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
994
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530995 if (!is_platform_with_100x_series_pch()) {
996 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
997 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
998 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
999 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001000
Subrata Banika5f47812020-09-29 11:43:01 +05301001 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +05301002 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
1003 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
1004 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
1005 }
1006
Stefan Tauner0d226142018-08-05 18:56:53 +02001007 char *flumap = find_flumap(image, size);
1008 uint32_t flumap1 = *(uint32_t *)flumap;
1009 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001010 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001011 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001012 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001013 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001014 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +02001015 (image + ((flumap1 & 0xff) << 4)),
1016 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +08001017 dump_oem((const uint8_t *)image + 0xf00);
1018
1019 const frba_t *frba = find_frba(image, size);
1020 const fcba_t *fcba = find_fcba(image, size);
1021 const fpsba_t *fpsba = find_fpsba(image, size);
1022 const fmba_t *fmba = find_fmba(image, size);
1023 const fmsba_t *fmsba = find_fmsba(image, size);
1024
1025 if (frba && fcba && fpsba && fmba && fmsba) {
1026 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +05301027 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001028 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +08001029 dump_fmba(fmba);
1030 dump_fmsba(fmsba);
1031 } else {
1032 printf("FD is corrupted!\n");
1033 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001034}
1035
Bill XIEfa5f9942017-09-12 11:22:29 +08001036static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -05001037{
Bill XIE612ec0e2017-08-30 16:10:27 +08001038 const frba_t *frba = find_frba(image, size);
1039 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -05001040 exit(EXIT_FAILURE);
1041
Bill XIE612ec0e2017-08-30 16:10:27 +08001042 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05001043}
1044
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001045static void write_regions(char *image, int size)
1046{
Bill XIEfa5f9942017-09-12 11:22:29 +08001047 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +08001048 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001049
Bill XIE612ec0e2017-08-30 16:10:27 +08001050 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001051 exit(EXIT_FAILURE);
1052
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001053 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001054 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001055 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001056 if (region.size > 0) {
1057 int region_fd;
1058 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -06001059 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001060 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001061 if (region_fd < 0) {
1062 perror("Error while trying to open file");
1063 exit(EXIT_FAILURE);
1064 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001065 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001066 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001067 close(region_fd);
1068 }
1069 }
1070}
1071
Mathew Kingc7ddc992019-08-08 14:59:25 -06001072static void validate_layout(char *image, int size)
1073{
1074 uint i, errors = 0;
1075 struct fmap *fmap;
1076 long int fmap_loc = fmap_find((uint8_t *)image, size);
1077 const frba_t *frba = find_frba(image, size);
1078
1079 if (fmap_loc < 0 || !frba)
1080 exit(EXIT_FAILURE);
1081
1082 fmap = (struct fmap *)(image + fmap_loc);
1083
1084 for (i = 0; i < max_regions; i++) {
1085 if (region_names[i].fmapname == NULL)
1086 continue;
1087
1088 region_t region = get_region(frba, i);
1089
1090 if (region.size == 0)
1091 continue;
1092
1093 const struct fmap_area *area =
1094 fmap_find_area(fmap, region_names[i].fmapname);
1095
1096 if (!area)
1097 continue;
1098
1099 if ((uint)region.base != area->offset ||
1100 (uint)region.size != area->size) {
1101 printf("Region mismatch between %s and %s\n",
1102 region_names[i].terse, area->name);
1103 printf(" Descriptor region %s:\n", region_names[i].terse);
1104 printf(" offset: 0x%08x\n", region.base);
1105 printf(" length: 0x%08x\n", region.size);
1106 printf(" FMAP area %s:\n", area->name);
1107 printf(" offset: 0x%08x\n", area->offset);
1108 printf(" length: 0x%08x\n", area->size);
1109 errors++;
1110 }
1111 }
1112
1113 if (errors > 0)
1114 exit(EXIT_FAILURE);
1115}
1116
Bill XIEfa5f9942017-09-12 11:22:29 +08001117static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001118{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001119 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001120 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001121
1122 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001123 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001124 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001125 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001126 if (new_fd < 0) {
1127 perror("Error while trying to open file");
1128 exit(EXIT_FAILURE);
1129 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001130 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001131 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001132 close(new_fd);
1133}
1134
Bill XIEfa5f9942017-09-12 11:22:29 +08001135static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001136 enum spi_frequency freq)
1137{
Bill XIE612ec0e2017-08-30 16:10:27 +08001138 fcba_t *fcba = find_fcba(image, size);
1139 if (!fcba)
1140 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001141
1142 /* clear bits 21-29 */
1143 fcba->flcomp &= ~0x3fe00000;
1144 /* Read ID and Read Status Clock Frequency */
1145 fcba->flcomp |= freq << 27;
1146 /* Write and Erase Clock Frequency */
1147 fcba->flcomp |= freq << 24;
1148 /* Fast Read Clock Frequency */
1149 fcba->flcomp |= freq << 21;
1150
1151 write_image(filename, image, size);
1152}
1153
Bill XIEfa5f9942017-09-12 11:22:29 +08001154static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001155{
Bill XIE612ec0e2017-08-30 16:10:27 +08001156 fcba_t *fcba = find_fcba(image, size);
1157 if (!fcba)
1158 exit(EXIT_FAILURE);
1159
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001160 int freq;
1161
1162 switch (ifd_version) {
1163 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001164 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001165 freq = SPI_FREQUENCY_20MHZ;
1166 break;
1167 case IFD_VERSION_2:
1168 freq = SPI_FREQUENCY_17MHZ;
1169 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001170 default:
1171 freq = SPI_FREQUENCY_17MHZ;
1172 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001173 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001174
1175 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001176 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001177}
1178
Bill XIEfa5f9942017-09-12 11:22:29 +08001179static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001180 unsigned int density)
1181{
Bill XIE612ec0e2017-08-30 16:10:27 +08001182 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001183 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001184 if (!fcba)
1185 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001186
1187 printf("Setting chip density to ");
1188 decode_component_density(density);
1189 printf("\n");
1190
1191 switch (ifd_version) {
1192 case IFD_VERSION_1:
1193 /* fail if selected density is not supported by this version */
1194 if ( (density == COMPONENT_DENSITY_32MB) ||
1195 (density == COMPONENT_DENSITY_64MB) ||
1196 (density == COMPONENT_DENSITY_UNUSED) ) {
1197 printf("error: Selected density not supported in IFD version 1.\n");
1198 exit(EXIT_FAILURE);
1199 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001200 mask = 0x7;
1201 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001202 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001203 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001204 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001205 mask = 0xf;
1206 chip2_offset = 4;
1207 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001208 default:
1209 printf("error: Unknown IFD version\n");
1210 exit(EXIT_FAILURE);
1211 break;
1212 }
1213
1214 /* clear chip density for corresponding chip */
1215 switch (selected_chip) {
1216 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001217 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001218 break;
1219 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001220 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001221 break;
1222 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001223 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001224 break;
1225 }
1226
1227 /* set the new density */
1228 if (selected_chip == 1 || selected_chip == 0)
1229 fcba->flcomp |= (density); /* first chip */
1230 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001231 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001232
1233 write_image(filename, image, size);
1234}
1235
Duncan Laurie7775d672019-06-06 13:39:26 -07001236static int check_region(const frba_t *frba, unsigned int region_type)
1237{
1238 region_t region;
1239
1240 if (!frba)
1241 return 0;
1242
1243 region = get_region(frba, region_type);
1244 return !!((region.base < region.limit) && (region.size > 0));
1245}
1246
Bill XIEfa5f9942017-09-12 11:22:29 +08001247static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001248{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001249 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001250 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001251 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001252 if (!fmba)
1253 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001254
1255 if (ifd_version >= IFD_VERSION_2) {
1256 wr_shift = FLMSTR_WR_SHIFT_V2;
1257 rd_shift = FLMSTR_RD_SHIFT_V2;
1258
1259 /* Clear non-reserved bits */
1260 fmba->flmstr1 &= 0xff;
1261 fmba->flmstr2 &= 0xff;
1262 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001263 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001264 } else {
1265 wr_shift = FLMSTR_WR_SHIFT_V1;
1266 rd_shift = FLMSTR_RD_SHIFT_V1;
1267
1268 fmba->flmstr1 = 0;
1269 fmba->flmstr2 = 0;
1270 /* Requestor ID */
1271 fmba->flmstr3 = 0x118;
1272 }
1273
Andrey Petrov96ecb772016-10-31 19:31:54 -07001274 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001275 case PLATFORM_APL:
1276 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001277 /* CPU/BIOS can read descriptor and BIOS */
1278 fmba->flmstr1 |= 0x3 << rd_shift;
1279 /* CPU/BIOS can write BIOS */
1280 fmba->flmstr1 |= 0x2 << wr_shift;
1281 /* TXE can read descriptor, BIOS and Device Expansion */
1282 fmba->flmstr2 |= 0x23 << rd_shift;
1283 /* TXE can only write Device Expansion */
1284 fmba->flmstr2 |= 0x20 << wr_shift;
1285 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001286 case PLATFORM_CNL:
1287 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001288 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001289 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301290 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001291 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301292 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001293 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301294 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001295 /* CPU/BIOS can read descriptor and BIOS. */
1296 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1297 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1298 /* CPU/BIOS can write BIOS. */
1299 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1300 /* ME can read descriptor and ME. */
1301 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1302 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001303 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001304 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1305 if (check_region(frba, REGION_GBE)) {
1306 /* BIOS can read/write GbE. */
1307 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1308 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1309 /* ME can read GbE. */
1310 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1311 /* GbE can read descriptor and read/write GbE.. */
1312 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1313 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1314 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1315 }
1316 if (check_region(frba, REGION_PDR)) {
1317 /* BIOS can read/write PDR. */
1318 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1319 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1320 }
1321 if (check_region(frba, REGION_EC)) {
1322 /* BIOS can read EC. */
1323 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1324 /* EC can read descriptor and read/write EC. */
1325 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1326 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1327 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1328 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001329 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001330 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001331 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001332 /* CPU/BIOS can read descriptor and BIOS. */
1333 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1334 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1335 /* CPU/BIOS can write BIOS. */
1336 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1337 /* ME can read descriptor and ME. */
1338 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1339 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1340 /* ME can write ME. */
1341 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1342 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001343 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001344 /* CPU/BIOS can read descriptor and BIOS. */
1345 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1346 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1347 /* CPU/BIOS can write BIOS. */
1348 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1349 /* ME can read descriptor and ME. */
1350 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1351 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1352 /* ME can write ME. */
1353 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1354 if (check_region(frba, REGION_GBE)) {
1355 /* BIOS can read GbE. */
1356 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1357 /* BIOS can write GbE. */
1358 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1359 /* ME can read GbE. */
1360 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1361 /* ME can write GbE. */
1362 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1363 /* GbE can write GbE. */
1364 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1365 /* GbE can read GbE. */
1366 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1367 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001368 break;
1369 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001370
1371 write_image(filename, image, size);
1372}
1373
Usha P412679d2020-10-15 11:25:08 +05301374static void enable_cpu_read_me(const char *filename, char *image, int size)
1375{
1376 int rd_shift;
1377 fmba_t *fmba = find_fmba(image, size);
1378
1379 if (!fmba)
1380 exit(EXIT_FAILURE);
1381
1382 if (ifd_version >= IFD_VERSION_2)
1383 rd_shift = FLMSTR_RD_SHIFT_V2;
1384 else
1385 rd_shift = FLMSTR_RD_SHIFT_V1;
1386
1387 /* CPU/BIOS can read ME. */
1388 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1389
1390 write_image(filename, image, size);
1391}
1392
Bill XIEfa5f9942017-09-12 11:22:29 +08001393static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001394{
Bill XIE612ec0e2017-08-30 16:10:27 +08001395 fmba_t *fmba = find_fmba(image, size);
1396 if (!fmba)
1397 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001398
1399 if (ifd_version >= IFD_VERSION_2) {
1400 /* Access bits for each region are read: 19:8 write: 31:20 */
1401 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1402 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1403 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001404 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001405 } else {
1406 fmba->flmstr1 = 0xffff0000;
1407 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001408 /* Keep chipset specific Requester ID */
1409 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001410 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001411
1412 write_image(filename, image, size);
1413}
1414
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001415static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1416 const unsigned int value)
1417{
1418 if (!fpsba || !fdb) {
1419 fprintf(stderr, "Internal error\n");
1420 exit(EXIT_FAILURE);
1421 }
1422
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001423 /* SoC Strap, aka PSL, aka ISL */
1424 int SS = (fdb->flmap1 >> 24) & 0xff;
1425 if (strap >= SS) {
1426 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001427 exit(EXIT_FAILURE);
1428 }
1429 fpsba->pchstrp[strap] = value;
1430}
1431
Bill XIEb3e15a22017-09-07 18:34:50 +08001432/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001433static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001434{
1435 if (ifd_version >= IFD_VERSION_2) {
1436 printf("%sting the HAP bit to %s Intel ME...\n",
1437 altmedisable?"Set":"Unset",
1438 altmedisable?"disable":"enable");
1439 if (altmedisable)
1440 fpsba->pchstrp[0] |= (1 << 16);
1441 else
1442 fpsba->pchstrp[0] &= ~(1 << 16);
1443 } else {
1444 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1445 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1446 "and MCH_AltMeDisable to %s Intel ME...\n",
1447 altmedisable?"Set":"Unset",
1448 altmedisable?"disable":"enable");
1449 if (altmedisable) {
1450 /* MCH_MeDisable */
1451 fmsba->data[0] |= 1;
1452 /* MCH_AltMeDisable */
1453 fmsba->data[0] |= (1 << 7);
1454 /* ICH_MeDisable */
1455 fpsba->pchstrp[0] |= 1;
1456 } else {
1457 fmsba->data[0] &= ~1;
1458 fmsba->data[0] &= ~(1 << 7);
1459 fpsba->pchstrp[0] &= ~1;
1460 }
1461 } else {
1462 printf("%sting the AltMeDisable to %s Intel ME...\n",
1463 altmedisable?"Set":"Unset",
1464 altmedisable?"disable":"enable");
1465 if (altmedisable)
1466 fpsba->pchstrp[10] |= (1 << 7);
1467 else
1468 fpsba->pchstrp[10] &= ~(1 << 7);
1469 }
1470 }
1471}
1472
Jacob Garber595d9262019-06-27 17:33:10 -06001473static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001474 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001475{
Bill XIE612ec0e2017-08-30 16:10:27 +08001476 frba_t *frba = find_frba(image, size);
1477 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001478 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001479
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001480 region_t region = get_region(frba, region_type);
1481 if (region.size <= 0xfff) {
1482 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1483 region_name(region_type));
1484 exit(EXIT_FAILURE);
1485 }
1486
Scott Duplichanf2c98372014-12-12 21:03:06 -06001487 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001488 if (region_fd == -1) {
1489 perror("Could not open file");
1490 exit(EXIT_FAILURE);
1491 }
1492 struct stat buf;
1493 if (fstat(region_fd, &buf) == -1) {
1494 perror("Could not stat file");
1495 exit(EXIT_FAILURE);
1496 }
1497 int region_size = buf.st_size;
1498
1499 printf("File %s is %d bytes\n", region_fname, region_size);
1500
1501 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001502 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001503 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1504 " bytes. Not injecting.\n",
1505 region_name(region_type), region.size,
1506 region.size, region_size, region_size);
1507 exit(EXIT_FAILURE);
1508 }
1509
1510 int offset = 0;
1511 if ((region_type == 1) && (region_size < region.size)) {
1512 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1513 " bytes. Padding before injecting.\n",
1514 region_name(region_type), region.size,
1515 region.size, region_size, region_size);
1516 offset = region.size - region_size;
1517 memset(image + region.base, 0xff, offset);
1518 }
1519
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001520 if (size < region.base + offset + region_size) {
1521 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1522 size, region.base + offset + region_size);
1523 exit(EXIT_FAILURE);
1524 }
1525
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001526 if (read(region_fd, image + region.base + offset, region_size)
1527 != region_size) {
1528 perror("Could not read file");
1529 exit(EXIT_FAILURE);
1530 }
1531
1532 close(region_fd);
1533
1534 printf("Adding %s as the %s section of %s\n",
1535 region_fname, region_name(region_type), filename);
1536 write_image(filename, image, size);
1537}
1538
Jacob Garber595d9262019-06-27 17:33:10 -06001539static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001540{
1541 unsigned int y = 1;
1542 if (x == 0)
1543 return 0;
1544 while (y <= x)
1545 y = y << 1;
1546
1547 return y;
1548}
1549
1550/**
1551 * Determine if two memory regions overlap.
1552 *
1553 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001554 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001555 * @return 1 if the two regions overlap
1556 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001557static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001558{
Bill XIEfa5f9942017-09-12 11:22:29 +08001559 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001560 return 0;
1561
Nico Huber844eda02019-01-05 00:06:19 +01001562 /* r1 should be either completely below or completely above r2 */
1563 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001564}
1565
Jacob Garber595d9262019-06-27 17:33:10 -06001566static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001567 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001568{
1569 FILE *romlayout;
1570 char tempstr[256];
1571 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001572 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001573 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001574 region_t current_regions[MAX_REGIONS];
1575 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001576 int new_extent = 0;
1577 char *new_image;
1578
1579 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001580 frba_t *frba = find_frba(image, size);
1581 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001582 exit(EXIT_FAILURE);
1583
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001584 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001585 current_regions[i] = get_region(frba, i);
1586 new_regions[i] = get_region(frba, i);
1587 }
1588
1589 /* read new layout */
1590 romlayout = fopen(layout_fname, "r");
1591
1592 if (!romlayout) {
1593 perror("Could not read layout file.\n");
1594 exit(EXIT_FAILURE);
1595 }
1596
1597 while (!feof(romlayout)) {
1598 char *tstr1, *tstr2;
1599
Patrick Georgi802ad522014-08-09 17:12:23 +02001600 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001601 layout_region_name))
1602 continue;
1603
1604 region_number = region_num(layout_region_name);
1605 if (region_number < 0)
1606 continue;
1607
1608 tstr1 = strtok(tempstr, ":");
1609 tstr2 = strtok(NULL, ":");
1610 if (!tstr1 || !tstr2) {
1611 fprintf(stderr, "Could not parse layout file.\n");
1612 exit(EXIT_FAILURE);
1613 }
1614 new_regions[region_number].base = strtol(tstr1,
1615 (char **)NULL, 16);
1616 new_regions[region_number].limit = strtol(tstr2,
1617 (char **)NULL, 16);
1618 new_regions[region_number].size =
1619 new_regions[region_number].limit -
1620 new_regions[region_number].base + 1;
1621
1622 if (new_regions[region_number].size < 0)
1623 new_regions[region_number].size = 0;
1624 }
1625 fclose(romlayout);
1626
1627 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001628 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001629 if (new_regions[i].size == 0)
1630 continue;
1631
1632 if (new_regions[i].size < current_regions[i].size) {
1633 printf("DANGER: Region %s is shrinking.\n",
1634 region_name(i));
1635 printf(" The region will be truncated to fit.\n");
1636 printf(" This may result in an unusable image.\n");
1637 }
1638
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001639 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001640 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001641 fprintf(stderr, "Regions would overlap.\n");
1642 exit(EXIT_FAILURE);
1643 }
1644 }
1645
1646 /* detect if the image size should grow */
1647 if (new_extent < new_regions[i].limit)
1648 new_extent = new_regions[i].limit;
1649 }
1650
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001651 /* check if the image is actually a Flash Descriptor region */
1652 if (size == new_regions[0].size) {
1653 printf("The image is a single Flash Descriptor:\n");
1654 printf(" Only the descriptor will be modified\n");
1655 new_extent = size;
1656 } else {
1657 new_extent = next_pow2(new_extent - 1);
1658 if (new_extent != size) {
1659 printf("The image has changed in size.\n");
1660 printf("The old image is %d bytes.\n", size);
1661 printf("The new image is %d bytes.\n", new_extent);
1662 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001663 }
1664
1665 /* copy regions to a new image */
1666 new_image = malloc(new_extent);
1667 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001668 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001669 int copy_size = new_regions[i].size;
1670 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001671 const region_t *current = &current_regions[i];
1672 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001673
Bill XIEfa5f9942017-09-12 11:22:29 +08001674 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001675 continue;
1676
Bill XIEfa5f9942017-09-12 11:22:29 +08001677 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001678 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001679 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001680 if (i == REGION_BIOS)
1681 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001682 }
1683
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001684 if ((i == REGION_BIOS) && (new->size < current->size)) {
1685 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001686 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001687 }
1688
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001689 if (size < current->base + offset_current + copy_size) {
1690 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1691 region_name(i));
1692 continue;
1693 };
1694
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001695 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1696 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001697 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1698 offset_current, current->limit, current->size);
1699 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1700 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001701
Bill XIEfa5f9942017-09-12 11:22:29 +08001702 memcpy(new_image + new->base + offset_new,
1703 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001704 copy_size);
1705 }
1706
1707 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001708 frba = find_frba(new_image, new_extent);
1709 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001710 exit(EXIT_FAILURE);
1711
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001712 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001713 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001714 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001715
1716 write_image(filename, new_image, new_extent);
1717 free(new_image);
1718}
1719
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001720static void print_version(void)
1721{
1722 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1723 printf("Copyright (C) 2011 Google Inc.\n\n");
1724 printf
1725 ("This program is free software: you can redistribute it and/or modify\n"
1726 "it under the terms of the GNU General Public License as published by\n"
1727 "the Free Software Foundation, version 2 of the License.\n\n"
1728 "This program is distributed in the hope that it will be useful,\n"
1729 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1730 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001731 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001732}
1733
1734static void print_usage(const char *name)
1735{
1736 printf("usage: %s [-vhdix?] <filename>\n", name);
1737 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001738 " -d | --dump: dump intel firmware descriptor\n"
1739 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1740 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1741 " -x | --extract: extract intel fd modules\n"
1742 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1743 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001744 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001745 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1746 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1747 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1748 " can only be used once per run:\n"
1749 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1750 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1751 " Dual Output Fast Read Support\n"
1752 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301753 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001754 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001755 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1756 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001757 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301758 " adl - Alder Lake\n"
1759 " aplk - Apollo Lake\n"
1760 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001761 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001762 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001763 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301764 " glk - Gemini Lake\n"
1765 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001766 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301767 " jsl - Jasper Lake\n"
1768 " sklkbl - Sky Lake/Kaby Lake\n"
1769 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02001770 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001771 " -S | --setpchstrap Write a PCH strap\n"
1772 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001773 " -v | --version: print the version\n"
1774 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001775 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1776 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001777 "\n");
1778}
1779
1780int main(int argc, char *argv[])
1781{
1782 int opt, option_index = 0;
1783 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001784 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001785 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301786 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001787 char *region_type_string = NULL, *region_fname = NULL;
1788 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001789 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001790 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001791 unsigned int value = 0;
1792 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001793 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001794 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1795
Bill XIEfa5f9942017-09-12 11:22:29 +08001796 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001797 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001798 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001799 {"extract", 0, NULL, 'x'},
1800 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001801 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001802 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001803 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001804 {"density", 1, NULL, 'D'},
1805 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001806 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001807 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001808 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301809 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001810 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001811 {"version", 0, NULL, 'v'},
1812 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001813 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001814 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001815 {"setpchstrap", 1, NULL, 'S'},
1816 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001817 {0, 0, 0, 0}
1818 };
1819
Usha P412679d2020-10-15 11:25:08 +05301820 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 -07001821 long_options, &option_index)) != EOF) {
1822 switch (opt) {
1823 case 'd':
1824 mode_dump = 1;
1825 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001826 case 'S':
1827 mode_setstrap = 1;
1828 pchstrap = strtoul(optarg, NULL, 0);
1829 break;
1830 case 'V':
1831 value = strtoul(optarg, NULL, 0);
1832 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001833 case 'f':
1834 mode_layout = 1;
1835 layout_fname = strdup(optarg);
1836 if (!layout_fname) {
1837 fprintf(stderr, "No layout file specified\n");
1838 print_usage(argv[0]);
1839 exit(EXIT_FAILURE);
1840 }
1841 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001842 case 'x':
1843 mode_extract = 1;
1844 break;
1845 case 'i':
1846 // separate type and file name
1847 region_type_string = strdup(optarg);
1848 region_fname = strchr(region_type_string, ':');
1849 if (!region_fname) {
1850 print_usage(argv[0]);
1851 exit(EXIT_FAILURE);
1852 }
1853 region_fname[0] = '\0';
1854 region_fname++;
1855 // Descriptor, BIOS, ME, GbE, Platform
1856 // valid type?
1857 if (!strcasecmp("Descriptor", region_type_string))
1858 region_type = 0;
1859 else if (!strcasecmp("BIOS", region_type_string))
1860 region_type = 1;
1861 else if (!strcasecmp("ME", region_type_string))
1862 region_type = 2;
1863 else if (!strcasecmp("GbE", region_type_string))
1864 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001865 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001866 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001867 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001868 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001869 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001870 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001871 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001872 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001873 else if (!strcasecmp("EC", region_type_string))
1874 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001875 else if (!strcasecmp("Device Exp2", region_type_string))
1876 region_type = 9;
1877 else if (!strcasecmp("IE", region_type_string))
1878 region_type = 10;
1879 else if (!strcasecmp("10GbE_0", region_type_string))
1880 region_type = 11;
1881 else if (!strcasecmp("10GbE_1", region_type_string))
1882 region_type = 12;
1883 else if (!strcasecmp("PTT", region_type_string))
1884 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001885 if (region_type == -1) {
1886 fprintf(stderr, "No such region type: '%s'\n\n",
1887 region_type_string);
1888 print_usage(argv[0]);
1889 exit(EXIT_FAILURE);
1890 }
1891 mode_inject = 1;
1892 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001893 case 'n':
1894 mode_newlayout = 1;
1895 layout_fname = strdup(optarg);
1896 if (!layout_fname) {
1897 fprintf(stderr, "No layout file specified\n");
1898 print_usage(argv[0]);
1899 exit(EXIT_FAILURE);
1900 }
1901 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001902 case 'O':
1903 new_filename = strdup(optarg);
1904 if (!new_filename) {
1905 fprintf(stderr, "No output filename specified\n");
1906 print_usage(argv[0]);
1907 exit(EXIT_FAILURE);
1908 }
1909 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001910 case 'D':
1911 mode_density = 1;
1912 new_density = strtoul(optarg, NULL, 0);
1913 switch (new_density) {
1914 case 512:
1915 new_density = COMPONENT_DENSITY_512KB;
1916 break;
1917 case 1:
1918 new_density = COMPONENT_DENSITY_1MB;
1919 break;
1920 case 2:
1921 new_density = COMPONENT_DENSITY_2MB;
1922 break;
1923 case 4:
1924 new_density = COMPONENT_DENSITY_4MB;
1925 break;
1926 case 8:
1927 new_density = COMPONENT_DENSITY_8MB;
1928 break;
1929 case 16:
1930 new_density = COMPONENT_DENSITY_16MB;
1931 break;
1932 case 32:
1933 new_density = COMPONENT_DENSITY_32MB;
1934 break;
1935 case 64:
1936 new_density = COMPONENT_DENSITY_64MB;
1937 break;
1938 case 0:
1939 new_density = COMPONENT_DENSITY_UNUSED;
1940 break;
1941 default:
1942 printf("error: Unknown density\n");
1943 print_usage(argv[0]);
1944 exit(EXIT_FAILURE);
1945 }
1946 break;
1947 case 'C':
1948 selected_chip = strtol(optarg, NULL, 0);
1949 if (selected_chip > 2) {
1950 fprintf(stderr, "error: Invalid chip selection\n");
1951 print_usage(argv[0]);
1952 exit(EXIT_FAILURE);
1953 }
1954 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001955 case 'M':
1956 mode_altmedisable = 1;
1957 altmedisable = strtol(optarg, NULL, 0);
1958 if (altmedisable > 1) {
1959 fprintf(stderr, "error: Illegal value\n");
1960 print_usage(argv[0]);
1961 exit(EXIT_FAILURE);
1962 }
1963 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001964 case 's':
1965 // Parse the requested SPI frequency
1966 inputfreq = strtol(optarg, NULL, 0);
1967 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001968 case 17:
1969 spifreq = SPI_FREQUENCY_17MHZ;
1970 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001971 case 20:
1972 spifreq = SPI_FREQUENCY_20MHZ;
1973 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001974 case 30:
1975 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1976 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001977 case 33:
1978 spifreq = SPI_FREQUENCY_33MHZ;
1979 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001980 case 48:
1981 spifreq = SPI_FREQUENCY_48MHZ;
1982 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001983 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001984 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001985 break;
1986 default:
1987 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1988 inputfreq);
1989 print_usage(argv[0]);
1990 exit(EXIT_FAILURE);
1991 }
1992 mode_spifreq = 1;
1993 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001994 case 'e':
1995 mode_em100 = 1;
1996 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001997 case 'l':
1998 mode_locked = 1;
1999 if (mode_unlocked == 1) {
2000 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2001 exit(EXIT_FAILURE);
2002 }
2003 break;
Usha P412679d2020-10-15 11:25:08 +05302004 case 'r':
2005 mode_read = 1;
2006 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002007 case 'u':
2008 mode_unlocked = 1;
2009 if (mode_locked == 1) {
2010 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2011 exit(EXIT_FAILURE);
2012 }
2013 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002014 case 'p':
2015 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002016 platform = PLATFORM_APL;
2017 } else if (!strcmp(optarg, "cnl")) {
2018 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002019 } else if (!strcmp(optarg, "lbg")) {
2020 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002021 } else if (!strcmp(optarg, "dnv")) {
2022 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002023 } else if (!strcmp(optarg, "ehl")) {
2024 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002025 } else if (!strcmp(optarg, "glk")) {
2026 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302027 } else if (!strcmp(optarg, "icl")) {
2028 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302029 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002030 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002031 } else if (!strcmp(optarg, "sklkbl")) {
2032 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002033 } else if (!strcmp(optarg, "tgl")) {
2034 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302035 } else if (!strcmp(optarg, "adl")) {
2036 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002037 } else if (!strcmp(optarg, "ifd2")) {
2038 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302039 } else if (!strcmp(optarg, "mtl")) {
2040 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002041 } else if (!strcmp(optarg, "wbg")) {
2042 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002043 } else {
2044 fprintf(stderr, "Unknown platform: %s\n", optarg);
2045 exit(EXIT_FAILURE);
2046 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002047 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07002048 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002049 case 't':
2050 mode_validate = 1;
2051 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002052 case 'v':
2053 print_version();
2054 exit(EXIT_SUCCESS);
2055 break;
2056 case 'h':
2057 case '?':
2058 default:
2059 print_usage(argv[0]);
2060 exit(EXIT_SUCCESS);
2061 break;
2062 }
2063 }
2064
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002065 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002066 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05002067 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002068 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002069 print_usage(argv[0]);
2070 exit(EXIT_FAILURE);
2071 }
2072
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002073 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002074 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06002075 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002076 fprintf(stderr, "You need to specify a mode.\n\n");
2077 print_usage(argv[0]);
2078 exit(EXIT_FAILURE);
2079 }
2080
2081 if (optind + 1 != argc) {
2082 fprintf(stderr, "You need to specify a file.\n\n");
2083 print_usage(argv[0]);
2084 exit(EXIT_FAILURE);
2085 }
2086
2087 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002088 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002089 if (bios_fd == -1) {
2090 perror("Could not open file");
2091 exit(EXIT_FAILURE);
2092 }
2093 struct stat buf;
2094 if (fstat(bios_fd, &buf) == -1) {
2095 perror("Could not stat file");
2096 exit(EXIT_FAILURE);
2097 }
2098 int size = buf.st_size;
2099
2100 printf("File %s is %d bytes\n", filename, size);
2101
2102 char *image = malloc(size);
2103 if (!image) {
2104 printf("Out of memory.\n");
2105 exit(EXIT_FAILURE);
2106 }
2107
2108 if (read(bios_fd, image, size) != size) {
2109 perror("Could not read file");
2110 exit(EXIT_FAILURE);
2111 }
2112
2113 close(bios_fd);
2114
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002115 // generate new filename
2116 if (new_filename == NULL) {
2117 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2118 if (!new_filename) {
2119 printf("Out of memory.\n");
2120 exit(EXIT_FAILURE);
2121 }
2122 // - 5: leave room for ".new\0"
2123 strcpy(new_filename, filename);
2124 strcat(new_filename, ".new");
2125 }
2126
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002127 check_ifd_version(image, size);
2128
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002129 if (mode_dump)
2130 dump_fd(image, size);
2131
Chris Douglass03ce0142014-02-26 13:30:13 -05002132 if (mode_layout)
2133 dump_layout(image, size, layout_fname);
2134
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002135 if (mode_extract)
2136 write_regions(image, size);
2137
Mathew Kingc7ddc992019-08-08 14:59:25 -06002138 if (mode_validate)
2139 validate_layout(image, size);
2140
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002141 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002142 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002143 region_fname);
2144
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002145 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002146 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002147
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002148 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002149 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002150
Jan Tatjefa317512016-03-11 00:52:07 +01002151 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002152 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002153
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002154 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002155 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002156
Alexander Couzensd12ea112016-09-10 13:33:05 +02002157 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002158 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002159
Usha P412679d2020-10-15 11:25:08 +05302160 if (mode_read)
2161 enable_cpu_read_me(new_filename, image, size);
2162
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002163 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002164 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002165
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002166 if (mode_setstrap) {
2167 fpsba_t *fpsba = find_fpsba(image, size);
2168 const fdbar_t *fdb = find_fd(image, size);
2169 set_pchstrap(fpsba, fdb, pchstrap, value);
2170 write_image(new_filename, image, size);
2171 }
2172
Bill XIEb3e15a22017-09-07 18:34:50 +08002173 if (mode_altmedisable) {
2174 fpsba_t *fpsba = find_fpsba(image, size);
2175 fmsba_t *fmsba = find_fmsba(image, size);
2176 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002177 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002178 }
2179
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002180 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002181 free(image);
2182
2183 return 0;
2184}