blob: 4048699242ea9c303e604311d34b570c62befca0 [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);
Subrata Banik89db2252020-08-26 14:49:17 +0530206
207 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800208 if (iccriba == 0x00) {
209 if (msl == 0 && isl <= 2)
210 return CHIPSET_ICH8;
211 else if (isl <= 2)
212 return CHIPSET_ICH9;
213 else if (isl <= 10)
214 return CHIPSET_ICH10;
215 else if (isl <= 16)
216 return CHIPSET_5_SERIES_IBEX_PEAK;
217 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
218 return CHIPSET_5_SERIES_IBEX_PEAK;
219 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
220 if (msl == 0 && isl <= 17)
221 return CHIPSET_BAYTRAIL;
222 else if (msl <= 1 && isl <= 18)
223 return CHIPSET_6_SERIES_COUGAR_POINT;
224 else if (msl <= 1 && isl <= 21)
225 return CHIPSET_8_SERIES_LYNX_POINT;
226 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
227 return CHIPSET_9_SERIES_WILDCAT_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800228 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200229 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800230}
231
Subrata Banik8c082e52021-06-10 23:02:29 +0530232static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
233{
234 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530235 case PLATFORM_APL:
236 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530237 case PLATFORM_GLK:
238 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
239 case PLATFORM_JSL:
240 return CHIPSET_N_SERIES_JASPER_LAKE;
241 case PLATFORM_EHL:
242 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200243 case PLATFORM_SKLKBL:
244 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530245 case PLATFORM_CNL:
246 return CHIPSET_300_SERIES_CANNON_POINT;
247 case PLATFORM_TGL:
248 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800249 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +0530250 case PLATFORM_MTL:
Subrata Banik8c082e52021-06-10 23:02:29 +0530251 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
252 case PLATFORM_ICL:
253 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800254 case PLATFORM_LBG:
255 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500256 case PLATFORM_DNV:
257 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200258 case PLATFORM_WBG:
259 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530260 default:
261 return CHIPSET_PCH_UNKNOWN;
262 }
263}
264
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700265/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700266 * Some newer platforms have re-defined the FCBA field that was used to
267 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
268 * have the required FCBA field, but are IFD v2 and return true if current
269 * platform is one of them.
270 */
271static int is_platform_ifd_2(void)
272{
273 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530274 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700275 PLATFORM_GLK,
276 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800277 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500278 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530279 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700280 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530281 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700282 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530283 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200284 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800285 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530286 PLATFORM_MTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200287 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700288 };
289 unsigned int i;
290
291 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
292 if (platform == ifd_2_platforms[i])
293 return 1;
294 }
295
296 return 0;
297}
298
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700299static void check_ifd_version(char *image, int size)
300{
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200301 const fdbar_t *fdb = find_fd(image, size);
302
Subrata Banik8c082e52021-06-10 23:02:29 +0530303 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530304 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200305 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
306 ifd_version = IFD_VERSION_1_5;
307 else
308 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200309 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530310 } else {
311 ifd_version = IFD_VERSION_1;
312 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200313 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530314 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700315}
316
Bill XIEfa5f9942017-09-12 11:22:29 +0800317static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700318{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500319 int base_mask;
320 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700321 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700322 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500323
324 if (ifd_version >= IFD_VERSION_2)
325 base_mask = 0x7fff;
326 else
327 base_mask = 0xfff;
328
329 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700330
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400331 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800332 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333 exit (EXIT_FAILURE);
334 }
335
Bill XIE4651d452017-09-12 11:54:48 +0800336 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700337 region.base = (flreg & base_mask) << 12;
338 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700339 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500340
Chris Douglass03ce0142014-02-26 13:30:13 -0500341 if (region.size < 0)
342 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700343
344 return region;
345}
346
Bill XIEfa5f9942017-09-12 11:22:29 +0800347static void set_region(frba_t *frba, unsigned int region_type,
348 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500349{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400350 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800351 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500352 exit (EXIT_FAILURE);
353 }
Bill XIE4651d452017-09-12 11:54:48 +0800354
355 frba->flreg[region_type] =
356 (((region->limit >> 12) & 0x7fff) << 16) |
357 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500358}
359
Bill XIEfa5f9942017-09-12 11:22:29 +0800360static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700361{
Bill XIEfa5f9942017-09-12 11:22:29 +0800362 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700363 fprintf(stderr, "Invalid region type.\n");
364 exit (EXIT_FAILURE);
365 }
366
Chris Douglass03ce0142014-02-26 13:30:13 -0500367 return region_names[region_type].pretty;
368}
369
Bill XIEfa5f9942017-09-12 11:22:29 +0800370static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500371{
Bill XIEfa5f9942017-09-12 11:22:29 +0800372 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500373 fprintf(stderr, "Invalid region type.\n");
374 exit (EXIT_FAILURE);
375 }
376
377 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700378}
379
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500380static int region_num(const char *name)
381{
Bill XIEfa5f9942017-09-12 11:22:29 +0800382 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500383
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200384 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500385 if (strcasecmp(name, region_names[i].pretty) == 0)
386 return i;
387 if (strcasecmp(name, region_names[i].terse) == 0)
388 return i;
389 }
390
391 return -1;
392}
393
Bill XIEfa5f9942017-09-12 11:22:29 +0800394static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700395{
Bill XIEfa5f9942017-09-12 11:22:29 +0800396 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700397 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700398 exit (EXIT_FAILURE);
399 }
400
Bill XIE1bf65062017-09-12 11:31:37 +0800401 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700402}
403
Bill XIEfa5f9942017-09-12 11:22:29 +0800404static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700405{
406 region_t region = get_region(frba, num);
407 printf(" Flash Region %d (%s): %08x - %08x %s\n",
408 num, region_name(num), region.base, region.limit,
409 region.size < 1 ? "(unused)" : "");
410}
411
Bill XIEfa5f9942017-09-12 11:22:29 +0800412static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
413 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500414{
415 region_t region = get_region(frba, num);
416 snprintf(buf, bufsize, "%08x:%08x %s\n",
417 region.base, region.limit, region_name_short(num));
418}
419
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200420static int sort_compare(const void *a, const void *b)
421{
422 return *(size_t *)a - *(size_t *)b;
423}
424
425/*
426 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
427 *
428 * It's platform specific which regions are used or are reserved.
429 * The 'SPI programming guide' as the name says is a guide only,
430 * not a specification what the hardware actually does.
431 * The best to do is not to rely on the guide, but detect how many
432 * regions are present in the IFD and expose them all.
433 *
434 * Very early IFDv2 chipsets, sometimes unofficially referred to as
435 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
436 * operating on an IFDv1.5 detect how much space is actually present
437 * in the IFD.
438 */
439static int max_regions_from_fdbar(const fdbar_t *fdb)
440{
441 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
442 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
443 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
444 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
445 const size_t flumap = 4096 - 256 - 4;
446 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
447
448 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
449
450 for (size_t i = 0; i < 4; i++) {
451 /*
452 * Find FRBA in the sorted array and determine the size of the
453 * region by the start of the next region. Every region requires
454 * 4 bytes of space.
455 */
456 if (sorted[i] == frba)
457 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
458 }
459 /* Never reaches this point */
460 return 0;
461}
462
Bill XIEfa5f9942017-09-12 11:22:29 +0800463static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700464{
Bill XIE4651d452017-09-12 11:54:48 +0800465 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530466 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700467 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800468 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530469 region = get_region(frba, i);
470 /* Skip unused & reserved Flash Region */
471 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
472 continue;
473
Bill XIE4651d452017-09-12 11:54:48 +0800474 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
475 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700476 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700477}
478
Bill XIEfa5f9942017-09-12 11:22:29 +0800479static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500480{
481 char buf[LAYOUT_LINELEN];
482 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800483 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500484
485 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
486 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
487 if (layout_fd == -1) {
488 perror("Could not open file");
489 exit(EXIT_FAILURE);
490 }
491
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200492 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200493 region_t region = get_region(frba, i);
494 /* is region invalid? */
495 if (region.size < 1)
496 continue;
497
Chris Douglass03ce0142014-02-26 13:30:13 -0500498 dump_region_layout(buf, bufsize, i, frba);
499 if (write(layout_fd, buf, strlen(buf)) < 0) {
500 perror("Could not write to file");
501 exit(EXIT_FAILURE);
502 }
503 }
504 close(layout_fd);
505 printf("Wrote layout to %s\n", layout_fname);
506}
507
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530508static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700509{
510 switch (freq) {
511 case SPI_FREQUENCY_20MHZ:
512 printf("20MHz");
513 break;
514 case SPI_FREQUENCY_33MHZ:
515 printf("33MHz");
516 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700517 case SPI_FREQUENCY_48MHZ:
518 printf("48MHz");
519 break;
520 case SPI_FREQUENCY_50MHZ_30MHZ:
521 switch (ifd_version) {
522 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200523 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700524 printf("50MHz");
525 break;
526 case IFD_VERSION_2:
527 printf("30MHz");
528 break;
529 }
530 break;
531 case SPI_FREQUENCY_17MHZ:
532 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700533 break;
534 default:
535 printf("unknown<%x>MHz", freq);
536 }
537}
538
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530539static void _decode_spi_frequency_500_series(unsigned int freq)
540{
541 switch (freq) {
542 case SPI_FREQUENCY_100MHZ:
543 printf("100MHz");
544 break;
545 case SPI_FREQUENCY_50MHZ:
546 printf("50MHz");
547 break;
548 case SPI_FREQUENCY_500SERIES_33MHZ:
549 printf("33MHz");
550 break;
551 case SPI_FREQUENCY_25MHZ:
552 printf("25MHz");
553 break;
554 case SPI_FREQUENCY_14MHZ:
555 printf("14MHz");
556 break;
557 default:
558 printf("unknown<%x>MHz", freq);
559 }
560}
561
562static void decode_spi_frequency(unsigned int freq)
563{
Subrata Banika5f47812020-09-29 11:43:01 +0530564 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530565 _decode_spi_frequency_500_series(freq);
566 else
567 _decode_spi_frequency(freq);
568}
569
Subrata Banike5d39922020-08-26 16:01:42 +0530570static void _decode_espi_frequency(unsigned int freq)
571{
572 switch (freq) {
573 case ESPI_FREQUENCY_20MHZ:
574 printf("20MHz");
575 break;
576 case ESPI_FREQUENCY_24MHZ:
577 printf("24MHz");
578 break;
579 case ESPI_FREQUENCY_30MHZ:
580 printf("30MHz");
581 break;
582 case ESPI_FREQUENCY_48MHZ:
583 printf("48MHz");
584 break;
585 case ESPI_FREQUENCY_60MHZ:
586 printf("60MHz");
587 break;
588 case ESPI_FREQUENCY_17MHZ:
589 printf("17MHz");
590 break;
591 default:
592 printf("unknown<%x>MHz", freq);
593 }
594}
595
596static void _decode_espi_frequency_500_series(unsigned int freq)
597{
598 switch (freq) {
599 case ESPI_FREQUENCY_500SERIES_20MHZ:
600 printf("20MHz");
601 break;
602 case ESPI_FREQUENCY_500SERIES_24MHZ:
603 printf("24MHz");
604 break;
605 case ESPI_FREQUENCY_500SERIES_25MHZ:
606 printf("25MHz");
607 break;
608 case ESPI_FREQUENCY_500SERIES_48MHZ:
609 printf("48MHz");
610 break;
611 case ESPI_FREQUENCY_500SERIES_60MHZ:
612 printf("60MHz");
613 break;
614 default:
615 printf("unknown<%x>MHz", freq);
616 }
617}
618
619static void decode_espi_frequency(unsigned int freq)
620{
Subrata Banika5f47812020-09-29 11:43:01 +0530621 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530622 _decode_espi_frequency_500_series(freq);
623 else
624 _decode_espi_frequency(freq);
625}
626
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700627static void decode_component_density(unsigned int density)
628{
629 switch (density) {
630 case COMPONENT_DENSITY_512KB:
631 printf("512KB");
632 break;
633 case COMPONENT_DENSITY_1MB:
634 printf("1MB");
635 break;
636 case COMPONENT_DENSITY_2MB:
637 printf("2MB");
638 break;
639 case COMPONENT_DENSITY_4MB:
640 printf("4MB");
641 break;
642 case COMPONENT_DENSITY_8MB:
643 printf("8MB");
644 break;
645 case COMPONENT_DENSITY_16MB:
646 printf("16MB");
647 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700648 case COMPONENT_DENSITY_32MB:
649 printf("32MB");
650 break;
651 case COMPONENT_DENSITY_64MB:
652 printf("64MB");
653 break;
654 case COMPONENT_DENSITY_UNUSED:
655 printf("UNUSED");
656 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700657 default:
658 printf("unknown<%x>MB", density);
659 }
660}
661
Subrata Banik26058dc2020-08-26 15:12:16 +0530662static int is_platform_with_pch(void)
663{
664 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
665 return 1;
666
667 return 0;
668}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530669
670/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
671static int is_platform_with_100x_series_pch(void)
672{
673 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530674 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530675 return 1;
676
677 return 0;
678}
679
Subrata Banike5d39922020-08-26 16:01:42 +0530680static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700681{
Subrata Banike5d39922020-08-26 16:01:42 +0530682 unsigned int freq;
683
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700684 printf("\nFound Component Section\n");
685 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700686 printf(" Dual Output Fast Read Support: %ssupported\n",
687 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700688 printf(" Read ID/Read Status Clock Frequency: ");
689 decode_spi_frequency((fcba->flcomp >> 27) & 7);
690 printf("\n Write/Erase Clock Frequency: ");
691 decode_spi_frequency((fcba->flcomp >> 24) & 7);
692 printf("\n Fast Read Clock Frequency: ");
693 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700694 printf("\n Fast Read Support: %ssupported",
695 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530696 if (is_platform_with_100x_series_pch() &&
697 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
698 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530699 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530700 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
701 else
702 freq = (fcba->flcomp >> 17) & 7;
703 decode_espi_frequency(freq);
704 } else {
705 printf("\n Read Clock Frequency: ");
706 decode_spi_frequency((fcba->flcomp >> 17) & 7);
707 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700708
709 switch (ifd_version) {
710 case IFD_VERSION_1:
711 printf("\n Component 2 Density: ");
712 decode_component_density((fcba->flcomp >> 3) & 7);
713 printf("\n Component 1 Density: ");
714 decode_component_density(fcba->flcomp & 7);
715 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200716 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700717 case IFD_VERSION_2:
718 printf("\n Component 2 Density: ");
719 decode_component_density((fcba->flcomp >> 4) & 0xf);
720 printf("\n Component 1 Density: ");
721 decode_component_density(fcba->flcomp & 0xf);
722 break;
723 }
724
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700725 printf("\n");
726 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700727 printf(" Invalid Instruction 3: 0x%02x\n",
728 (fcba->flill >> 24) & 0xff);
729 printf(" Invalid Instruction 2: 0x%02x\n",
730 (fcba->flill >> 16) & 0xff);
731 printf(" Invalid Instruction 1: 0x%02x\n",
732 (fcba->flill >> 8) & 0xff);
733 printf(" Invalid Instruction 0: 0x%02x\n",
734 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530735 if (is_platform_with_100x_series_pch()) {
736 printf("FLILL1 0x%08x\n", fcba->flpb);
737 printf(" Invalid Instruction 7: 0x%02x\n",
738 (fcba->flpb >> 24) & 0xff);
739 printf(" Invalid Instruction 6: 0x%02x\n",
740 (fcba->flpb >> 16) & 0xff);
741 printf(" Invalid Instruction 5: 0x%02x\n",
742 (fcba->flpb >> 8) & 0xff);
743 printf(" Invalid Instruction 4: 0x%02x\n",
744 fcba->flpb & 0xff);
745 } else {
746 printf("FLPB 0x%08x\n", fcba->flpb);
747 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
748 (fcba->flpb & 0xfff) << 12);
749 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700750}
751
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200752static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700753{
Bill XIE4651d452017-09-12 11:54:48 +0800754 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200755 /* SoC Straps, aka PSL, aka ISL */
756 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200757
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700758 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200759 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200760 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800761
762 if (ifd_version >= IFD_VERSION_2) {
763 printf("HAP bit is %sset\n",
764 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
765 } else if (chipset >= CHIPSET_ICH8
766 && chipset <= CHIPSET_ICH10) {
767 printf("ICH_MeDisable bit is %sset\n",
768 fpsba->pchstrp[0] & 1 ? "" : "not ");
769 } else {
770 printf("AltMeDisable bit is %sset\n",
771 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
772 }
773
Bill XIE4651d452017-09-12 11:54:48 +0800774 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700775}
776
777static void decode_flmstr(uint32_t flmstr)
778{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700779 int wr_shift, rd_shift;
780 if (ifd_version >= IFD_VERSION_2) {
781 wr_shift = FLMSTR_WR_SHIFT_V2;
782 rd_shift = FLMSTR_RD_SHIFT_V2;
783 } else {
784 wr_shift = FLMSTR_WR_SHIFT_V1;
785 rd_shift = FLMSTR_RD_SHIFT_V1;
786 }
787
788 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500789 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700790 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700791 (flmstr & (1 << (wr_shift + 8))) ?
792 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700793 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700794 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500795 if (PLATFORM_HAS_GBE_REGION) {
796 printf(" GbE Region Write Access: %s\n",
797 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
798 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700799 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700800 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700801 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700802 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700803 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700804 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500805 if (PLATFORM_HAS_10GBE_0_REGION) {
806 printf(" 10GbE_0 Write Access: %s\n",
807 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
808 }
809 if (PLATFORM_HAS_10GBE_1_REGION) {
810 printf(" 10GbE_1 Write Access: %s\n",
811 (flmstr & (1 << 4)) ? "enabled" : "disabled");
812 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700813
Jeff Dalyabd4b962022-01-06 00:52:30 -0500814 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700815 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700816 (flmstr & (1 << (rd_shift + 8))) ?
817 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700818 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700819 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500820 if (PLATFORM_HAS_GBE_REGION) {
821 printf(" GbE Region Read Access: %s\n",
822 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
823 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700824 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700825 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700826 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700827 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700828 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700829 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500830 if (PLATFORM_HAS_10GBE_0_REGION) {
831 printf(" 10GbE_0 Read Access: %s\n",
832 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
833 }
834 if (PLATFORM_HAS_10GBE_1_REGION) {
835 printf(" 10GbE_1 Read Access: %s\n",
836 (flmstr & (1 << 0)) ? "enabled" : "disabled");
837 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700838
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700839 /* Requestor ID doesn't exist for ifd 2 */
840 if (ifd_version < IFD_VERSION_2)
841 printf(" Requester ID: 0x%04x\n\n",
842 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700843}
844
Bill XIEfa5f9942017-09-12 11:22:29 +0800845static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700846{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700847 printf("Found Master Section\n");
848 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
849 decode_flmstr(fmba->flmstr1);
850 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
851 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500852 if (PLATFORM_HAS_GBE_REGION) {
853 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
854 decode_flmstr(fmba->flmstr3);
855 if (ifd_version >= IFD_VERSION_2) {
856 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
857 decode_flmstr(fmba->flmstr5);
858 }
859 } else {
860 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
861 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700862 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700863}
864
Bill XIEfa5f9942017-09-12 11:22:29 +0800865static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700866{
Bill XIE612ec0e2017-08-30 16:10:27 +0800867 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700868 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800869 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
870 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800871
872 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
873 printf("MCH_MeDisable bit is %sset\n",
874 fmsba->data[0] & 1 ? "" : "not ");
875 printf("MCH_AltMeDisable bit is %sset\n",
876 fmsba->data[0] & (1 << 7) ? "" : "not ");
877 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700878}
879
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700880static void dump_jid(uint32_t jid)
881{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100882 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700883 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100884 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200885 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100886 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200887 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700888}
889
890static void dump_vscc(uint32_t vscc)
891{
892 printf(" Lower Erase Opcode: 0x%02x\n",
893 vscc >> 24);
894 printf(" Lower Write Enable on Write Status: 0x%02x\n",
895 vscc & (1 << 20) ? 0x06 : 0x50);
896 printf(" Lower Write Status Required: %s\n",
897 vscc & (1 << 19) ? "Yes" : "No");
898 printf(" Lower Write Granularity: %d bytes\n",
899 vscc & (1 << 18) ? 64 : 1);
900 printf(" Lower Block / Sector Erase Size: ");
901 switch ((vscc >> 16) & 0x3) {
902 case 0:
903 printf("256 Byte\n");
904 break;
905 case 1:
906 printf("4KB\n");
907 break;
908 case 2:
909 printf("8KB\n");
910 break;
911 case 3:
912 printf("64KB\n");
913 break;
914 }
915
916 printf(" Upper Erase Opcode: 0x%02x\n",
917 (vscc >> 8) & 0xff);
918 printf(" Upper Write Enable on Write Status: 0x%02x\n",
919 vscc & (1 << 4) ? 0x06 : 0x50);
920 printf(" Upper Write Status Required: %s\n",
921 vscc & (1 << 3) ? "Yes" : "No");
922 printf(" Upper Write Granularity: %d bytes\n",
923 vscc & (1 << 2) ? 64 : 1);
924 printf(" Upper Block / Sector Erase Size: ");
925 switch (vscc & 0x3) {
926 case 0:
927 printf("256 Byte\n");
928 break;
929 case 1:
930 printf("4KB\n");
931 break;
932 case 2:
933 printf("8KB\n");
934 break;
935 case 3:
936 printf("64KB\n");
937 break;
938 }
939}
940
Bill XIEfa5f9942017-09-12 11:22:29 +0800941static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700942{
943 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200944 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
945 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700946
947 printf("ME VSCC table:\n");
948 for (i = 0; i < num; i++) {
949 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
950 dump_jid(vtba->entry[i].jid);
951 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
952 dump_vscc(vtba->entry[i].vscc);
953 }
954 printf("\n");
955}
956
Bill XIEfa5f9942017-09-12 11:22:29 +0800957static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700958{
959 int i, j;
960 printf("OEM Section:\n");
961 for (i = 0; i < 4; i++) {
962 printf("%02x:", i << 4);
963 for (j = 0; j < 16; j++)
964 printf(" %02x", oem[(i<<4)+j]);
965 printf ("\n");
966 }
967 printf ("\n");
968}
969
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700970static void dump_fd(char *image, int size)
971{
Bill XIE612ec0e2017-08-30 16:10:27 +0800972 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700973 if (!fdb)
974 exit(EXIT_FAILURE);
975
Subrata Banik26058dc2020-08-26 15:12:16 +0530976 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
977 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700978 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530979 if (!is_platform_with_100x_series_pch())
980 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700981 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
982 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
983 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
984
985 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530986 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
987 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700988 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
989 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
990 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
991
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530992 if (!is_platform_with_100x_series_pch()) {
993 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
994 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
995 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
996 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700997
Subrata Banika5f47812020-09-29 11:43:01 +0530998 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530999 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
1000 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
1001 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
1002 }
1003
Stefan Tauner0d226142018-08-05 18:56:53 +02001004 char *flumap = find_flumap(image, size);
1005 uint32_t flumap1 = *(uint32_t *)flumap;
1006 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001007 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001008 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001009 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001010 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001011 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +02001012 (image + ((flumap1 & 0xff) << 4)),
1013 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +08001014 dump_oem((const uint8_t *)image + 0xf00);
1015
1016 const frba_t *frba = find_frba(image, size);
1017 const fcba_t *fcba = find_fcba(image, size);
1018 const fpsba_t *fpsba = find_fpsba(image, size);
1019 const fmba_t *fmba = find_fmba(image, size);
1020 const fmsba_t *fmsba = find_fmsba(image, size);
1021
1022 if (frba && fcba && fpsba && fmba && fmsba) {
1023 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +05301024 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001025 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +08001026 dump_fmba(fmba);
1027 dump_fmsba(fmsba);
1028 } else {
1029 printf("FD is corrupted!\n");
1030 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001031}
1032
Bill XIEfa5f9942017-09-12 11:22:29 +08001033static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -05001034{
Bill XIE612ec0e2017-08-30 16:10:27 +08001035 const frba_t *frba = find_frba(image, size);
1036 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -05001037 exit(EXIT_FAILURE);
1038
Bill XIE612ec0e2017-08-30 16:10:27 +08001039 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05001040}
1041
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001042static void write_regions(char *image, int size)
1043{
Bill XIEfa5f9942017-09-12 11:22:29 +08001044 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +08001045 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001046
Bill XIE612ec0e2017-08-30 16:10:27 +08001047 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001048 exit(EXIT_FAILURE);
1049
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001050 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001051 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001052 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001053 if (region.size > 0) {
1054 int region_fd;
1055 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -06001056 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001057 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001058 if (region_fd < 0) {
1059 perror("Error while trying to open file");
1060 exit(EXIT_FAILURE);
1061 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001062 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001063 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001064 close(region_fd);
1065 }
1066 }
1067}
1068
Mathew Kingc7ddc992019-08-08 14:59:25 -06001069static void validate_layout(char *image, int size)
1070{
1071 uint i, errors = 0;
1072 struct fmap *fmap;
1073 long int fmap_loc = fmap_find((uint8_t *)image, size);
1074 const frba_t *frba = find_frba(image, size);
1075
1076 if (fmap_loc < 0 || !frba)
1077 exit(EXIT_FAILURE);
1078
1079 fmap = (struct fmap *)(image + fmap_loc);
1080
1081 for (i = 0; i < max_regions; i++) {
1082 if (region_names[i].fmapname == NULL)
1083 continue;
1084
1085 region_t region = get_region(frba, i);
1086
1087 if (region.size == 0)
1088 continue;
1089
1090 const struct fmap_area *area =
1091 fmap_find_area(fmap, region_names[i].fmapname);
1092
1093 if (!area)
1094 continue;
1095
1096 if ((uint)region.base != area->offset ||
1097 (uint)region.size != area->size) {
1098 printf("Region mismatch between %s and %s\n",
1099 region_names[i].terse, area->name);
1100 printf(" Descriptor region %s:\n", region_names[i].terse);
1101 printf(" offset: 0x%08x\n", region.base);
1102 printf(" length: 0x%08x\n", region.size);
1103 printf(" FMAP area %s:\n", area->name);
1104 printf(" offset: 0x%08x\n", area->offset);
1105 printf(" length: 0x%08x\n", area->size);
1106 errors++;
1107 }
1108 }
1109
1110 if (errors > 0)
1111 exit(EXIT_FAILURE);
1112}
1113
Bill XIEfa5f9942017-09-12 11:22:29 +08001114static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001115{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001116 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001117 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001118
1119 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001120 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001121 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001122 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001123 if (new_fd < 0) {
1124 perror("Error while trying to open file");
1125 exit(EXIT_FAILURE);
1126 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001127 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001128 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001129 close(new_fd);
1130}
1131
Bill XIEfa5f9942017-09-12 11:22:29 +08001132static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001133 enum spi_frequency freq)
1134{
Bill XIE612ec0e2017-08-30 16:10:27 +08001135 fcba_t *fcba = find_fcba(image, size);
1136 if (!fcba)
1137 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001138
1139 /* clear bits 21-29 */
1140 fcba->flcomp &= ~0x3fe00000;
1141 /* Read ID and Read Status Clock Frequency */
1142 fcba->flcomp |= freq << 27;
1143 /* Write and Erase Clock Frequency */
1144 fcba->flcomp |= freq << 24;
1145 /* Fast Read Clock Frequency */
1146 fcba->flcomp |= freq << 21;
1147
1148 write_image(filename, image, size);
1149}
1150
Bill XIEfa5f9942017-09-12 11:22:29 +08001151static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001152{
Bill XIE612ec0e2017-08-30 16:10:27 +08001153 fcba_t *fcba = find_fcba(image, size);
1154 if (!fcba)
1155 exit(EXIT_FAILURE);
1156
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001157 int freq;
1158
1159 switch (ifd_version) {
1160 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001161 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001162 freq = SPI_FREQUENCY_20MHZ;
1163 break;
1164 case IFD_VERSION_2:
1165 freq = SPI_FREQUENCY_17MHZ;
1166 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001167 default:
1168 freq = SPI_FREQUENCY_17MHZ;
1169 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001170 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001171
1172 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001173 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001174}
1175
Bill XIEfa5f9942017-09-12 11:22:29 +08001176static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001177 unsigned int density)
1178{
Bill XIE612ec0e2017-08-30 16:10:27 +08001179 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001180 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001181 if (!fcba)
1182 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001183
1184 printf("Setting chip density to ");
1185 decode_component_density(density);
1186 printf("\n");
1187
1188 switch (ifd_version) {
1189 case IFD_VERSION_1:
1190 /* fail if selected density is not supported by this version */
1191 if ( (density == COMPONENT_DENSITY_32MB) ||
1192 (density == COMPONENT_DENSITY_64MB) ||
1193 (density == COMPONENT_DENSITY_UNUSED) ) {
1194 printf("error: Selected density not supported in IFD version 1.\n");
1195 exit(EXIT_FAILURE);
1196 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001197 mask = 0x7;
1198 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001199 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001200 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001201 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001202 mask = 0xf;
1203 chip2_offset = 4;
1204 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001205 default:
1206 printf("error: Unknown IFD version\n");
1207 exit(EXIT_FAILURE);
1208 break;
1209 }
1210
1211 /* clear chip density for corresponding chip */
1212 switch (selected_chip) {
1213 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001214 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001215 break;
1216 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001217 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001218 break;
1219 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001220 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001221 break;
1222 }
1223
1224 /* set the new density */
1225 if (selected_chip == 1 || selected_chip == 0)
1226 fcba->flcomp |= (density); /* first chip */
1227 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001228 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001229
1230 write_image(filename, image, size);
1231}
1232
Duncan Laurie7775d672019-06-06 13:39:26 -07001233static int check_region(const frba_t *frba, unsigned int region_type)
1234{
1235 region_t region;
1236
1237 if (!frba)
1238 return 0;
1239
1240 region = get_region(frba, region_type);
1241 return !!((region.base < region.limit) && (region.size > 0));
1242}
1243
Bill XIEfa5f9942017-09-12 11:22:29 +08001244static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001245{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001246 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001247 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001248 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001249 if (!fmba)
1250 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001251
1252 if (ifd_version >= IFD_VERSION_2) {
1253 wr_shift = FLMSTR_WR_SHIFT_V2;
1254 rd_shift = FLMSTR_RD_SHIFT_V2;
1255
1256 /* Clear non-reserved bits */
1257 fmba->flmstr1 &= 0xff;
1258 fmba->flmstr2 &= 0xff;
1259 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001260 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001261 } else {
1262 wr_shift = FLMSTR_WR_SHIFT_V1;
1263 rd_shift = FLMSTR_RD_SHIFT_V1;
1264
1265 fmba->flmstr1 = 0;
1266 fmba->flmstr2 = 0;
1267 /* Requestor ID */
1268 fmba->flmstr3 = 0x118;
1269 }
1270
Andrey Petrov96ecb772016-10-31 19:31:54 -07001271 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001272 case PLATFORM_APL:
1273 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001274 /* CPU/BIOS can read descriptor and BIOS */
1275 fmba->flmstr1 |= 0x3 << rd_shift;
1276 /* CPU/BIOS can write BIOS */
1277 fmba->flmstr1 |= 0x2 << wr_shift;
1278 /* TXE can read descriptor, BIOS and Device Expansion */
1279 fmba->flmstr2 |= 0x23 << rd_shift;
1280 /* TXE can only write Device Expansion */
1281 fmba->flmstr2 |= 0x20 << wr_shift;
1282 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001283 case PLATFORM_CNL:
1284 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001285 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001286 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301287 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001288 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301289 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001290 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301291 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001292 /* CPU/BIOS can read descriptor and BIOS. */
1293 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1294 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1295 /* CPU/BIOS can write BIOS. */
1296 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1297 /* ME can read descriptor and ME. */
1298 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1299 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001300 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001301 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1302 if (check_region(frba, REGION_GBE)) {
1303 /* BIOS can read/write GbE. */
1304 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1305 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1306 /* ME can read GbE. */
1307 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1308 /* GbE can read descriptor and read/write GbE.. */
1309 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1310 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1311 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1312 }
1313 if (check_region(frba, REGION_PDR)) {
1314 /* BIOS can read/write PDR. */
1315 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1316 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1317 }
1318 if (check_region(frba, REGION_EC)) {
1319 /* BIOS can read EC. */
1320 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1321 /* EC can read descriptor and read/write EC. */
1322 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1323 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1324 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1325 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001326 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001327 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001328 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001329 /* CPU/BIOS can read descriptor and BIOS. */
1330 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1331 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1332 /* CPU/BIOS can write BIOS. */
1333 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1334 /* ME can read descriptor and ME. */
1335 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1336 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1337 /* ME can write ME. */
1338 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1339 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001340 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001341 /* CPU/BIOS can read descriptor and BIOS. */
1342 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1343 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1344 /* CPU/BIOS can write BIOS. */
1345 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1346 /* ME can read descriptor and ME. */
1347 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1348 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1349 /* ME can write ME. */
1350 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1351 if (check_region(frba, REGION_GBE)) {
1352 /* BIOS can read GbE. */
1353 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1354 /* BIOS can write GbE. */
1355 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1356 /* ME can read GbE. */
1357 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1358 /* ME can write GbE. */
1359 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1360 /* GbE can write GbE. */
1361 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1362 /* GbE can read GbE. */
1363 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1364 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001365 break;
1366 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001367
1368 write_image(filename, image, size);
1369}
1370
Usha P412679d2020-10-15 11:25:08 +05301371static void enable_cpu_read_me(const char *filename, char *image, int size)
1372{
1373 int rd_shift;
1374 fmba_t *fmba = find_fmba(image, size);
1375
1376 if (!fmba)
1377 exit(EXIT_FAILURE);
1378
1379 if (ifd_version >= IFD_VERSION_2)
1380 rd_shift = FLMSTR_RD_SHIFT_V2;
1381 else
1382 rd_shift = FLMSTR_RD_SHIFT_V1;
1383
1384 /* CPU/BIOS can read ME. */
1385 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1386
1387 write_image(filename, image, size);
1388}
1389
Bill XIEfa5f9942017-09-12 11:22:29 +08001390static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001391{
Bill XIE612ec0e2017-08-30 16:10:27 +08001392 fmba_t *fmba = find_fmba(image, size);
1393 if (!fmba)
1394 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001395
1396 if (ifd_version >= IFD_VERSION_2) {
1397 /* Access bits for each region are read: 19:8 write: 31:20 */
1398 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1399 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1400 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001401 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001402 } else {
1403 fmba->flmstr1 = 0xffff0000;
1404 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001405 /* Keep chipset specific Requester ID */
1406 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001407 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001408
1409 write_image(filename, image, size);
1410}
1411
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001412static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1413 const unsigned int value)
1414{
1415 if (!fpsba || !fdb) {
1416 fprintf(stderr, "Internal error\n");
1417 exit(EXIT_FAILURE);
1418 }
1419
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001420 /* SoC Strap, aka PSL, aka ISL */
1421 int SS = (fdb->flmap1 >> 24) & 0xff;
1422 if (strap >= SS) {
1423 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001424 exit(EXIT_FAILURE);
1425 }
1426 fpsba->pchstrp[strap] = value;
1427}
1428
Bill XIEb3e15a22017-09-07 18:34:50 +08001429/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001430static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001431{
1432 if (ifd_version >= IFD_VERSION_2) {
1433 printf("%sting the HAP bit to %s Intel ME...\n",
1434 altmedisable?"Set":"Unset",
1435 altmedisable?"disable":"enable");
1436 if (altmedisable)
1437 fpsba->pchstrp[0] |= (1 << 16);
1438 else
1439 fpsba->pchstrp[0] &= ~(1 << 16);
1440 } else {
1441 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1442 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1443 "and MCH_AltMeDisable to %s Intel ME...\n",
1444 altmedisable?"Set":"Unset",
1445 altmedisable?"disable":"enable");
1446 if (altmedisable) {
1447 /* MCH_MeDisable */
1448 fmsba->data[0] |= 1;
1449 /* MCH_AltMeDisable */
1450 fmsba->data[0] |= (1 << 7);
1451 /* ICH_MeDisable */
1452 fpsba->pchstrp[0] |= 1;
1453 } else {
1454 fmsba->data[0] &= ~1;
1455 fmsba->data[0] &= ~(1 << 7);
1456 fpsba->pchstrp[0] &= ~1;
1457 }
1458 } else {
1459 printf("%sting the AltMeDisable to %s Intel ME...\n",
1460 altmedisable?"Set":"Unset",
1461 altmedisable?"disable":"enable");
1462 if (altmedisable)
1463 fpsba->pchstrp[10] |= (1 << 7);
1464 else
1465 fpsba->pchstrp[10] &= ~(1 << 7);
1466 }
1467 }
1468}
1469
Jacob Garber595d9262019-06-27 17:33:10 -06001470static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001471 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001472{
Bill XIE612ec0e2017-08-30 16:10:27 +08001473 frba_t *frba = find_frba(image, size);
1474 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001475 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001476
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001477 region_t region = get_region(frba, region_type);
1478 if (region.size <= 0xfff) {
1479 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1480 region_name(region_type));
1481 exit(EXIT_FAILURE);
1482 }
1483
Scott Duplichanf2c98372014-12-12 21:03:06 -06001484 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001485 if (region_fd == -1) {
1486 perror("Could not open file");
1487 exit(EXIT_FAILURE);
1488 }
1489 struct stat buf;
1490 if (fstat(region_fd, &buf) == -1) {
1491 perror("Could not stat file");
1492 exit(EXIT_FAILURE);
1493 }
1494 int region_size = buf.st_size;
1495
1496 printf("File %s is %d bytes\n", region_fname, region_size);
1497
1498 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001499 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001500 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1501 " bytes. Not injecting.\n",
1502 region_name(region_type), region.size,
1503 region.size, region_size, region_size);
1504 exit(EXIT_FAILURE);
1505 }
1506
1507 int offset = 0;
1508 if ((region_type == 1) && (region_size < region.size)) {
1509 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1510 " bytes. Padding before injecting.\n",
1511 region_name(region_type), region.size,
1512 region.size, region_size, region_size);
1513 offset = region.size - region_size;
1514 memset(image + region.base, 0xff, offset);
1515 }
1516
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001517 if (size < region.base + offset + region_size) {
1518 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1519 size, region.base + offset + region_size);
1520 exit(EXIT_FAILURE);
1521 }
1522
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001523 if (read(region_fd, image + region.base + offset, region_size)
1524 != region_size) {
1525 perror("Could not read file");
1526 exit(EXIT_FAILURE);
1527 }
1528
1529 close(region_fd);
1530
1531 printf("Adding %s as the %s section of %s\n",
1532 region_fname, region_name(region_type), filename);
1533 write_image(filename, image, size);
1534}
1535
Jacob Garber595d9262019-06-27 17:33:10 -06001536static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001537{
1538 unsigned int y = 1;
1539 if (x == 0)
1540 return 0;
1541 while (y <= x)
1542 y = y << 1;
1543
1544 return y;
1545}
1546
1547/**
1548 * Determine if two memory regions overlap.
1549 *
1550 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001551 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001552 * @return 1 if the two regions overlap
1553 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001554static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001555{
Bill XIEfa5f9942017-09-12 11:22:29 +08001556 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001557 return 0;
1558
Nico Huber844eda02019-01-05 00:06:19 +01001559 /* r1 should be either completely below or completely above r2 */
1560 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001561}
1562
Jacob Garber595d9262019-06-27 17:33:10 -06001563static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001564 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001565{
1566 FILE *romlayout;
1567 char tempstr[256];
1568 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001569 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001570 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001571 region_t current_regions[MAX_REGIONS];
1572 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001573 int new_extent = 0;
1574 char *new_image;
1575
1576 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001577 frba_t *frba = find_frba(image, size);
1578 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001579 exit(EXIT_FAILURE);
1580
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001581 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001582 current_regions[i] = get_region(frba, i);
1583 new_regions[i] = get_region(frba, i);
1584 }
1585
1586 /* read new layout */
1587 romlayout = fopen(layout_fname, "r");
1588
1589 if (!romlayout) {
1590 perror("Could not read layout file.\n");
1591 exit(EXIT_FAILURE);
1592 }
1593
1594 while (!feof(romlayout)) {
1595 char *tstr1, *tstr2;
1596
Patrick Georgi802ad522014-08-09 17:12:23 +02001597 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001598 layout_region_name))
1599 continue;
1600
1601 region_number = region_num(layout_region_name);
1602 if (region_number < 0)
1603 continue;
1604
1605 tstr1 = strtok(tempstr, ":");
1606 tstr2 = strtok(NULL, ":");
1607 if (!tstr1 || !tstr2) {
1608 fprintf(stderr, "Could not parse layout file.\n");
1609 exit(EXIT_FAILURE);
1610 }
1611 new_regions[region_number].base = strtol(tstr1,
1612 (char **)NULL, 16);
1613 new_regions[region_number].limit = strtol(tstr2,
1614 (char **)NULL, 16);
1615 new_regions[region_number].size =
1616 new_regions[region_number].limit -
1617 new_regions[region_number].base + 1;
1618
1619 if (new_regions[region_number].size < 0)
1620 new_regions[region_number].size = 0;
1621 }
1622 fclose(romlayout);
1623
1624 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001625 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001626 if (new_regions[i].size == 0)
1627 continue;
1628
1629 if (new_regions[i].size < current_regions[i].size) {
1630 printf("DANGER: Region %s is shrinking.\n",
1631 region_name(i));
1632 printf(" The region will be truncated to fit.\n");
1633 printf(" This may result in an unusable image.\n");
1634 }
1635
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001636 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001637 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001638 fprintf(stderr, "Regions would overlap.\n");
1639 exit(EXIT_FAILURE);
1640 }
1641 }
1642
1643 /* detect if the image size should grow */
1644 if (new_extent < new_regions[i].limit)
1645 new_extent = new_regions[i].limit;
1646 }
1647
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001648 /* check if the image is actually a Flash Descriptor region */
1649 if (size == new_regions[0].size) {
1650 printf("The image is a single Flash Descriptor:\n");
1651 printf(" Only the descriptor will be modified\n");
1652 new_extent = size;
1653 } else {
1654 new_extent = next_pow2(new_extent - 1);
1655 if (new_extent != size) {
1656 printf("The image has changed in size.\n");
1657 printf("The old image is %d bytes.\n", size);
1658 printf("The new image is %d bytes.\n", new_extent);
1659 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001660 }
1661
1662 /* copy regions to a new image */
1663 new_image = malloc(new_extent);
1664 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001665 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001666 int copy_size = new_regions[i].size;
1667 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001668 const region_t *current = &current_regions[i];
1669 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001670
Bill XIEfa5f9942017-09-12 11:22:29 +08001671 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001672 continue;
1673
Bill XIEfa5f9942017-09-12 11:22:29 +08001674 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001675 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001676 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001677 if (i == REGION_BIOS)
1678 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001679 }
1680
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001681 if ((i == REGION_BIOS) && (new->size < current->size)) {
1682 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001683 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001684 }
1685
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001686 if (size < current->base + offset_current + copy_size) {
1687 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1688 region_name(i));
1689 continue;
1690 };
1691
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001692 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1693 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001694 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1695 offset_current, current->limit, current->size);
1696 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1697 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001698
Bill XIEfa5f9942017-09-12 11:22:29 +08001699 memcpy(new_image + new->base + offset_new,
1700 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001701 copy_size);
1702 }
1703
1704 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001705 frba = find_frba(new_image, new_extent);
1706 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001707 exit(EXIT_FAILURE);
1708
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001709 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001710 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001711 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001712
1713 write_image(filename, new_image, new_extent);
1714 free(new_image);
1715}
1716
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001717static void print_version(void)
1718{
1719 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1720 printf("Copyright (C) 2011 Google Inc.\n\n");
1721 printf
1722 ("This program is free software: you can redistribute it and/or modify\n"
1723 "it under the terms of the GNU General Public License as published by\n"
1724 "the Free Software Foundation, version 2 of the License.\n\n"
1725 "This program is distributed in the hope that it will be useful,\n"
1726 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1727 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001728 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001729}
1730
1731static void print_usage(const char *name)
1732{
1733 printf("usage: %s [-vhdix?] <filename>\n", name);
1734 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001735 " -d | --dump: dump intel firmware descriptor\n"
1736 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1737 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1738 " -x | --extract: extract intel fd modules\n"
1739 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1740 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001741 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001742 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1743 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1744 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1745 " can only be used once per run:\n"
1746 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1747 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1748 " Dual Output Fast Read Support\n"
1749 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301750 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001751 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001752 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1753 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001754 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301755 " adl - Alder Lake\n"
1756 " aplk - Apollo Lake\n"
1757 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001758 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001759 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001760 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301761 " glk - Gemini Lake\n"
1762 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001763 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301764 " jsl - Jasper Lake\n"
1765 " sklkbl - Sky Lake/Kaby Lake\n"
1766 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02001767 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001768 " -S | --setpchstrap Write a PCH strap\n"
1769 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001770 " -v | --version: print the version\n"
1771 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001772 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1773 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001774 "\n");
1775}
1776
1777int main(int argc, char *argv[])
1778{
1779 int opt, option_index = 0;
1780 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001781 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001782 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301783 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001784 char *region_type_string = NULL, *region_fname = NULL;
1785 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001786 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001787 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001788 unsigned int value = 0;
1789 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001790 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001791 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1792
Bill XIEfa5f9942017-09-12 11:22:29 +08001793 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001794 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001795 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001796 {"extract", 0, NULL, 'x'},
1797 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001798 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001799 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001800 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001801 {"density", 1, NULL, 'D'},
1802 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001803 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001804 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001805 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301806 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001807 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001808 {"version", 0, NULL, 'v'},
1809 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001810 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001811 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001812 {"setpchstrap", 1, NULL, 'S'},
1813 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001814 {0, 0, 0, 0}
1815 };
1816
Usha P412679d2020-10-15 11:25:08 +05301817 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 -07001818 long_options, &option_index)) != EOF) {
1819 switch (opt) {
1820 case 'd':
1821 mode_dump = 1;
1822 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001823 case 'S':
1824 mode_setstrap = 1;
1825 pchstrap = strtoul(optarg, NULL, 0);
1826 break;
1827 case 'V':
1828 value = strtoul(optarg, NULL, 0);
1829 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001830 case 'f':
1831 mode_layout = 1;
1832 layout_fname = strdup(optarg);
1833 if (!layout_fname) {
1834 fprintf(stderr, "No layout file specified\n");
1835 print_usage(argv[0]);
1836 exit(EXIT_FAILURE);
1837 }
1838 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001839 case 'x':
1840 mode_extract = 1;
1841 break;
1842 case 'i':
1843 // separate type and file name
1844 region_type_string = strdup(optarg);
1845 region_fname = strchr(region_type_string, ':');
1846 if (!region_fname) {
1847 print_usage(argv[0]);
1848 exit(EXIT_FAILURE);
1849 }
1850 region_fname[0] = '\0';
1851 region_fname++;
1852 // Descriptor, BIOS, ME, GbE, Platform
1853 // valid type?
1854 if (!strcasecmp("Descriptor", region_type_string))
1855 region_type = 0;
1856 else if (!strcasecmp("BIOS", region_type_string))
1857 region_type = 1;
1858 else if (!strcasecmp("ME", region_type_string))
1859 region_type = 2;
1860 else if (!strcasecmp("GbE", region_type_string))
1861 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001862 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001863 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001864 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001865 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001866 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001867 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001868 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001869 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001870 else if (!strcasecmp("EC", region_type_string))
1871 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001872 else if (!strcasecmp("Device Exp2", region_type_string))
1873 region_type = 9;
1874 else if (!strcasecmp("IE", region_type_string))
1875 region_type = 10;
1876 else if (!strcasecmp("10GbE_0", region_type_string))
1877 region_type = 11;
1878 else if (!strcasecmp("10GbE_1", region_type_string))
1879 region_type = 12;
1880 else if (!strcasecmp("PTT", region_type_string))
1881 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001882 if (region_type == -1) {
1883 fprintf(stderr, "No such region type: '%s'\n\n",
1884 region_type_string);
1885 print_usage(argv[0]);
1886 exit(EXIT_FAILURE);
1887 }
1888 mode_inject = 1;
1889 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001890 case 'n':
1891 mode_newlayout = 1;
1892 layout_fname = strdup(optarg);
1893 if (!layout_fname) {
1894 fprintf(stderr, "No layout file specified\n");
1895 print_usage(argv[0]);
1896 exit(EXIT_FAILURE);
1897 }
1898 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001899 case 'O':
1900 new_filename = strdup(optarg);
1901 if (!new_filename) {
1902 fprintf(stderr, "No output filename specified\n");
1903 print_usage(argv[0]);
1904 exit(EXIT_FAILURE);
1905 }
1906 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001907 case 'D':
1908 mode_density = 1;
1909 new_density = strtoul(optarg, NULL, 0);
1910 switch (new_density) {
1911 case 512:
1912 new_density = COMPONENT_DENSITY_512KB;
1913 break;
1914 case 1:
1915 new_density = COMPONENT_DENSITY_1MB;
1916 break;
1917 case 2:
1918 new_density = COMPONENT_DENSITY_2MB;
1919 break;
1920 case 4:
1921 new_density = COMPONENT_DENSITY_4MB;
1922 break;
1923 case 8:
1924 new_density = COMPONENT_DENSITY_8MB;
1925 break;
1926 case 16:
1927 new_density = COMPONENT_DENSITY_16MB;
1928 break;
1929 case 32:
1930 new_density = COMPONENT_DENSITY_32MB;
1931 break;
1932 case 64:
1933 new_density = COMPONENT_DENSITY_64MB;
1934 break;
1935 case 0:
1936 new_density = COMPONENT_DENSITY_UNUSED;
1937 break;
1938 default:
1939 printf("error: Unknown density\n");
1940 print_usage(argv[0]);
1941 exit(EXIT_FAILURE);
1942 }
1943 break;
1944 case 'C':
1945 selected_chip = strtol(optarg, NULL, 0);
1946 if (selected_chip > 2) {
1947 fprintf(stderr, "error: Invalid chip selection\n");
1948 print_usage(argv[0]);
1949 exit(EXIT_FAILURE);
1950 }
1951 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001952 case 'M':
1953 mode_altmedisable = 1;
1954 altmedisable = strtol(optarg, NULL, 0);
1955 if (altmedisable > 1) {
1956 fprintf(stderr, "error: Illegal value\n");
1957 print_usage(argv[0]);
1958 exit(EXIT_FAILURE);
1959 }
1960 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001961 case 's':
1962 // Parse the requested SPI frequency
1963 inputfreq = strtol(optarg, NULL, 0);
1964 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001965 case 17:
1966 spifreq = SPI_FREQUENCY_17MHZ;
1967 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001968 case 20:
1969 spifreq = SPI_FREQUENCY_20MHZ;
1970 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001971 case 30:
1972 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1973 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001974 case 33:
1975 spifreq = SPI_FREQUENCY_33MHZ;
1976 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001977 case 48:
1978 spifreq = SPI_FREQUENCY_48MHZ;
1979 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001980 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001981 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001982 break;
1983 default:
1984 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1985 inputfreq);
1986 print_usage(argv[0]);
1987 exit(EXIT_FAILURE);
1988 }
1989 mode_spifreq = 1;
1990 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001991 case 'e':
1992 mode_em100 = 1;
1993 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001994 case 'l':
1995 mode_locked = 1;
1996 if (mode_unlocked == 1) {
1997 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1998 exit(EXIT_FAILURE);
1999 }
2000 break;
Usha P412679d2020-10-15 11:25:08 +05302001 case 'r':
2002 mode_read = 1;
2003 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002004 case 'u':
2005 mode_unlocked = 1;
2006 if (mode_locked == 1) {
2007 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2008 exit(EXIT_FAILURE);
2009 }
2010 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002011 case 'p':
2012 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002013 platform = PLATFORM_APL;
2014 } else if (!strcmp(optarg, "cnl")) {
2015 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002016 } else if (!strcmp(optarg, "lbg")) {
2017 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002018 } else if (!strcmp(optarg, "dnv")) {
2019 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002020 } else if (!strcmp(optarg, "ehl")) {
2021 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002022 } else if (!strcmp(optarg, "glk")) {
2023 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302024 } else if (!strcmp(optarg, "icl")) {
2025 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302026 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002027 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002028 } else if (!strcmp(optarg, "sklkbl")) {
2029 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002030 } else if (!strcmp(optarg, "tgl")) {
2031 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302032 } else if (!strcmp(optarg, "adl")) {
2033 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002034 } else if (!strcmp(optarg, "ifd2")) {
2035 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302036 } else if (!strcmp(optarg, "mtl")) {
2037 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002038 } else if (!strcmp(optarg, "wbg")) {
2039 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002040 } else {
2041 fprintf(stderr, "Unknown platform: %s\n", optarg);
2042 exit(EXIT_FAILURE);
2043 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002044 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07002045 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002046 case 't':
2047 mode_validate = 1;
2048 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002049 case 'v':
2050 print_version();
2051 exit(EXIT_SUCCESS);
2052 break;
2053 case 'h':
2054 case '?':
2055 default:
2056 print_usage(argv[0]);
2057 exit(EXIT_SUCCESS);
2058 break;
2059 }
2060 }
2061
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002062 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002063 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05002064 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002065 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002066 print_usage(argv[0]);
2067 exit(EXIT_FAILURE);
2068 }
2069
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002070 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002071 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06002072 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002073 fprintf(stderr, "You need to specify a mode.\n\n");
2074 print_usage(argv[0]);
2075 exit(EXIT_FAILURE);
2076 }
2077
2078 if (optind + 1 != argc) {
2079 fprintf(stderr, "You need to specify a file.\n\n");
2080 print_usage(argv[0]);
2081 exit(EXIT_FAILURE);
2082 }
2083
2084 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002085 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002086 if (bios_fd == -1) {
2087 perror("Could not open file");
2088 exit(EXIT_FAILURE);
2089 }
2090 struct stat buf;
2091 if (fstat(bios_fd, &buf) == -1) {
2092 perror("Could not stat file");
2093 exit(EXIT_FAILURE);
2094 }
2095 int size = buf.st_size;
2096
2097 printf("File %s is %d bytes\n", filename, size);
2098
2099 char *image = malloc(size);
2100 if (!image) {
2101 printf("Out of memory.\n");
2102 exit(EXIT_FAILURE);
2103 }
2104
2105 if (read(bios_fd, image, size) != size) {
2106 perror("Could not read file");
2107 exit(EXIT_FAILURE);
2108 }
2109
2110 close(bios_fd);
2111
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002112 // generate new filename
2113 if (new_filename == NULL) {
2114 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2115 if (!new_filename) {
2116 printf("Out of memory.\n");
2117 exit(EXIT_FAILURE);
2118 }
2119 // - 5: leave room for ".new\0"
2120 strcpy(new_filename, filename);
2121 strcat(new_filename, ".new");
2122 }
2123
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002124 check_ifd_version(image, size);
2125
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002126 if (mode_dump)
2127 dump_fd(image, size);
2128
Chris Douglass03ce0142014-02-26 13:30:13 -05002129 if (mode_layout)
2130 dump_layout(image, size, layout_fname);
2131
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002132 if (mode_extract)
2133 write_regions(image, size);
2134
Mathew Kingc7ddc992019-08-08 14:59:25 -06002135 if (mode_validate)
2136 validate_layout(image, size);
2137
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002138 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002139 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002140 region_fname);
2141
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002142 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002143 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002144
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002145 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002146 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002147
Jan Tatjefa317512016-03-11 00:52:07 +01002148 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002149 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002150
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002151 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002152 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002153
Alexander Couzensd12ea112016-09-10 13:33:05 +02002154 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002155 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002156
Usha P412679d2020-10-15 11:25:08 +05302157 if (mode_read)
2158 enable_cpu_read_me(new_filename, image, size);
2159
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002160 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002161 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002162
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002163 if (mode_setstrap) {
2164 fpsba_t *fpsba = find_fpsba(image, size);
2165 const fdbar_t *fdb = find_fd(image, size);
2166 set_pchstrap(fpsba, fdb, pchstrap, value);
2167 write_image(new_filename, image, size);
2168 }
2169
Bill XIEb3e15a22017-09-07 18:34:50 +08002170 if (mode_altmedisable) {
2171 fpsba_t *fpsba = find_fpsba(image, size);
2172 fmsba_t *fmsba = find_fmsba(image, size);
2173 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002174 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002175 }
2176
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002177 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002178 free(image);
2179
2180 return 0;
2181}