blob: 61aedf53ef3ed73d3634b4a7f812c1d8b788ad52 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003
4#include <unistd.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <getopt.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080012#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060013#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014#include "ifdtool.h"
15
Scott Duplichanf2c98372014-12-12 21:03:06 -060016#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
Bill XIE612ec0e2017-08-30 16:10:27 +080020/**
21 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
22 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
23 * @param base: base address represented with char* type.
24 * @param limit: upper limit of the legal address.
25 *
26 */
27#define PTR_IN_RANGE(ptr, base, limit) \
28 ((const char *)(ptr) >= (base) && \
29 (const char *)&(ptr)[1] <= (base) + (limit))
30
Jeff Dalyabd4b962022-01-06 00:52:30 -050031/**
32 * PLATFORM_HAS_GBE_REGION - some platforms do not support the PCH GbE LAN region
33 */
34#define PLATFORM_HAS_GBE_REGION (platform != PLATFORM_DNV)
35
36/*
37 * PLATFORM_HAS_EC_REGION - some platforms do not support the EC region
38 */
39#define PLATFORM_HAS_EC_REGION (ifd_version >= IFD_VERSION_2 && platform != PLATFORM_DNV)
40
41/*
42 * PLATFORM_HAS_10GBE_X_REGION - some platforms have 1 or more 10GbE LAN regions
43 */
44#define PLATFORM_HAS_10GBE_0_REGION (platform == PLATFORM_DNV)
45#define PLATFORM_HAS_10GBE_1_REGION (platform == PLATFORM_DNV)
46
Patrick Rudolph98ecaa42022-10-24 15:06:15 +020047static int max_regions_from_fdbar(const fdbar_t *fdb);
48
Duncan Laurie1f7fd722015-06-22 11:14:48 -070049static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080050static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080051static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010052static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070053static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050054
Duncan Laurie1f7fd722015-06-22 11:14:48 -070055static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060056 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
57 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
58 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
59 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
60 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
Jeff Daly3623eca2022-01-05 23:51:40 -050061 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
62 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
63 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060064 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050065 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
66 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
67 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
68 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
69 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
70 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
71 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050072};
73
Bill XIEb3e15a22017-09-07 18:34:50 +080074/* port from flashrom */
75static const char *const ich_chipset_names[] = {
76 "Unknown ICH",
Bill XIEb3e15a22017-09-07 18:34:50 +080077 "ICH8",
78 "ICH9",
79 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053080 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080081 "5 series Ibex Peak",
82 "6 series Cougar Point",
83 "7 series Panther Point",
84 "8 series Lynx Point",
85 "Baytrail",
86 "8 series Lynx Point LP",
87 "8 series Wellsburg",
88 "9 series Wildcat Point",
89 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053090 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053091 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053092 "Jasper Lake: N6xxx, N51xx, N45xx",
93 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053094 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +053095 "300 series Cannon Point",
96 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +053097 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080098 "C620 series Lewisburg",
Patrick Rudolph19209002022-10-22 10:34:05 +020099 "Denverton: C39xx",
Bill XIEb3e15a22017-09-07 18:34:50 +0800100 NULL
101};
102
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700103static fdbar_t *find_fd(char *image, int size)
104{
105 int i, found = 0;
106
107 /* Scan for FD signature */
108 for (i = 0; i < (size - 4); i += 4) {
109 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
110 found = 1;
111 break; // signature found.
112 }
113 }
114
115 if (!found) {
116 printf("No Flash Descriptor found in this image\n");
117 return NULL;
118 }
119
Bill XIE612ec0e2017-08-30 16:10:27 +0800120 fdbar_t *fdb = (fdbar_t *) (image + i);
121 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
122}
123
Stefan Tauner0d226142018-08-05 18:56:53 +0200124static char *find_flumap(char *image, int size)
125{
126 /* The upper map is located in the word before the 256B-long OEM section
127 * at the end of the 4kB-long flash descriptor. In the official
128 * documentation this is defined as FDBAR + 0xEFC. However, starting
129 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
130 * has moved 16 bytes back to offset 0x10 of the image. Although
131 * official documentation still maintains the offset relative to FDBAR
132 * this is wrong and a simple fixed offset from the start of the image
133 * works.
134 */
135 char *flumap = image + 4096 - 256 - 4;
136 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
137}
138
Bill XIE612ec0e2017-08-30 16:10:27 +0800139static fcba_t *find_fcba(char *image, int size)
140{
141 fdbar_t *fdb = find_fd(image, size);
142 if (!fdb)
143 return NULL;
144 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
145 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
146
147}
148
149static fmba_t *find_fmba(char *image, int size)
150{
151 fdbar_t *fdb = find_fd(image, size);
152 if (!fdb)
153 return NULL;
154 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
155 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
156}
157
158static frba_t *find_frba(char *image, int size)
159{
160 fdbar_t *fdb = find_fd(image, size);
161 if (!fdb)
162 return NULL;
163 frba_t *frba =
164 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
165 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
166}
167
168static fpsba_t *find_fpsba(char *image, int size)
169{
170 fdbar_t *fdb = find_fd(image, size);
171 if (!fdb)
172 return NULL;
173 fpsba_t *fpsba =
174 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200175
176 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
177 if ((((char *)fpsba) + SSL) >= (image + size))
178 return NULL;
179 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800180}
181
182static fmsba_t *find_fmsba(char *image, int size)
183{
184 fdbar_t *fdb = find_fd(image, size);
185 if (!fdb)
186 return NULL;
187 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
188 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700189}
190
Bill XIEb3e15a22017-09-07 18:34:50 +0800191/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530192static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800193{
Subrata Banik8c082e52021-06-10 23:02:29 +0530194 const fdbar_t *fdb = find_fd(image, size);
195 if (!fdb)
196 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800197 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
198 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
199 uint32_t isl = (fdb->flmap1 >> 24);
Subrata Banik89db2252020-08-26 14:49:17 +0530200
201 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800202 if (iccriba == 0x00) {
203 if (msl == 0 && isl <= 2)
204 return CHIPSET_ICH8;
205 else if (isl <= 2)
206 return CHIPSET_ICH9;
207 else if (isl <= 10)
208 return CHIPSET_ICH10;
209 else if (isl <= 16)
210 return CHIPSET_5_SERIES_IBEX_PEAK;
211 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
212 return CHIPSET_5_SERIES_IBEX_PEAK;
213 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
214 if (msl == 0 && isl <= 17)
215 return CHIPSET_BAYTRAIL;
216 else if (msl <= 1 && isl <= 18)
217 return CHIPSET_6_SERIES_COUGAR_POINT;
218 else if (msl <= 1 && isl <= 21)
219 return CHIPSET_8_SERIES_LYNX_POINT;
220 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
221 return CHIPSET_9_SERIES_WILDCAT_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800222 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200223 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800224}
225
Subrata Banik8c082e52021-06-10 23:02:29 +0530226static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
227{
228 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530229 case PLATFORM_APL:
230 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530231 case PLATFORM_GLK:
232 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
233 case PLATFORM_JSL:
234 return CHIPSET_N_SERIES_JASPER_LAKE;
235 case PLATFORM_EHL:
236 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200237 case PLATFORM_SKLKBL:
238 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530239 case PLATFORM_CNL:
240 return CHIPSET_300_SERIES_CANNON_POINT;
241 case PLATFORM_TGL:
242 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800243 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +0530244 case PLATFORM_MTL:
Subrata Banik8c082e52021-06-10 23:02:29 +0530245 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
246 case PLATFORM_ICL:
247 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800248 case PLATFORM_LBG:
249 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500250 case PLATFORM_DNV:
251 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200252 case PLATFORM_WBG:
253 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530254 default:
255 return CHIPSET_PCH_UNKNOWN;
256 }
257}
258
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700259/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700260 * Some newer platforms have re-defined the FCBA field that was used to
261 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
262 * have the required FCBA field, but are IFD v2 and return true if current
263 * platform is one of them.
264 */
265static int is_platform_ifd_2(void)
266{
267 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530268 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700269 PLATFORM_GLK,
270 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800271 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500272 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530273 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700274 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530275 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700276 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530277 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200278 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800279 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530280 PLATFORM_MTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200281 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700282 };
283 unsigned int i;
284
285 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
286 if (platform == ifd_2_platforms[i])
287 return 1;
288 }
289
290 return 0;
291}
292
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700293static void check_ifd_version(char *image, int size)
294{
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200295 const fdbar_t *fdb = find_fd(image, size);
296
Subrata Banik8c082e52021-06-10 23:02:29 +0530297 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530298 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200299 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
300 ifd_version = IFD_VERSION_1_5;
301 else
302 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200303 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530304 } else {
305 ifd_version = IFD_VERSION_1;
306 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200307 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530308 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700309}
310
Bill XIEfa5f9942017-09-12 11:22:29 +0800311static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700312{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500313 int base_mask;
314 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700315 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500317
318 if (ifd_version >= IFD_VERSION_2)
319 base_mask = 0x7fff;
320 else
321 base_mask = 0xfff;
322
323 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700324
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400325 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800326 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700327 exit (EXIT_FAILURE);
328 }
329
Bill XIE4651d452017-09-12 11:54:48 +0800330 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700331 region.base = (flreg & base_mask) << 12;
332 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500334
Chris Douglass03ce0142014-02-26 13:30:13 -0500335 if (region.size < 0)
336 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700337
338 return region;
339}
340
Bill XIEfa5f9942017-09-12 11:22:29 +0800341static void set_region(frba_t *frba, unsigned int region_type,
342 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500343{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400344 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800345 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500346 exit (EXIT_FAILURE);
347 }
Bill XIE4651d452017-09-12 11:54:48 +0800348
349 frba->flreg[region_type] =
350 (((region->limit >> 12) & 0x7fff) << 16) |
351 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500352}
353
Bill XIEfa5f9942017-09-12 11:22:29 +0800354static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355{
Bill XIEfa5f9942017-09-12 11:22:29 +0800356 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700357 fprintf(stderr, "Invalid region type.\n");
358 exit (EXIT_FAILURE);
359 }
360
Chris Douglass03ce0142014-02-26 13:30:13 -0500361 return region_names[region_type].pretty;
362}
363
Bill XIEfa5f9942017-09-12 11:22:29 +0800364static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500365{
Bill XIEfa5f9942017-09-12 11:22:29 +0800366 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500367 fprintf(stderr, "Invalid region type.\n");
368 exit (EXIT_FAILURE);
369 }
370
371 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700372}
373
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500374static int region_num(const char *name)
375{
Bill XIEfa5f9942017-09-12 11:22:29 +0800376 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500377
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200378 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500379 if (strcasecmp(name, region_names[i].pretty) == 0)
380 return i;
381 if (strcasecmp(name, region_names[i].terse) == 0)
382 return i;
383 }
384
385 return -1;
386}
387
Bill XIEfa5f9942017-09-12 11:22:29 +0800388static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700389{
Bill XIEfa5f9942017-09-12 11:22:29 +0800390 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700391 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700392 exit (EXIT_FAILURE);
393 }
394
Bill XIE1bf65062017-09-12 11:31:37 +0800395 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700396}
397
Bill XIEfa5f9942017-09-12 11:22:29 +0800398static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700399{
400 region_t region = get_region(frba, num);
401 printf(" Flash Region %d (%s): %08x - %08x %s\n",
402 num, region_name(num), region.base, region.limit,
403 region.size < 1 ? "(unused)" : "");
404}
405
Bill XIEfa5f9942017-09-12 11:22:29 +0800406static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
407 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500408{
409 region_t region = get_region(frba, num);
410 snprintf(buf, bufsize, "%08x:%08x %s\n",
411 region.base, region.limit, region_name_short(num));
412}
413
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200414static int sort_compare(const void *a, const void *b)
415{
416 return *(size_t *)a - *(size_t *)b;
417}
418
419/*
420 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
421 *
422 * It's platform specific which regions are used or are reserved.
423 * The 'SPI programming guide' as the name says is a guide only,
424 * not a specification what the hardware actually does.
425 * The best to do is not to rely on the guide, but detect how many
426 * regions are present in the IFD and expose them all.
427 *
428 * Very early IFDv2 chipsets, sometimes unofficially referred to as
429 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
430 * operating on an IFDv1.5 detect how much space is actually present
431 * in the IFD.
432 */
433static int max_regions_from_fdbar(const fdbar_t *fdb)
434{
435 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
436 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
437 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
438 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
439 const size_t flumap = 4096 - 256 - 4;
440 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
441
442 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
443
444 for (size_t i = 0; i < 4; i++) {
445 /*
446 * Find FRBA in the sorted array and determine the size of the
447 * region by the start of the next region. Every region requires
448 * 4 bytes of space.
449 */
450 if (sorted[i] == frba)
451 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
452 }
453 /* Never reaches this point */
454 return 0;
455}
456
Bill XIEfa5f9942017-09-12 11:22:29 +0800457static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700458{
Bill XIE4651d452017-09-12 11:54:48 +0800459 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530460 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700461 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800462 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530463 region = get_region(frba, i);
464 /* Skip unused & reserved Flash Region */
465 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
466 continue;
467
Bill XIE4651d452017-09-12 11:54:48 +0800468 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
469 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700470 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700471}
472
Bill XIEfa5f9942017-09-12 11:22:29 +0800473static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500474{
475 char buf[LAYOUT_LINELEN];
476 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800477 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500478
479 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
480 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
481 if (layout_fd == -1) {
482 perror("Could not open file");
483 exit(EXIT_FAILURE);
484 }
485
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200486 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200487 region_t region = get_region(frba, i);
488 /* is region invalid? */
489 if (region.size < 1)
490 continue;
491
Chris Douglass03ce0142014-02-26 13:30:13 -0500492 dump_region_layout(buf, bufsize, i, frba);
493 if (write(layout_fd, buf, strlen(buf)) < 0) {
494 perror("Could not write to file");
495 exit(EXIT_FAILURE);
496 }
497 }
498 close(layout_fd);
499 printf("Wrote layout to %s\n", layout_fname);
500}
501
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530502static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700503{
504 switch (freq) {
505 case SPI_FREQUENCY_20MHZ:
506 printf("20MHz");
507 break;
508 case SPI_FREQUENCY_33MHZ:
509 printf("33MHz");
510 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700511 case SPI_FREQUENCY_48MHZ:
512 printf("48MHz");
513 break;
514 case SPI_FREQUENCY_50MHZ_30MHZ:
515 switch (ifd_version) {
516 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200517 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700518 printf("50MHz");
519 break;
520 case IFD_VERSION_2:
521 printf("30MHz");
522 break;
523 }
524 break;
525 case SPI_FREQUENCY_17MHZ:
526 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700527 break;
528 default:
529 printf("unknown<%x>MHz", freq);
530 }
531}
532
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530533static void _decode_spi_frequency_500_series(unsigned int freq)
534{
535 switch (freq) {
536 case SPI_FREQUENCY_100MHZ:
537 printf("100MHz");
538 break;
539 case SPI_FREQUENCY_50MHZ:
540 printf("50MHz");
541 break;
542 case SPI_FREQUENCY_500SERIES_33MHZ:
543 printf("33MHz");
544 break;
545 case SPI_FREQUENCY_25MHZ:
546 printf("25MHz");
547 break;
548 case SPI_FREQUENCY_14MHZ:
549 printf("14MHz");
550 break;
551 default:
552 printf("unknown<%x>MHz", freq);
553 }
554}
555
556static void decode_spi_frequency(unsigned int freq)
557{
Subrata Banika5f47812020-09-29 11:43:01 +0530558 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530559 _decode_spi_frequency_500_series(freq);
560 else
561 _decode_spi_frequency(freq);
562}
563
Subrata Banike5d39922020-08-26 16:01:42 +0530564static void _decode_espi_frequency(unsigned int freq)
565{
566 switch (freq) {
567 case ESPI_FREQUENCY_20MHZ:
568 printf("20MHz");
569 break;
570 case ESPI_FREQUENCY_24MHZ:
571 printf("24MHz");
572 break;
573 case ESPI_FREQUENCY_30MHZ:
574 printf("30MHz");
575 break;
576 case ESPI_FREQUENCY_48MHZ:
577 printf("48MHz");
578 break;
579 case ESPI_FREQUENCY_60MHZ:
580 printf("60MHz");
581 break;
582 case ESPI_FREQUENCY_17MHZ:
583 printf("17MHz");
584 break;
585 default:
586 printf("unknown<%x>MHz", freq);
587 }
588}
589
590static void _decode_espi_frequency_500_series(unsigned int freq)
591{
592 switch (freq) {
593 case ESPI_FREQUENCY_500SERIES_20MHZ:
594 printf("20MHz");
595 break;
596 case ESPI_FREQUENCY_500SERIES_24MHZ:
597 printf("24MHz");
598 break;
599 case ESPI_FREQUENCY_500SERIES_25MHZ:
600 printf("25MHz");
601 break;
602 case ESPI_FREQUENCY_500SERIES_48MHZ:
603 printf("48MHz");
604 break;
605 case ESPI_FREQUENCY_500SERIES_60MHZ:
606 printf("60MHz");
607 break;
608 default:
609 printf("unknown<%x>MHz", freq);
610 }
611}
612
613static void decode_espi_frequency(unsigned int freq)
614{
Subrata Banika5f47812020-09-29 11:43:01 +0530615 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530616 _decode_espi_frequency_500_series(freq);
617 else
618 _decode_espi_frequency(freq);
619}
620
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700621static void decode_component_density(unsigned int density)
622{
623 switch (density) {
624 case COMPONENT_DENSITY_512KB:
625 printf("512KB");
626 break;
627 case COMPONENT_DENSITY_1MB:
628 printf("1MB");
629 break;
630 case COMPONENT_DENSITY_2MB:
631 printf("2MB");
632 break;
633 case COMPONENT_DENSITY_4MB:
634 printf("4MB");
635 break;
636 case COMPONENT_DENSITY_8MB:
637 printf("8MB");
638 break;
639 case COMPONENT_DENSITY_16MB:
640 printf("16MB");
641 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700642 case COMPONENT_DENSITY_32MB:
643 printf("32MB");
644 break;
645 case COMPONENT_DENSITY_64MB:
646 printf("64MB");
647 break;
648 case COMPONENT_DENSITY_UNUSED:
649 printf("UNUSED");
650 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700651 default:
652 printf("unknown<%x>MB", density);
653 }
654}
655
Subrata Banik26058dc2020-08-26 15:12:16 +0530656static int is_platform_with_pch(void)
657{
658 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
659 return 1;
660
661 return 0;
662}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530663
664/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
665static int is_platform_with_100x_series_pch(void)
666{
667 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530668 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530669 return 1;
670
671 return 0;
672}
673
Subrata Banike5d39922020-08-26 16:01:42 +0530674static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700675{
Subrata Banike5d39922020-08-26 16:01:42 +0530676 unsigned int freq;
677
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700678 printf("\nFound Component Section\n");
679 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700680 printf(" Dual Output Fast Read Support: %ssupported\n",
681 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700682 printf(" Read ID/Read Status Clock Frequency: ");
683 decode_spi_frequency((fcba->flcomp >> 27) & 7);
684 printf("\n Write/Erase Clock Frequency: ");
685 decode_spi_frequency((fcba->flcomp >> 24) & 7);
686 printf("\n Fast Read Clock Frequency: ");
687 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700688 printf("\n Fast Read Support: %ssupported",
689 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530690 if (is_platform_with_100x_series_pch() &&
691 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
692 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530693 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530694 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
695 else
696 freq = (fcba->flcomp >> 17) & 7;
697 decode_espi_frequency(freq);
698 } else {
699 printf("\n Read Clock Frequency: ");
700 decode_spi_frequency((fcba->flcomp >> 17) & 7);
701 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700702
703 switch (ifd_version) {
704 case IFD_VERSION_1:
705 printf("\n Component 2 Density: ");
706 decode_component_density((fcba->flcomp >> 3) & 7);
707 printf("\n Component 1 Density: ");
708 decode_component_density(fcba->flcomp & 7);
709 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200710 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700711 case IFD_VERSION_2:
712 printf("\n Component 2 Density: ");
713 decode_component_density((fcba->flcomp >> 4) & 0xf);
714 printf("\n Component 1 Density: ");
715 decode_component_density(fcba->flcomp & 0xf);
716 break;
717 }
718
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700719 printf("\n");
720 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700721 printf(" Invalid Instruction 3: 0x%02x\n",
722 (fcba->flill >> 24) & 0xff);
723 printf(" Invalid Instruction 2: 0x%02x\n",
724 (fcba->flill >> 16) & 0xff);
725 printf(" Invalid Instruction 1: 0x%02x\n",
726 (fcba->flill >> 8) & 0xff);
727 printf(" Invalid Instruction 0: 0x%02x\n",
728 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530729 if (is_platform_with_100x_series_pch()) {
730 printf("FLILL1 0x%08x\n", fcba->flpb);
731 printf(" Invalid Instruction 7: 0x%02x\n",
732 (fcba->flpb >> 24) & 0xff);
733 printf(" Invalid Instruction 6: 0x%02x\n",
734 (fcba->flpb >> 16) & 0xff);
735 printf(" Invalid Instruction 5: 0x%02x\n",
736 (fcba->flpb >> 8) & 0xff);
737 printf(" Invalid Instruction 4: 0x%02x\n",
738 fcba->flpb & 0xff);
739 } else {
740 printf("FLPB 0x%08x\n", fcba->flpb);
741 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
742 (fcba->flpb & 0xfff) << 12);
743 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700744}
745
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200746static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700747{
Bill XIE4651d452017-09-12 11:54:48 +0800748 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200749 /* SoC Straps, aka PSL, aka ISL */
750 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200751
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700752 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200753 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200754 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800755
756 if (ifd_version >= IFD_VERSION_2) {
757 printf("HAP bit is %sset\n",
758 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
759 } else if (chipset >= CHIPSET_ICH8
760 && chipset <= CHIPSET_ICH10) {
761 printf("ICH_MeDisable bit is %sset\n",
762 fpsba->pchstrp[0] & 1 ? "" : "not ");
763 } else {
764 printf("AltMeDisable bit is %sset\n",
765 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
766 }
767
Bill XIE4651d452017-09-12 11:54:48 +0800768 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700769}
770
771static void decode_flmstr(uint32_t flmstr)
772{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700773 int wr_shift, rd_shift;
774 if (ifd_version >= IFD_VERSION_2) {
775 wr_shift = FLMSTR_WR_SHIFT_V2;
776 rd_shift = FLMSTR_RD_SHIFT_V2;
777 } else {
778 wr_shift = FLMSTR_WR_SHIFT_V1;
779 rd_shift = FLMSTR_RD_SHIFT_V1;
780 }
781
782 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500783 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700784 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700785 (flmstr & (1 << (wr_shift + 8))) ?
786 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700787 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700788 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500789 if (PLATFORM_HAS_GBE_REGION) {
790 printf(" GbE Region Write Access: %s\n",
791 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
792 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700793 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700794 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700795 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700796 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700797 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700798 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500799 if (PLATFORM_HAS_10GBE_0_REGION) {
800 printf(" 10GbE_0 Write Access: %s\n",
801 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
802 }
803 if (PLATFORM_HAS_10GBE_1_REGION) {
804 printf(" 10GbE_1 Write Access: %s\n",
805 (flmstr & (1 << 4)) ? "enabled" : "disabled");
806 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700807
Jeff Dalyabd4b962022-01-06 00:52:30 -0500808 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700809 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700810 (flmstr & (1 << (rd_shift + 8))) ?
811 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700812 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700813 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500814 if (PLATFORM_HAS_GBE_REGION) {
815 printf(" GbE Region Read Access: %s\n",
816 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
817 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700818 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700819 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700820 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700821 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700822 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700823 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500824 if (PLATFORM_HAS_10GBE_0_REGION) {
825 printf(" 10GbE_0 Read Access: %s\n",
826 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
827 }
828 if (PLATFORM_HAS_10GBE_1_REGION) {
829 printf(" 10GbE_1 Read Access: %s\n",
830 (flmstr & (1 << 0)) ? "enabled" : "disabled");
831 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700832
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700833 /* Requestor ID doesn't exist for ifd 2 */
834 if (ifd_version < IFD_VERSION_2)
835 printf(" Requester ID: 0x%04x\n\n",
836 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700837}
838
Bill XIEfa5f9942017-09-12 11:22:29 +0800839static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700840{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700841 printf("Found Master Section\n");
842 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
843 decode_flmstr(fmba->flmstr1);
844 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
845 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500846 if (PLATFORM_HAS_GBE_REGION) {
847 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
848 decode_flmstr(fmba->flmstr3);
849 if (ifd_version >= IFD_VERSION_2) {
850 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
851 decode_flmstr(fmba->flmstr5);
852 }
853 } else {
854 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
855 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700856 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700857}
858
Bill XIEfa5f9942017-09-12 11:22:29 +0800859static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700860{
Bill XIE612ec0e2017-08-30 16:10:27 +0800861 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700862 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800863 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
864 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800865
866 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
867 printf("MCH_MeDisable bit is %sset\n",
868 fmsba->data[0] & 1 ? "" : "not ");
869 printf("MCH_AltMeDisable bit is %sset\n",
870 fmsba->data[0] & (1 << 7) ? "" : "not ");
871 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700872}
873
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700874static void dump_jid(uint32_t jid)
875{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100876 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700877 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100878 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200879 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100880 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200881 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700882}
883
884static void dump_vscc(uint32_t vscc)
885{
886 printf(" Lower Erase Opcode: 0x%02x\n",
887 vscc >> 24);
888 printf(" Lower Write Enable on Write Status: 0x%02x\n",
889 vscc & (1 << 20) ? 0x06 : 0x50);
890 printf(" Lower Write Status Required: %s\n",
891 vscc & (1 << 19) ? "Yes" : "No");
892 printf(" Lower Write Granularity: %d bytes\n",
893 vscc & (1 << 18) ? 64 : 1);
894 printf(" Lower Block / Sector Erase Size: ");
895 switch ((vscc >> 16) & 0x3) {
896 case 0:
897 printf("256 Byte\n");
898 break;
899 case 1:
900 printf("4KB\n");
901 break;
902 case 2:
903 printf("8KB\n");
904 break;
905 case 3:
906 printf("64KB\n");
907 break;
908 }
909
910 printf(" Upper Erase Opcode: 0x%02x\n",
911 (vscc >> 8) & 0xff);
912 printf(" Upper Write Enable on Write Status: 0x%02x\n",
913 vscc & (1 << 4) ? 0x06 : 0x50);
914 printf(" Upper Write Status Required: %s\n",
915 vscc & (1 << 3) ? "Yes" : "No");
916 printf(" Upper Write Granularity: %d bytes\n",
917 vscc & (1 << 2) ? 64 : 1);
918 printf(" Upper Block / Sector Erase Size: ");
919 switch (vscc & 0x3) {
920 case 0:
921 printf("256 Byte\n");
922 break;
923 case 1:
924 printf("4KB\n");
925 break;
926 case 2:
927 printf("8KB\n");
928 break;
929 case 3:
930 printf("64KB\n");
931 break;
932 }
933}
934
Bill XIEfa5f9942017-09-12 11:22:29 +0800935static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700936{
937 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200938 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
939 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700940
941 printf("ME VSCC table:\n");
942 for (i = 0; i < num; i++) {
943 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
944 dump_jid(vtba->entry[i].jid);
945 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
946 dump_vscc(vtba->entry[i].vscc);
947 }
948 printf("\n");
949}
950
Bill XIEfa5f9942017-09-12 11:22:29 +0800951static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700952{
953 int i, j;
954 printf("OEM Section:\n");
955 for (i = 0; i < 4; i++) {
956 printf("%02x:", i << 4);
957 for (j = 0; j < 16; j++)
958 printf(" %02x", oem[(i<<4)+j]);
959 printf ("\n");
960 }
961 printf ("\n");
962}
963
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700964static void dump_fd(char *image, int size)
965{
Bill XIE612ec0e2017-08-30 16:10:27 +0800966 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700967 if (!fdb)
968 exit(EXIT_FAILURE);
969
Subrata Banik26058dc2020-08-26 15:12:16 +0530970 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
971 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700972 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530973 if (!is_platform_with_100x_series_pch())
974 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700975 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
976 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
977 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
978
979 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530980 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
981 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700982 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
983 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
984 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
985
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530986 if (!is_platform_with_100x_series_pch()) {
987 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
988 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
989 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
990 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700991
Subrata Banika5f47812020-09-29 11:43:01 +0530992 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530993 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
994 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
995 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
996 }
997
Stefan Tauner0d226142018-08-05 18:56:53 +0200998 char *flumap = find_flumap(image, size);
999 uint32_t flumap1 = *(uint32_t *)flumap;
1000 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001001 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001002 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001003 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001004 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001005 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +02001006 (image + ((flumap1 & 0xff) << 4)),
1007 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +08001008 dump_oem((const uint8_t *)image + 0xf00);
1009
1010 const frba_t *frba = find_frba(image, size);
1011 const fcba_t *fcba = find_fcba(image, size);
1012 const fpsba_t *fpsba = find_fpsba(image, size);
1013 const fmba_t *fmba = find_fmba(image, size);
1014 const fmsba_t *fmsba = find_fmsba(image, size);
1015
1016 if (frba && fcba && fpsba && fmba && fmsba) {
1017 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +05301018 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001019 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +08001020 dump_fmba(fmba);
1021 dump_fmsba(fmsba);
1022 } else {
1023 printf("FD is corrupted!\n");
1024 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001025}
1026
Bill XIEfa5f9942017-09-12 11:22:29 +08001027static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -05001028{
Bill XIE612ec0e2017-08-30 16:10:27 +08001029 const frba_t *frba = find_frba(image, size);
1030 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -05001031 exit(EXIT_FAILURE);
1032
Bill XIE612ec0e2017-08-30 16:10:27 +08001033 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05001034}
1035
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001036static void write_regions(char *image, int size)
1037{
Bill XIEfa5f9942017-09-12 11:22:29 +08001038 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +08001039 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001040
Bill XIE612ec0e2017-08-30 16:10:27 +08001041 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001042 exit(EXIT_FAILURE);
1043
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001044 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001045 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001046 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001047 if (region.size > 0) {
1048 int region_fd;
1049 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -06001050 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001051 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001052 if (region_fd < 0) {
1053 perror("Error while trying to open file");
1054 exit(EXIT_FAILURE);
1055 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001056 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001057 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001058 close(region_fd);
1059 }
1060 }
1061}
1062
Mathew Kingc7ddc992019-08-08 14:59:25 -06001063static void validate_layout(char *image, int size)
1064{
1065 uint i, errors = 0;
1066 struct fmap *fmap;
1067 long int fmap_loc = fmap_find((uint8_t *)image, size);
1068 const frba_t *frba = find_frba(image, size);
1069
1070 if (fmap_loc < 0 || !frba)
1071 exit(EXIT_FAILURE);
1072
1073 fmap = (struct fmap *)(image + fmap_loc);
1074
1075 for (i = 0; i < max_regions; i++) {
1076 if (region_names[i].fmapname == NULL)
1077 continue;
1078
1079 region_t region = get_region(frba, i);
1080
1081 if (region.size == 0)
1082 continue;
1083
1084 const struct fmap_area *area =
1085 fmap_find_area(fmap, region_names[i].fmapname);
1086
1087 if (!area)
1088 continue;
1089
1090 if ((uint)region.base != area->offset ||
1091 (uint)region.size != area->size) {
1092 printf("Region mismatch between %s and %s\n",
1093 region_names[i].terse, area->name);
1094 printf(" Descriptor region %s:\n", region_names[i].terse);
1095 printf(" offset: 0x%08x\n", region.base);
1096 printf(" length: 0x%08x\n", region.size);
1097 printf(" FMAP area %s:\n", area->name);
1098 printf(" offset: 0x%08x\n", area->offset);
1099 printf(" length: 0x%08x\n", area->size);
1100 errors++;
1101 }
1102 }
1103
1104 if (errors > 0)
1105 exit(EXIT_FAILURE);
1106}
1107
Bill XIEfa5f9942017-09-12 11:22:29 +08001108static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001109{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001110 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001111 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001112
1113 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001114 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001115 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001116 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001117 if (new_fd < 0) {
1118 perror("Error while trying to open file");
1119 exit(EXIT_FAILURE);
1120 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001121 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001122 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001123 close(new_fd);
1124}
1125
Bill XIEfa5f9942017-09-12 11:22:29 +08001126static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001127 enum spi_frequency freq)
1128{
Bill XIE612ec0e2017-08-30 16:10:27 +08001129 fcba_t *fcba = find_fcba(image, size);
1130 if (!fcba)
1131 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001132
1133 /* clear bits 21-29 */
1134 fcba->flcomp &= ~0x3fe00000;
1135 /* Read ID and Read Status Clock Frequency */
1136 fcba->flcomp |= freq << 27;
1137 /* Write and Erase Clock Frequency */
1138 fcba->flcomp |= freq << 24;
1139 /* Fast Read Clock Frequency */
1140 fcba->flcomp |= freq << 21;
1141
1142 write_image(filename, image, size);
1143}
1144
Bill XIEfa5f9942017-09-12 11:22:29 +08001145static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001146{
Bill XIE612ec0e2017-08-30 16:10:27 +08001147 fcba_t *fcba = find_fcba(image, size);
1148 if (!fcba)
1149 exit(EXIT_FAILURE);
1150
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001151 int freq;
1152
1153 switch (ifd_version) {
1154 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001155 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001156 freq = SPI_FREQUENCY_20MHZ;
1157 break;
1158 case IFD_VERSION_2:
1159 freq = SPI_FREQUENCY_17MHZ;
1160 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001161 default:
1162 freq = SPI_FREQUENCY_17MHZ;
1163 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001164 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001165
1166 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001167 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001168}
1169
Bill XIEfa5f9942017-09-12 11:22:29 +08001170static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001171 unsigned int density)
1172{
Bill XIE612ec0e2017-08-30 16:10:27 +08001173 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001174 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001175 if (!fcba)
1176 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001177
1178 printf("Setting chip density to ");
1179 decode_component_density(density);
1180 printf("\n");
1181
1182 switch (ifd_version) {
1183 case IFD_VERSION_1:
1184 /* fail if selected density is not supported by this version */
1185 if ( (density == COMPONENT_DENSITY_32MB) ||
1186 (density == COMPONENT_DENSITY_64MB) ||
1187 (density == COMPONENT_DENSITY_UNUSED) ) {
1188 printf("error: Selected density not supported in IFD version 1.\n");
1189 exit(EXIT_FAILURE);
1190 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001191 mask = 0x7;
1192 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001193 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001194 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001195 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001196 mask = 0xf;
1197 chip2_offset = 4;
1198 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001199 default:
1200 printf("error: Unknown IFD version\n");
1201 exit(EXIT_FAILURE);
1202 break;
1203 }
1204
1205 /* clear chip density for corresponding chip */
1206 switch (selected_chip) {
1207 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001208 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001209 break;
1210 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001211 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001212 break;
1213 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001214 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001215 break;
1216 }
1217
1218 /* set the new density */
1219 if (selected_chip == 1 || selected_chip == 0)
1220 fcba->flcomp |= (density); /* first chip */
1221 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001222 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001223
1224 write_image(filename, image, size);
1225}
1226
Duncan Laurie7775d672019-06-06 13:39:26 -07001227static int check_region(const frba_t *frba, unsigned int region_type)
1228{
1229 region_t region;
1230
1231 if (!frba)
1232 return 0;
1233
1234 region = get_region(frba, region_type);
1235 return !!((region.base < region.limit) && (region.size > 0));
1236}
1237
Bill XIEfa5f9942017-09-12 11:22:29 +08001238static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001239{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001240 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001241 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001242 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001243 if (!fmba)
1244 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001245
1246 if (ifd_version >= IFD_VERSION_2) {
1247 wr_shift = FLMSTR_WR_SHIFT_V2;
1248 rd_shift = FLMSTR_RD_SHIFT_V2;
1249
1250 /* Clear non-reserved bits */
1251 fmba->flmstr1 &= 0xff;
1252 fmba->flmstr2 &= 0xff;
1253 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001254 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001255 } else {
1256 wr_shift = FLMSTR_WR_SHIFT_V1;
1257 rd_shift = FLMSTR_RD_SHIFT_V1;
1258
1259 fmba->flmstr1 = 0;
1260 fmba->flmstr2 = 0;
1261 /* Requestor ID */
1262 fmba->flmstr3 = 0x118;
1263 }
1264
Andrey Petrov96ecb772016-10-31 19:31:54 -07001265 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001266 case PLATFORM_APL:
1267 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001268 /* CPU/BIOS can read descriptor and BIOS */
1269 fmba->flmstr1 |= 0x3 << rd_shift;
1270 /* CPU/BIOS can write BIOS */
1271 fmba->flmstr1 |= 0x2 << wr_shift;
1272 /* TXE can read descriptor, BIOS and Device Expansion */
1273 fmba->flmstr2 |= 0x23 << rd_shift;
1274 /* TXE can only write Device Expansion */
1275 fmba->flmstr2 |= 0x20 << wr_shift;
1276 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001277 case PLATFORM_CNL:
1278 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001279 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001280 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301281 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001282 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301283 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001284 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301285 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001286 /* CPU/BIOS can read descriptor and BIOS. */
1287 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1288 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1289 /* CPU/BIOS can write BIOS. */
1290 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1291 /* ME can read descriptor and ME. */
1292 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1293 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001294 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001295 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1296 if (check_region(frba, REGION_GBE)) {
1297 /* BIOS can read/write GbE. */
1298 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1299 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1300 /* ME can read GbE. */
1301 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1302 /* GbE can read descriptor and read/write GbE.. */
1303 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1304 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1305 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1306 }
1307 if (check_region(frba, REGION_PDR)) {
1308 /* BIOS can read/write PDR. */
1309 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1310 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1311 }
1312 if (check_region(frba, REGION_EC)) {
1313 /* BIOS can read EC. */
1314 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1315 /* EC can read descriptor and read/write EC. */
1316 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1317 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1318 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1319 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001320 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001321 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001322 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001323 /* CPU/BIOS can read descriptor and BIOS. */
1324 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1325 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1326 /* CPU/BIOS can write BIOS. */
1327 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1328 /* ME can read descriptor and ME. */
1329 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1330 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1331 /* ME can write ME. */
1332 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1333 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001334 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001335 /* CPU/BIOS can read descriptor and BIOS. */
1336 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1337 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1338 /* CPU/BIOS can write BIOS. */
1339 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1340 /* ME can read descriptor and ME. */
1341 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1342 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1343 /* ME can write ME. */
1344 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1345 if (check_region(frba, REGION_GBE)) {
1346 /* BIOS can read GbE. */
1347 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1348 /* BIOS can write GbE. */
1349 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1350 /* ME can read GbE. */
1351 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1352 /* ME can write GbE. */
1353 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1354 /* GbE can write GbE. */
1355 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1356 /* GbE can read GbE. */
1357 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1358 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001359 break;
1360 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001361
1362 write_image(filename, image, size);
1363}
1364
Usha P412679d2020-10-15 11:25:08 +05301365static void enable_cpu_read_me(const char *filename, char *image, int size)
1366{
1367 int rd_shift;
1368 fmba_t *fmba = find_fmba(image, size);
1369
1370 if (!fmba)
1371 exit(EXIT_FAILURE);
1372
1373 if (ifd_version >= IFD_VERSION_2)
1374 rd_shift = FLMSTR_RD_SHIFT_V2;
1375 else
1376 rd_shift = FLMSTR_RD_SHIFT_V1;
1377
1378 /* CPU/BIOS can read ME. */
1379 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1380
1381 write_image(filename, image, size);
1382}
1383
Bill XIEfa5f9942017-09-12 11:22:29 +08001384static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001385{
Bill XIE612ec0e2017-08-30 16:10:27 +08001386 fmba_t *fmba = find_fmba(image, size);
1387 if (!fmba)
1388 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001389
1390 if (ifd_version >= IFD_VERSION_2) {
1391 /* Access bits for each region are read: 19:8 write: 31:20 */
1392 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1393 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1394 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001395 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001396 } else {
1397 fmba->flmstr1 = 0xffff0000;
1398 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001399 /* Keep chipset specific Requester ID */
1400 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001401 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001402
1403 write_image(filename, image, size);
1404}
1405
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001406static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1407 const unsigned int value)
1408{
1409 if (!fpsba || !fdb) {
1410 fprintf(stderr, "Internal error\n");
1411 exit(EXIT_FAILURE);
1412 }
1413
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001414 /* SoC Strap, aka PSL, aka ISL */
1415 int SS = (fdb->flmap1 >> 24) & 0xff;
1416 if (strap >= SS) {
1417 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001418 exit(EXIT_FAILURE);
1419 }
1420 fpsba->pchstrp[strap] = value;
1421}
1422
Bill XIEb3e15a22017-09-07 18:34:50 +08001423/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001424static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001425{
1426 if (ifd_version >= IFD_VERSION_2) {
1427 printf("%sting the HAP bit to %s Intel ME...\n",
1428 altmedisable?"Set":"Unset",
1429 altmedisable?"disable":"enable");
1430 if (altmedisable)
1431 fpsba->pchstrp[0] |= (1 << 16);
1432 else
1433 fpsba->pchstrp[0] &= ~(1 << 16);
1434 } else {
1435 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1436 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1437 "and MCH_AltMeDisable to %s Intel ME...\n",
1438 altmedisable?"Set":"Unset",
1439 altmedisable?"disable":"enable");
1440 if (altmedisable) {
1441 /* MCH_MeDisable */
1442 fmsba->data[0] |= 1;
1443 /* MCH_AltMeDisable */
1444 fmsba->data[0] |= (1 << 7);
1445 /* ICH_MeDisable */
1446 fpsba->pchstrp[0] |= 1;
1447 } else {
1448 fmsba->data[0] &= ~1;
1449 fmsba->data[0] &= ~(1 << 7);
1450 fpsba->pchstrp[0] &= ~1;
1451 }
1452 } else {
1453 printf("%sting the AltMeDisable to %s Intel ME...\n",
1454 altmedisable?"Set":"Unset",
1455 altmedisable?"disable":"enable");
1456 if (altmedisable)
1457 fpsba->pchstrp[10] |= (1 << 7);
1458 else
1459 fpsba->pchstrp[10] &= ~(1 << 7);
1460 }
1461 }
1462}
1463
Jacob Garber595d9262019-06-27 17:33:10 -06001464static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001465 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001466{
Bill XIE612ec0e2017-08-30 16:10:27 +08001467 frba_t *frba = find_frba(image, size);
1468 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001469 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001470
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001471 region_t region = get_region(frba, region_type);
1472 if (region.size <= 0xfff) {
1473 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1474 region_name(region_type));
1475 exit(EXIT_FAILURE);
1476 }
1477
Scott Duplichanf2c98372014-12-12 21:03:06 -06001478 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001479 if (region_fd == -1) {
1480 perror("Could not open file");
1481 exit(EXIT_FAILURE);
1482 }
1483 struct stat buf;
1484 if (fstat(region_fd, &buf) == -1) {
1485 perror("Could not stat file");
1486 exit(EXIT_FAILURE);
1487 }
1488 int region_size = buf.st_size;
1489
1490 printf("File %s is %d bytes\n", region_fname, region_size);
1491
1492 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001493 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001494 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1495 " bytes. Not injecting.\n",
1496 region_name(region_type), region.size,
1497 region.size, region_size, region_size);
1498 exit(EXIT_FAILURE);
1499 }
1500
1501 int offset = 0;
1502 if ((region_type == 1) && (region_size < region.size)) {
1503 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1504 " bytes. Padding before injecting.\n",
1505 region_name(region_type), region.size,
1506 region.size, region_size, region_size);
1507 offset = region.size - region_size;
1508 memset(image + region.base, 0xff, offset);
1509 }
1510
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001511 if (size < region.base + offset + region_size) {
1512 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1513 size, region.base + offset + region_size);
1514 exit(EXIT_FAILURE);
1515 }
1516
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001517 if (read(region_fd, image + region.base + offset, region_size)
1518 != region_size) {
1519 perror("Could not read file");
1520 exit(EXIT_FAILURE);
1521 }
1522
1523 close(region_fd);
1524
1525 printf("Adding %s as the %s section of %s\n",
1526 region_fname, region_name(region_type), filename);
1527 write_image(filename, image, size);
1528}
1529
Jacob Garber595d9262019-06-27 17:33:10 -06001530static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001531{
1532 unsigned int y = 1;
1533 if (x == 0)
1534 return 0;
1535 while (y <= x)
1536 y = y << 1;
1537
1538 return y;
1539}
1540
1541/**
1542 * Determine if two memory regions overlap.
1543 *
1544 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001545 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001546 * @return 1 if the two regions overlap
1547 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001548static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001549{
Bill XIEfa5f9942017-09-12 11:22:29 +08001550 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001551 return 0;
1552
Nico Huber844eda02019-01-05 00:06:19 +01001553 /* r1 should be either completely below or completely above r2 */
1554 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001555}
1556
Jacob Garber595d9262019-06-27 17:33:10 -06001557static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001558 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001559{
1560 FILE *romlayout;
1561 char tempstr[256];
1562 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001563 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001564 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001565 region_t current_regions[MAX_REGIONS];
1566 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001567 int new_extent = 0;
1568 char *new_image;
1569
1570 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001571 frba_t *frba = find_frba(image, size);
1572 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001573 exit(EXIT_FAILURE);
1574
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001575 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001576 current_regions[i] = get_region(frba, i);
1577 new_regions[i] = get_region(frba, i);
1578 }
1579
1580 /* read new layout */
1581 romlayout = fopen(layout_fname, "r");
1582
1583 if (!romlayout) {
1584 perror("Could not read layout file.\n");
1585 exit(EXIT_FAILURE);
1586 }
1587
1588 while (!feof(romlayout)) {
1589 char *tstr1, *tstr2;
1590
Patrick Georgi802ad522014-08-09 17:12:23 +02001591 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001592 layout_region_name))
1593 continue;
1594
1595 region_number = region_num(layout_region_name);
1596 if (region_number < 0)
1597 continue;
1598
1599 tstr1 = strtok(tempstr, ":");
1600 tstr2 = strtok(NULL, ":");
1601 if (!tstr1 || !tstr2) {
1602 fprintf(stderr, "Could not parse layout file.\n");
1603 exit(EXIT_FAILURE);
1604 }
1605 new_regions[region_number].base = strtol(tstr1,
1606 (char **)NULL, 16);
1607 new_regions[region_number].limit = strtol(tstr2,
1608 (char **)NULL, 16);
1609 new_regions[region_number].size =
1610 new_regions[region_number].limit -
1611 new_regions[region_number].base + 1;
1612
1613 if (new_regions[region_number].size < 0)
1614 new_regions[region_number].size = 0;
1615 }
1616 fclose(romlayout);
1617
1618 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001619 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001620 if (new_regions[i].size == 0)
1621 continue;
1622
1623 if (new_regions[i].size < current_regions[i].size) {
1624 printf("DANGER: Region %s is shrinking.\n",
1625 region_name(i));
1626 printf(" The region will be truncated to fit.\n");
1627 printf(" This may result in an unusable image.\n");
1628 }
1629
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001630 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001631 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001632 fprintf(stderr, "Regions would overlap.\n");
1633 exit(EXIT_FAILURE);
1634 }
1635 }
1636
1637 /* detect if the image size should grow */
1638 if (new_extent < new_regions[i].limit)
1639 new_extent = new_regions[i].limit;
1640 }
1641
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001642 /* check if the image is actually a Flash Descriptor region */
1643 if (size == new_regions[0].size) {
1644 printf("The image is a single Flash Descriptor:\n");
1645 printf(" Only the descriptor will be modified\n");
1646 new_extent = size;
1647 } else {
1648 new_extent = next_pow2(new_extent - 1);
1649 if (new_extent != size) {
1650 printf("The image has changed in size.\n");
1651 printf("The old image is %d bytes.\n", size);
1652 printf("The new image is %d bytes.\n", new_extent);
1653 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001654 }
1655
1656 /* copy regions to a new image */
1657 new_image = malloc(new_extent);
1658 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001659 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001660 int copy_size = new_regions[i].size;
1661 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001662 const region_t *current = &current_regions[i];
1663 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001664
Bill XIEfa5f9942017-09-12 11:22:29 +08001665 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001666 continue;
1667
Bill XIEfa5f9942017-09-12 11:22:29 +08001668 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001669 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001670 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001671 if (i == REGION_BIOS)
1672 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001673 }
1674
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001675 if ((i == REGION_BIOS) && (new->size < current->size)) {
1676 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001677 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001678 }
1679
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001680 if (size < current->base + offset_current + copy_size) {
1681 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1682 region_name(i));
1683 continue;
1684 };
1685
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001686 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1687 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001688 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1689 offset_current, current->limit, current->size);
1690 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1691 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001692
Bill XIEfa5f9942017-09-12 11:22:29 +08001693 memcpy(new_image + new->base + offset_new,
1694 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001695 copy_size);
1696 }
1697
1698 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001699 frba = find_frba(new_image, new_extent);
1700 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001701 exit(EXIT_FAILURE);
1702
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001703 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001704 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001705 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001706
1707 write_image(filename, new_image, new_extent);
1708 free(new_image);
1709}
1710
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001711static void print_version(void)
1712{
1713 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1714 printf("Copyright (C) 2011 Google Inc.\n\n");
1715 printf
1716 ("This program is free software: you can redistribute it and/or modify\n"
1717 "it under the terms of the GNU General Public License as published by\n"
1718 "the Free Software Foundation, version 2 of the License.\n\n"
1719 "This program is distributed in the hope that it will be useful,\n"
1720 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1721 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001722 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001723}
1724
1725static void print_usage(const char *name)
1726{
1727 printf("usage: %s [-vhdix?] <filename>\n", name);
1728 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001729 " -d | --dump: dump intel firmware descriptor\n"
1730 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1731 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1732 " -x | --extract: extract intel fd modules\n"
1733 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1734 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001735 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001736 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1737 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1738 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1739 " can only be used once per run:\n"
1740 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1741 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1742 " Dual Output Fast Read Support\n"
1743 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301744 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001745 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001746 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1747 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001748 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301749 " adl - Alder Lake\n"
1750 " aplk - Apollo Lake\n"
1751 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001752 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001753 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001754 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301755 " glk - Gemini Lake\n"
1756 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001757 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301758 " jsl - Jasper Lake\n"
1759 " sklkbl - Sky Lake/Kaby Lake\n"
1760 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02001761 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001762 " -S | --setpchstrap Write a PCH strap\n"
1763 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001764 " -v | --version: print the version\n"
1765 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001766 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1767 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001768 "\n");
1769}
1770
1771int main(int argc, char *argv[])
1772{
1773 int opt, option_index = 0;
1774 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001775 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001776 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301777 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001778 char *region_type_string = NULL, *region_fname = NULL;
1779 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001780 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001781 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001782 unsigned int value = 0;
1783 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001784 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001785 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1786
Bill XIEfa5f9942017-09-12 11:22:29 +08001787 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001788 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001789 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001790 {"extract", 0, NULL, 'x'},
1791 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001792 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001793 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001794 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001795 {"density", 1, NULL, 'D'},
1796 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001797 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001798 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001799 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301800 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001801 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001802 {"version", 0, NULL, 'v'},
1803 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001804 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001805 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001806 {"setpchstrap", 1, NULL, 'S'},
1807 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001808 {0, 0, 0, 0}
1809 };
1810
Usha P412679d2020-10-15 11:25:08 +05301811 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 -07001812 long_options, &option_index)) != EOF) {
1813 switch (opt) {
1814 case 'd':
1815 mode_dump = 1;
1816 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001817 case 'S':
1818 mode_setstrap = 1;
1819 pchstrap = strtoul(optarg, NULL, 0);
1820 break;
1821 case 'V':
1822 value = strtoul(optarg, NULL, 0);
1823 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001824 case 'f':
1825 mode_layout = 1;
1826 layout_fname = strdup(optarg);
1827 if (!layout_fname) {
1828 fprintf(stderr, "No layout file specified\n");
1829 print_usage(argv[0]);
1830 exit(EXIT_FAILURE);
1831 }
1832 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001833 case 'x':
1834 mode_extract = 1;
1835 break;
1836 case 'i':
1837 // separate type and file name
1838 region_type_string = strdup(optarg);
1839 region_fname = strchr(region_type_string, ':');
1840 if (!region_fname) {
1841 print_usage(argv[0]);
1842 exit(EXIT_FAILURE);
1843 }
1844 region_fname[0] = '\0';
1845 region_fname++;
1846 // Descriptor, BIOS, ME, GbE, Platform
1847 // valid type?
1848 if (!strcasecmp("Descriptor", region_type_string))
1849 region_type = 0;
1850 else if (!strcasecmp("BIOS", region_type_string))
1851 region_type = 1;
1852 else if (!strcasecmp("ME", region_type_string))
1853 region_type = 2;
1854 else if (!strcasecmp("GbE", region_type_string))
1855 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001856 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001857 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001858 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001859 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001860 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001861 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001862 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001863 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001864 else if (!strcasecmp("EC", region_type_string))
1865 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001866 else if (!strcasecmp("Device Exp2", region_type_string))
1867 region_type = 9;
1868 else if (!strcasecmp("IE", region_type_string))
1869 region_type = 10;
1870 else if (!strcasecmp("10GbE_0", region_type_string))
1871 region_type = 11;
1872 else if (!strcasecmp("10GbE_1", region_type_string))
1873 region_type = 12;
1874 else if (!strcasecmp("PTT", region_type_string))
1875 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001876 if (region_type == -1) {
1877 fprintf(stderr, "No such region type: '%s'\n\n",
1878 region_type_string);
1879 print_usage(argv[0]);
1880 exit(EXIT_FAILURE);
1881 }
1882 mode_inject = 1;
1883 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001884 case 'n':
1885 mode_newlayout = 1;
1886 layout_fname = strdup(optarg);
1887 if (!layout_fname) {
1888 fprintf(stderr, "No layout file specified\n");
1889 print_usage(argv[0]);
1890 exit(EXIT_FAILURE);
1891 }
1892 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001893 case 'O':
1894 new_filename = strdup(optarg);
1895 if (!new_filename) {
1896 fprintf(stderr, "No output filename specified\n");
1897 print_usage(argv[0]);
1898 exit(EXIT_FAILURE);
1899 }
1900 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001901 case 'D':
1902 mode_density = 1;
1903 new_density = strtoul(optarg, NULL, 0);
1904 switch (new_density) {
1905 case 512:
1906 new_density = COMPONENT_DENSITY_512KB;
1907 break;
1908 case 1:
1909 new_density = COMPONENT_DENSITY_1MB;
1910 break;
1911 case 2:
1912 new_density = COMPONENT_DENSITY_2MB;
1913 break;
1914 case 4:
1915 new_density = COMPONENT_DENSITY_4MB;
1916 break;
1917 case 8:
1918 new_density = COMPONENT_DENSITY_8MB;
1919 break;
1920 case 16:
1921 new_density = COMPONENT_DENSITY_16MB;
1922 break;
1923 case 32:
1924 new_density = COMPONENT_DENSITY_32MB;
1925 break;
1926 case 64:
1927 new_density = COMPONENT_DENSITY_64MB;
1928 break;
1929 case 0:
1930 new_density = COMPONENT_DENSITY_UNUSED;
1931 break;
1932 default:
1933 printf("error: Unknown density\n");
1934 print_usage(argv[0]);
1935 exit(EXIT_FAILURE);
1936 }
1937 break;
1938 case 'C':
1939 selected_chip = strtol(optarg, NULL, 0);
1940 if (selected_chip > 2) {
1941 fprintf(stderr, "error: Invalid chip selection\n");
1942 print_usage(argv[0]);
1943 exit(EXIT_FAILURE);
1944 }
1945 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001946 case 'M':
1947 mode_altmedisable = 1;
1948 altmedisable = strtol(optarg, NULL, 0);
1949 if (altmedisable > 1) {
1950 fprintf(stderr, "error: Illegal value\n");
1951 print_usage(argv[0]);
1952 exit(EXIT_FAILURE);
1953 }
1954 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001955 case 's':
1956 // Parse the requested SPI frequency
1957 inputfreq = strtol(optarg, NULL, 0);
1958 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001959 case 17:
1960 spifreq = SPI_FREQUENCY_17MHZ;
1961 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001962 case 20:
1963 spifreq = SPI_FREQUENCY_20MHZ;
1964 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001965 case 30:
1966 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1967 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001968 case 33:
1969 spifreq = SPI_FREQUENCY_33MHZ;
1970 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001971 case 48:
1972 spifreq = SPI_FREQUENCY_48MHZ;
1973 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001974 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001975 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001976 break;
1977 default:
1978 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1979 inputfreq);
1980 print_usage(argv[0]);
1981 exit(EXIT_FAILURE);
1982 }
1983 mode_spifreq = 1;
1984 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001985 case 'e':
1986 mode_em100 = 1;
1987 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001988 case 'l':
1989 mode_locked = 1;
1990 if (mode_unlocked == 1) {
1991 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1992 exit(EXIT_FAILURE);
1993 }
1994 break;
Usha P412679d2020-10-15 11:25:08 +05301995 case 'r':
1996 mode_read = 1;
1997 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001998 case 'u':
1999 mode_unlocked = 1;
2000 if (mode_locked == 1) {
2001 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2002 exit(EXIT_FAILURE);
2003 }
2004 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002005 case 'p':
2006 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002007 platform = PLATFORM_APL;
2008 } else if (!strcmp(optarg, "cnl")) {
2009 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002010 } else if (!strcmp(optarg, "lbg")) {
2011 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002012 } else if (!strcmp(optarg, "dnv")) {
2013 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002014 } else if (!strcmp(optarg, "ehl")) {
2015 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002016 } else if (!strcmp(optarg, "glk")) {
2017 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302018 } else if (!strcmp(optarg, "icl")) {
2019 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302020 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002021 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002022 } else if (!strcmp(optarg, "sklkbl")) {
2023 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002024 } else if (!strcmp(optarg, "tgl")) {
2025 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302026 } else if (!strcmp(optarg, "adl")) {
2027 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002028 } else if (!strcmp(optarg, "ifd2")) {
2029 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302030 } else if (!strcmp(optarg, "mtl")) {
2031 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002032 } else if (!strcmp(optarg, "wbg")) {
2033 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002034 } else {
2035 fprintf(stderr, "Unknown platform: %s\n", optarg);
2036 exit(EXIT_FAILURE);
2037 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002038 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07002039 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002040 case 't':
2041 mode_validate = 1;
2042 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002043 case 'v':
2044 print_version();
2045 exit(EXIT_SUCCESS);
2046 break;
2047 case 'h':
2048 case '?':
2049 default:
2050 print_usage(argv[0]);
2051 exit(EXIT_SUCCESS);
2052 break;
2053 }
2054 }
2055
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002056 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002057 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05002058 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002059 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002060 print_usage(argv[0]);
2061 exit(EXIT_FAILURE);
2062 }
2063
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002064 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002065 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06002066 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002067 fprintf(stderr, "You need to specify a mode.\n\n");
2068 print_usage(argv[0]);
2069 exit(EXIT_FAILURE);
2070 }
2071
2072 if (optind + 1 != argc) {
2073 fprintf(stderr, "You need to specify a file.\n\n");
2074 print_usage(argv[0]);
2075 exit(EXIT_FAILURE);
2076 }
2077
2078 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002079 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002080 if (bios_fd == -1) {
2081 perror("Could not open file");
2082 exit(EXIT_FAILURE);
2083 }
2084 struct stat buf;
2085 if (fstat(bios_fd, &buf) == -1) {
2086 perror("Could not stat file");
2087 exit(EXIT_FAILURE);
2088 }
2089 int size = buf.st_size;
2090
2091 printf("File %s is %d bytes\n", filename, size);
2092
2093 char *image = malloc(size);
2094 if (!image) {
2095 printf("Out of memory.\n");
2096 exit(EXIT_FAILURE);
2097 }
2098
2099 if (read(bios_fd, image, size) != size) {
2100 perror("Could not read file");
2101 exit(EXIT_FAILURE);
2102 }
2103
2104 close(bios_fd);
2105
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002106 // generate new filename
2107 if (new_filename == NULL) {
2108 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2109 if (!new_filename) {
2110 printf("Out of memory.\n");
2111 exit(EXIT_FAILURE);
2112 }
2113 // - 5: leave room for ".new\0"
2114 strcpy(new_filename, filename);
2115 strcat(new_filename, ".new");
2116 }
2117
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002118 check_ifd_version(image, size);
2119
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002120 if (mode_dump)
2121 dump_fd(image, size);
2122
Chris Douglass03ce0142014-02-26 13:30:13 -05002123 if (mode_layout)
2124 dump_layout(image, size, layout_fname);
2125
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002126 if (mode_extract)
2127 write_regions(image, size);
2128
Mathew Kingc7ddc992019-08-08 14:59:25 -06002129 if (mode_validate)
2130 validate_layout(image, size);
2131
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002132 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002133 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002134 region_fname);
2135
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002136 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002137 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002138
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002139 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002140 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002141
Jan Tatjefa317512016-03-11 00:52:07 +01002142 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002143 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002144
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002145 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002146 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002147
Alexander Couzensd12ea112016-09-10 13:33:05 +02002148 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002149 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002150
Usha P412679d2020-10-15 11:25:08 +05302151 if (mode_read)
2152 enable_cpu_read_me(new_filename, image, size);
2153
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002154 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002155 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002156
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002157 if (mode_setstrap) {
2158 fpsba_t *fpsba = find_fpsba(image, size);
2159 const fdbar_t *fdb = find_fd(image, size);
2160 set_pchstrap(fpsba, fdb, pchstrap, value);
2161 write_image(new_filename, image, size);
2162 }
2163
Bill XIEb3e15a22017-09-07 18:34:50 +08002164 if (mode_altmedisable) {
2165 fpsba_t *fpsba = find_fpsba(image, size);
2166 fmsba_t *fmsba = find_fmsba(image, size);
2167 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002168 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002169 }
2170
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002171 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002172 free(image);
2173
2174 return 0;
2175}