blob: 95bf1525e2e1ad389c777523e41e26a82eda8997 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003
4#include <unistd.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <getopt.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080012#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060013#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014#include "ifdtool.h"
15
Scott Duplichanf2c98372014-12-12 21:03:06 -060016#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
Bill XIE612ec0e2017-08-30 16:10:27 +080020/**
21 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
22 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
23 * @param base: base address represented with char* type.
24 * @param limit: upper limit of the legal address.
25 *
26 */
27#define PTR_IN_RANGE(ptr, base, limit) \
28 ((const char *)(ptr) >= (base) && \
29 (const char *)&(ptr)[1] <= (base) + (limit))
30
Jeff Dalyabd4b962022-01-06 00:52:30 -050031/**
32 * PLATFORM_HAS_GBE_REGION - some platforms do not support the PCH GbE LAN region
33 */
34#define PLATFORM_HAS_GBE_REGION (platform != PLATFORM_DNV)
35
36/*
37 * PLATFORM_HAS_EC_REGION - some platforms do not support the EC region
38 */
39#define PLATFORM_HAS_EC_REGION (ifd_version >= IFD_VERSION_2 && platform != PLATFORM_DNV)
40
41/*
42 * PLATFORM_HAS_10GBE_X_REGION - some platforms have 1 or more 10GbE LAN regions
43 */
44#define PLATFORM_HAS_10GBE_0_REGION (platform == PLATFORM_DNV)
45#define PLATFORM_HAS_10GBE_1_REGION (platform == PLATFORM_DNV)
46
Patrick Rudolph98ecaa42022-10-24 15:06:15 +020047static int max_regions_from_fdbar(const fdbar_t *fdb);
48
Duncan Laurie1f7fd722015-06-22 11:14:48 -070049static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080050static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080051static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010052static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070053static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050054
Duncan Laurie1f7fd722015-06-22 11:14:48 -070055static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060056 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
57 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
58 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
59 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
60 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
Jeff Daly3623eca2022-01-05 23:51:40 -050061 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
62 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
63 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060064 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050065 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
66 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
67 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
68 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
69 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
70 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
71 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050072};
73
Bill XIEb3e15a22017-09-07 18:34:50 +080074/* port from flashrom */
75static const char *const ich_chipset_names[] = {
76 "Unknown ICH",
77 "ICH",
78 "ICH2345",
79 "ICH6",
80 "SCH U",
81 "Atom E6xx",
82 "Atom S1220 S1240 S1260",
83 "ICH7",
84 "ICH8",
85 "ICH9",
86 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053087 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080088 "5 series Ibex Peak",
89 "6 series Cougar Point",
90 "7 series Panther Point",
91 "8 series Lynx Point",
92 "Baytrail",
93 "8 series Lynx Point LP",
94 "8 series Wellsburg",
95 "9 series Wildcat Point",
96 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053097 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053098 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053099 "Jasper Lake: N6xxx, N51xx, N45xx",
100 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +0530101 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +0530102 "300 series Cannon Point",
103 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +0530104 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +0800105 "C620 series Lewisburg",
106 NULL
107};
108
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700109static fdbar_t *find_fd(char *image, int size)
110{
111 int i, found = 0;
112
113 /* Scan for FD signature */
114 for (i = 0; i < (size - 4); i += 4) {
115 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
116 found = 1;
117 break; // signature found.
118 }
119 }
120
121 if (!found) {
122 printf("No Flash Descriptor found in this image\n");
123 return NULL;
124 }
125
Bill XIE612ec0e2017-08-30 16:10:27 +0800126 fdbar_t *fdb = (fdbar_t *) (image + i);
127 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
128}
129
Stefan Tauner0d226142018-08-05 18:56:53 +0200130static char *find_flumap(char *image, int size)
131{
132 /* The upper map is located in the word before the 256B-long OEM section
133 * at the end of the 4kB-long flash descriptor. In the official
134 * documentation this is defined as FDBAR + 0xEFC. However, starting
135 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
136 * has moved 16 bytes back to offset 0x10 of the image. Although
137 * official documentation still maintains the offset relative to FDBAR
138 * this is wrong and a simple fixed offset from the start of the image
139 * works.
140 */
141 char *flumap = image + 4096 - 256 - 4;
142 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
143}
144
Bill XIE612ec0e2017-08-30 16:10:27 +0800145static fcba_t *find_fcba(char *image, int size)
146{
147 fdbar_t *fdb = find_fd(image, size);
148 if (!fdb)
149 return NULL;
150 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
151 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
152
153}
154
155static fmba_t *find_fmba(char *image, int size)
156{
157 fdbar_t *fdb = find_fd(image, size);
158 if (!fdb)
159 return NULL;
160 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
161 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
162}
163
164static frba_t *find_frba(char *image, int size)
165{
166 fdbar_t *fdb = find_fd(image, size);
167 if (!fdb)
168 return NULL;
169 frba_t *frba =
170 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
171 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
172}
173
174static fpsba_t *find_fpsba(char *image, int size)
175{
176 fdbar_t *fdb = find_fd(image, size);
177 if (!fdb)
178 return NULL;
179 fpsba_t *fpsba =
180 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200181
182 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
183 if ((((char *)fpsba) + SSL) >= (image + size))
184 return NULL;
185 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800186}
187
188static fmsba_t *find_fmsba(char *image, int size)
189{
190 fdbar_t *fdb = find_fd(image, size);
191 if (!fdb)
192 return NULL;
193 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
194 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700195}
196
Bill XIEb3e15a22017-09-07 18:34:50 +0800197/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530198static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800199{
Subrata Banik8c082e52021-06-10 23:02:29 +0530200 const fdbar_t *fdb = find_fd(image, size);
201 if (!fdb)
202 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800203 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
204 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
205 uint32_t isl = (fdb->flmap1 >> 24);
206 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
Subrata Banik89db2252020-08-26 14:49:17 +0530207
208 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800209 if (iccriba == 0x00) {
210 if (msl == 0 && isl <= 2)
211 return CHIPSET_ICH8;
212 else if (isl <= 2)
213 return CHIPSET_ICH9;
214 else if (isl <= 10)
215 return CHIPSET_ICH10;
216 else if (isl <= 16)
217 return CHIPSET_5_SERIES_IBEX_PEAK;
218 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
219 return CHIPSET_5_SERIES_IBEX_PEAK;
220 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
221 if (msl == 0 && isl <= 17)
222 return CHIPSET_BAYTRAIL;
223 else if (msl <= 1 && isl <= 18)
224 return CHIPSET_6_SERIES_COUGAR_POINT;
225 else if (msl <= 1 && isl <= 21)
226 return CHIPSET_8_SERIES_LYNX_POINT;
227 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
228 return CHIPSET_9_SERIES_WILDCAT_POINT;
229 } else if (nm == 6) {
230 return CHIPSET_C620_SERIES_LEWISBURG;
Bill XIEb3e15a22017-09-07 18:34:50 +0800231 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200232 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800233}
234
Subrata Banik8c082e52021-06-10 23:02:29 +0530235static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
236{
237 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530238 case PLATFORM_APL:
239 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530240 case PLATFORM_GLK:
241 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
242 case PLATFORM_JSL:
243 return CHIPSET_N_SERIES_JASPER_LAKE;
244 case PLATFORM_EHL:
245 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200246 case PLATFORM_SKLKBL:
247 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530248 case PLATFORM_CNL:
249 return CHIPSET_300_SERIES_CANNON_POINT;
250 case PLATFORM_TGL:
251 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800252 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +0530253 case PLATFORM_MTL:
Subrata Banik8c082e52021-06-10 23:02:29 +0530254 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
255 case PLATFORM_ICL:
256 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800257 case PLATFORM_LBG:
258 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500259 case PLATFORM_DNV:
260 return CHIPSET_DENVERTON;
Subrata Banik8c082e52021-06-10 23:02:29 +0530261 default:
262 return CHIPSET_PCH_UNKNOWN;
263 }
264}
265
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700266/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700267 * Some newer platforms have re-defined the FCBA field that was used to
268 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
269 * have the required FCBA field, but are IFD v2 and return true if current
270 * platform is one of them.
271 */
272static int is_platform_ifd_2(void)
273{
274 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530275 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700276 PLATFORM_GLK,
277 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800278 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500279 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530280 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700281 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530282 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700283 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530284 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200285 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800286 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530287 PLATFORM_MTL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700288 };
289 unsigned int i;
290
291 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
292 if (platform == ifd_2_platforms[i])
293 return 1;
294 }
295
296 return 0;
297}
298
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700299static void check_ifd_version(char *image, int size)
300{
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200301 const fdbar_t *fdb = find_fd(image, size);
302
Subrata Banik8c082e52021-06-10 23:02:29 +0530303 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700304 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530305 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200306 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530307 } else {
308 ifd_version = IFD_VERSION_1;
309 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200310 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530311 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700312}
313
Bill XIEfa5f9942017-09-12 11:22:29 +0800314static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700315{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500316 int base_mask;
317 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700318 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700319 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500320
321 if (ifd_version >= IFD_VERSION_2)
322 base_mask = 0x7fff;
323 else
324 base_mask = 0xfff;
325
326 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700327
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400328 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800329 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700330 exit (EXIT_FAILURE);
331 }
332
Bill XIE4651d452017-09-12 11:54:48 +0800333 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700334 region.base = (flreg & base_mask) << 12;
335 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700336 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500337
Chris Douglass03ce0142014-02-26 13:30:13 -0500338 if (region.size < 0)
339 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700340
341 return region;
342}
343
Bill XIEfa5f9942017-09-12 11:22:29 +0800344static void set_region(frba_t *frba, unsigned int region_type,
345 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500346{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400347 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800348 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500349 exit (EXIT_FAILURE);
350 }
Bill XIE4651d452017-09-12 11:54:48 +0800351
352 frba->flreg[region_type] =
353 (((region->limit >> 12) & 0x7fff) << 16) |
354 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500355}
356
Bill XIEfa5f9942017-09-12 11:22:29 +0800357static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700358{
Bill XIEfa5f9942017-09-12 11:22:29 +0800359 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700360 fprintf(stderr, "Invalid region type.\n");
361 exit (EXIT_FAILURE);
362 }
363
Chris Douglass03ce0142014-02-26 13:30:13 -0500364 return region_names[region_type].pretty;
365}
366
Bill XIEfa5f9942017-09-12 11:22:29 +0800367static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500368{
Bill XIEfa5f9942017-09-12 11:22:29 +0800369 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500370 fprintf(stderr, "Invalid region type.\n");
371 exit (EXIT_FAILURE);
372 }
373
374 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700375}
376
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500377static int region_num(const char *name)
378{
Bill XIEfa5f9942017-09-12 11:22:29 +0800379 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500380
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200381 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500382 if (strcasecmp(name, region_names[i].pretty) == 0)
383 return i;
384 if (strcasecmp(name, region_names[i].terse) == 0)
385 return i;
386 }
387
388 return -1;
389}
390
Bill XIEfa5f9942017-09-12 11:22:29 +0800391static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700392{
Bill XIEfa5f9942017-09-12 11:22:29 +0800393 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700394 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700395 exit (EXIT_FAILURE);
396 }
397
Bill XIE1bf65062017-09-12 11:31:37 +0800398 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700399}
400
Bill XIEfa5f9942017-09-12 11:22:29 +0800401static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700402{
403 region_t region = get_region(frba, num);
404 printf(" Flash Region %d (%s): %08x - %08x %s\n",
405 num, region_name(num), region.base, region.limit,
406 region.size < 1 ? "(unused)" : "");
407}
408
Bill XIEfa5f9942017-09-12 11:22:29 +0800409static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
410 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500411{
412 region_t region = get_region(frba, num);
413 snprintf(buf, bufsize, "%08x:%08x %s\n",
414 region.base, region.limit, region_name_short(num));
415}
416
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200417static int sort_compare(const void *a, const void *b)
418{
419 return *(size_t *)a - *(size_t *)b;
420}
421
422/*
423 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
424 *
425 * It's platform specific which regions are used or are reserved.
426 * The 'SPI programming guide' as the name says is a guide only,
427 * not a specification what the hardware actually does.
428 * The best to do is not to rely on the guide, but detect how many
429 * regions are present in the IFD and expose them all.
430 *
431 * Very early IFDv2 chipsets, sometimes unofficially referred to as
432 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
433 * operating on an IFDv1.5 detect how much space is actually present
434 * in the IFD.
435 */
436static int max_regions_from_fdbar(const fdbar_t *fdb)
437{
438 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
439 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
440 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
441 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
442 const size_t flumap = 4096 - 256 - 4;
443 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
444
445 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
446
447 for (size_t i = 0; i < 4; i++) {
448 /*
449 * Find FRBA in the sorted array and determine the size of the
450 * region by the start of the next region. Every region requires
451 * 4 bytes of space.
452 */
453 if (sorted[i] == frba)
454 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
455 }
456 /* Never reaches this point */
457 return 0;
458}
459
Bill XIEfa5f9942017-09-12 11:22:29 +0800460static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700461{
Bill XIE4651d452017-09-12 11:54:48 +0800462 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530463 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700464 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800465 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530466 region = get_region(frba, i);
467 /* Skip unused & reserved Flash Region */
468 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
469 continue;
470
Bill XIE4651d452017-09-12 11:54:48 +0800471 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
472 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700473 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700474}
475
Bill XIEfa5f9942017-09-12 11:22:29 +0800476static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500477{
478 char buf[LAYOUT_LINELEN];
479 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800480 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500481
482 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
483 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
484 if (layout_fd == -1) {
485 perror("Could not open file");
486 exit(EXIT_FAILURE);
487 }
488
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200489 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200490 region_t region = get_region(frba, i);
491 /* is region invalid? */
492 if (region.size < 1)
493 continue;
494
Chris Douglass03ce0142014-02-26 13:30:13 -0500495 dump_region_layout(buf, bufsize, i, frba);
496 if (write(layout_fd, buf, strlen(buf)) < 0) {
497 perror("Could not write to file");
498 exit(EXIT_FAILURE);
499 }
500 }
501 close(layout_fd);
502 printf("Wrote layout to %s\n", layout_fname);
503}
504
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530505static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700506{
507 switch (freq) {
508 case SPI_FREQUENCY_20MHZ:
509 printf("20MHz");
510 break;
511 case SPI_FREQUENCY_33MHZ:
512 printf("33MHz");
513 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700514 case SPI_FREQUENCY_48MHZ:
515 printf("48MHz");
516 break;
517 case SPI_FREQUENCY_50MHZ_30MHZ:
518 switch (ifd_version) {
519 case IFD_VERSION_1:
520 printf("50MHz");
521 break;
522 case IFD_VERSION_2:
523 printf("30MHz");
524 break;
525 }
526 break;
527 case SPI_FREQUENCY_17MHZ:
528 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700529 break;
530 default:
531 printf("unknown<%x>MHz", freq);
532 }
533}
534
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530535static void _decode_spi_frequency_500_series(unsigned int freq)
536{
537 switch (freq) {
538 case SPI_FREQUENCY_100MHZ:
539 printf("100MHz");
540 break;
541 case SPI_FREQUENCY_50MHZ:
542 printf("50MHz");
543 break;
544 case SPI_FREQUENCY_500SERIES_33MHZ:
545 printf("33MHz");
546 break;
547 case SPI_FREQUENCY_25MHZ:
548 printf("25MHz");
549 break;
550 case SPI_FREQUENCY_14MHZ:
551 printf("14MHz");
552 break;
553 default:
554 printf("unknown<%x>MHz", freq);
555 }
556}
557
558static void decode_spi_frequency(unsigned int freq)
559{
Subrata Banika5f47812020-09-29 11:43:01 +0530560 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530561 _decode_spi_frequency_500_series(freq);
562 else
563 _decode_spi_frequency(freq);
564}
565
Subrata Banike5d39922020-08-26 16:01:42 +0530566static void _decode_espi_frequency(unsigned int freq)
567{
568 switch (freq) {
569 case ESPI_FREQUENCY_20MHZ:
570 printf("20MHz");
571 break;
572 case ESPI_FREQUENCY_24MHZ:
573 printf("24MHz");
574 break;
575 case ESPI_FREQUENCY_30MHZ:
576 printf("30MHz");
577 break;
578 case ESPI_FREQUENCY_48MHZ:
579 printf("48MHz");
580 break;
581 case ESPI_FREQUENCY_60MHZ:
582 printf("60MHz");
583 break;
584 case ESPI_FREQUENCY_17MHZ:
585 printf("17MHz");
586 break;
587 default:
588 printf("unknown<%x>MHz", freq);
589 }
590}
591
592static void _decode_espi_frequency_500_series(unsigned int freq)
593{
594 switch (freq) {
595 case ESPI_FREQUENCY_500SERIES_20MHZ:
596 printf("20MHz");
597 break;
598 case ESPI_FREQUENCY_500SERIES_24MHZ:
599 printf("24MHz");
600 break;
601 case ESPI_FREQUENCY_500SERIES_25MHZ:
602 printf("25MHz");
603 break;
604 case ESPI_FREQUENCY_500SERIES_48MHZ:
605 printf("48MHz");
606 break;
607 case ESPI_FREQUENCY_500SERIES_60MHZ:
608 printf("60MHz");
609 break;
610 default:
611 printf("unknown<%x>MHz", freq);
612 }
613}
614
615static void decode_espi_frequency(unsigned int freq)
616{
Subrata Banika5f47812020-09-29 11:43:01 +0530617 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530618 _decode_espi_frequency_500_series(freq);
619 else
620 _decode_espi_frequency(freq);
621}
622
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700623static void decode_component_density(unsigned int density)
624{
625 switch (density) {
626 case COMPONENT_DENSITY_512KB:
627 printf("512KB");
628 break;
629 case COMPONENT_DENSITY_1MB:
630 printf("1MB");
631 break;
632 case COMPONENT_DENSITY_2MB:
633 printf("2MB");
634 break;
635 case COMPONENT_DENSITY_4MB:
636 printf("4MB");
637 break;
638 case COMPONENT_DENSITY_8MB:
639 printf("8MB");
640 break;
641 case COMPONENT_DENSITY_16MB:
642 printf("16MB");
643 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700644 case COMPONENT_DENSITY_32MB:
645 printf("32MB");
646 break;
647 case COMPONENT_DENSITY_64MB:
648 printf("64MB");
649 break;
650 case COMPONENT_DENSITY_UNUSED:
651 printf("UNUSED");
652 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700653 default:
654 printf("unknown<%x>MB", density);
655 }
656}
657
Subrata Banik26058dc2020-08-26 15:12:16 +0530658static int is_platform_with_pch(void)
659{
660 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
661 return 1;
662
663 return 0;
664}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530665
666/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
667static int is_platform_with_100x_series_pch(void)
668{
669 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530670 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530671 return 1;
672
673 return 0;
674}
675
Subrata Banike5d39922020-08-26 16:01:42 +0530676static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700677{
Subrata Banike5d39922020-08-26 16:01:42 +0530678 unsigned int freq;
679
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700680 printf("\nFound Component Section\n");
681 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700682 printf(" Dual Output Fast Read Support: %ssupported\n",
683 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700684 printf(" Read ID/Read Status Clock Frequency: ");
685 decode_spi_frequency((fcba->flcomp >> 27) & 7);
686 printf("\n Write/Erase Clock Frequency: ");
687 decode_spi_frequency((fcba->flcomp >> 24) & 7);
688 printf("\n Fast Read Clock Frequency: ");
689 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700690 printf("\n Fast Read Support: %ssupported",
691 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530692 if (is_platform_with_100x_series_pch() &&
693 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
694 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530695 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530696 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
697 else
698 freq = (fcba->flcomp >> 17) & 7;
699 decode_espi_frequency(freq);
700 } else {
701 printf("\n Read Clock Frequency: ");
702 decode_spi_frequency((fcba->flcomp >> 17) & 7);
703 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700704
705 switch (ifd_version) {
706 case IFD_VERSION_1:
707 printf("\n Component 2 Density: ");
708 decode_component_density((fcba->flcomp >> 3) & 7);
709 printf("\n Component 1 Density: ");
710 decode_component_density(fcba->flcomp & 7);
711 break;
712 case IFD_VERSION_2:
713 printf("\n Component 2 Density: ");
714 decode_component_density((fcba->flcomp >> 4) & 0xf);
715 printf("\n Component 1 Density: ");
716 decode_component_density(fcba->flcomp & 0xf);
717 break;
718 }
719
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700720 printf("\n");
721 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700722 printf(" Invalid Instruction 3: 0x%02x\n",
723 (fcba->flill >> 24) & 0xff);
724 printf(" Invalid Instruction 2: 0x%02x\n",
725 (fcba->flill >> 16) & 0xff);
726 printf(" Invalid Instruction 1: 0x%02x\n",
727 (fcba->flill >> 8) & 0xff);
728 printf(" Invalid Instruction 0: 0x%02x\n",
729 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530730 if (is_platform_with_100x_series_pch()) {
731 printf("FLILL1 0x%08x\n", fcba->flpb);
732 printf(" Invalid Instruction 7: 0x%02x\n",
733 (fcba->flpb >> 24) & 0xff);
734 printf(" Invalid Instruction 6: 0x%02x\n",
735 (fcba->flpb >> 16) & 0xff);
736 printf(" Invalid Instruction 5: 0x%02x\n",
737 (fcba->flpb >> 8) & 0xff);
738 printf(" Invalid Instruction 4: 0x%02x\n",
739 fcba->flpb & 0xff);
740 } else {
741 printf("FLPB 0x%08x\n", fcba->flpb);
742 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
743 (fcba->flpb & 0xfff) << 12);
744 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700745}
746
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200747static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700748{
Bill XIE4651d452017-09-12 11:54:48 +0800749 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200750 /* SoC Straps, aka PSL, aka ISL */
751 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200752
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700753 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200754 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200755 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800756
757 if (ifd_version >= IFD_VERSION_2) {
758 printf("HAP bit is %sset\n",
759 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
760 } else if (chipset >= CHIPSET_ICH8
761 && chipset <= CHIPSET_ICH10) {
762 printf("ICH_MeDisable bit is %sset\n",
763 fpsba->pchstrp[0] & 1 ? "" : "not ");
764 } else {
765 printf("AltMeDisable bit is %sset\n",
766 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
767 }
768
Bill XIE4651d452017-09-12 11:54:48 +0800769 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700770}
771
772static void decode_flmstr(uint32_t flmstr)
773{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700774 int wr_shift, rd_shift;
775 if (ifd_version >= IFD_VERSION_2) {
776 wr_shift = FLMSTR_WR_SHIFT_V2;
777 rd_shift = FLMSTR_RD_SHIFT_V2;
778 } else {
779 wr_shift = FLMSTR_WR_SHIFT_V1;
780 rd_shift = FLMSTR_RD_SHIFT_V1;
781 }
782
783 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500784 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700785 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700786 (flmstr & (1 << (wr_shift + 8))) ?
787 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700788 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700789 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500790 if (PLATFORM_HAS_GBE_REGION) {
791 printf(" GbE Region Write Access: %s\n",
792 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
793 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700794 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700795 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700796 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700797 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700798 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700799 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500800 if (PLATFORM_HAS_10GBE_0_REGION) {
801 printf(" 10GbE_0 Write Access: %s\n",
802 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
803 }
804 if (PLATFORM_HAS_10GBE_1_REGION) {
805 printf(" 10GbE_1 Write Access: %s\n",
806 (flmstr & (1 << 4)) ? "enabled" : "disabled");
807 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700808
Jeff Dalyabd4b962022-01-06 00:52:30 -0500809 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700810 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700811 (flmstr & (1 << (rd_shift + 8))) ?
812 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700813 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700814 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500815 if (PLATFORM_HAS_GBE_REGION) {
816 printf(" GbE Region Read Access: %s\n",
817 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
818 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700819 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700820 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700821 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700822 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700823 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700824 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500825 if (PLATFORM_HAS_10GBE_0_REGION) {
826 printf(" 10GbE_0 Read Access: %s\n",
827 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
828 }
829 if (PLATFORM_HAS_10GBE_1_REGION) {
830 printf(" 10GbE_1 Read Access: %s\n",
831 (flmstr & (1 << 0)) ? "enabled" : "disabled");
832 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700833
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700834 /* Requestor ID doesn't exist for ifd 2 */
835 if (ifd_version < IFD_VERSION_2)
836 printf(" Requester ID: 0x%04x\n\n",
837 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700838}
839
Bill XIEfa5f9942017-09-12 11:22:29 +0800840static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700841{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700842 printf("Found Master Section\n");
843 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
844 decode_flmstr(fmba->flmstr1);
845 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
846 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500847 if (PLATFORM_HAS_GBE_REGION) {
848 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
849 decode_flmstr(fmba->flmstr3);
850 if (ifd_version >= IFD_VERSION_2) {
851 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
852 decode_flmstr(fmba->flmstr5);
853 }
854 } else {
855 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
856 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700857 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700858}
859
Bill XIEfa5f9942017-09-12 11:22:29 +0800860static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700861{
Bill XIE612ec0e2017-08-30 16:10:27 +0800862 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700863 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800864 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
865 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800866
867 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
868 printf("MCH_MeDisable bit is %sset\n",
869 fmsba->data[0] & 1 ? "" : "not ");
870 printf("MCH_AltMeDisable bit is %sset\n",
871 fmsba->data[0] & (1 << 7) ? "" : "not ");
872 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700873}
874
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700875static void dump_jid(uint32_t jid)
876{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100877 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700878 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100879 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200880 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100881 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200882 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700883}
884
885static void dump_vscc(uint32_t vscc)
886{
887 printf(" Lower Erase Opcode: 0x%02x\n",
888 vscc >> 24);
889 printf(" Lower Write Enable on Write Status: 0x%02x\n",
890 vscc & (1 << 20) ? 0x06 : 0x50);
891 printf(" Lower Write Status Required: %s\n",
892 vscc & (1 << 19) ? "Yes" : "No");
893 printf(" Lower Write Granularity: %d bytes\n",
894 vscc & (1 << 18) ? 64 : 1);
895 printf(" Lower Block / Sector Erase Size: ");
896 switch ((vscc >> 16) & 0x3) {
897 case 0:
898 printf("256 Byte\n");
899 break;
900 case 1:
901 printf("4KB\n");
902 break;
903 case 2:
904 printf("8KB\n");
905 break;
906 case 3:
907 printf("64KB\n");
908 break;
909 }
910
911 printf(" Upper Erase Opcode: 0x%02x\n",
912 (vscc >> 8) & 0xff);
913 printf(" Upper Write Enable on Write Status: 0x%02x\n",
914 vscc & (1 << 4) ? 0x06 : 0x50);
915 printf(" Upper Write Status Required: %s\n",
916 vscc & (1 << 3) ? "Yes" : "No");
917 printf(" Upper Write Granularity: %d bytes\n",
918 vscc & (1 << 2) ? 64 : 1);
919 printf(" Upper Block / Sector Erase Size: ");
920 switch (vscc & 0x3) {
921 case 0:
922 printf("256 Byte\n");
923 break;
924 case 1:
925 printf("4KB\n");
926 break;
927 case 2:
928 printf("8KB\n");
929 break;
930 case 3:
931 printf("64KB\n");
932 break;
933 }
934}
935
Bill XIEfa5f9942017-09-12 11:22:29 +0800936static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700937{
938 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200939 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
940 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700941
942 printf("ME VSCC table:\n");
943 for (i = 0; i < num; i++) {
944 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
945 dump_jid(vtba->entry[i].jid);
946 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
947 dump_vscc(vtba->entry[i].vscc);
948 }
949 printf("\n");
950}
951
Bill XIEfa5f9942017-09-12 11:22:29 +0800952static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700953{
954 int i, j;
955 printf("OEM Section:\n");
956 for (i = 0; i < 4; i++) {
957 printf("%02x:", i << 4);
958 for (j = 0; j < 16; j++)
959 printf(" %02x", oem[(i<<4)+j]);
960 printf ("\n");
961 }
962 printf ("\n");
963}
964
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700965static void dump_fd(char *image, int size)
966{
Bill XIE612ec0e2017-08-30 16:10:27 +0800967 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700968 if (!fdb)
969 exit(EXIT_FAILURE);
970
Subrata Banik26058dc2020-08-26 15:12:16 +0530971 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
972 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700973 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530974 if (!is_platform_with_100x_series_pch())
975 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700976 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
977 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
978 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
979
980 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530981 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
982 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700983 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
984 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
985 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
986
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530987 if (!is_platform_with_100x_series_pch()) {
988 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
989 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
990 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
991 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700992
Subrata Banika5f47812020-09-29 11:43:01 +0530993 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530994 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
995 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
996 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
997 }
998
Stefan Tauner0d226142018-08-05 18:56:53 +0200999 char *flumap = find_flumap(image, size);
1000 uint32_t flumap1 = *(uint32_t *)flumap;
1001 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001002 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001003 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001004 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001005 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001006 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +02001007 (image + ((flumap1 & 0xff) << 4)),
1008 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +08001009 dump_oem((const uint8_t *)image + 0xf00);
1010
1011 const frba_t *frba = find_frba(image, size);
1012 const fcba_t *fcba = find_fcba(image, size);
1013 const fpsba_t *fpsba = find_fpsba(image, size);
1014 const fmba_t *fmba = find_fmba(image, size);
1015 const fmsba_t *fmsba = find_fmsba(image, size);
1016
1017 if (frba && fcba && fpsba && fmba && fmsba) {
1018 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +05301019 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001020 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +08001021 dump_fmba(fmba);
1022 dump_fmsba(fmsba);
1023 } else {
1024 printf("FD is corrupted!\n");
1025 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001026}
1027
Bill XIEfa5f9942017-09-12 11:22:29 +08001028static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -05001029{
Bill XIE612ec0e2017-08-30 16:10:27 +08001030 const frba_t *frba = find_frba(image, size);
1031 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -05001032 exit(EXIT_FAILURE);
1033
Bill XIE612ec0e2017-08-30 16:10:27 +08001034 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05001035}
1036
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001037static void write_regions(char *image, int size)
1038{
Bill XIEfa5f9942017-09-12 11:22:29 +08001039 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +08001040 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001041
Bill XIE612ec0e2017-08-30 16:10:27 +08001042 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001043 exit(EXIT_FAILURE);
1044
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001045 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001046 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001047 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001048 if (region.size > 0) {
1049 int region_fd;
1050 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -06001051 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001052 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001053 if (region_fd < 0) {
1054 perror("Error while trying to open file");
1055 exit(EXIT_FAILURE);
1056 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001057 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001058 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001059 close(region_fd);
1060 }
1061 }
1062}
1063
Mathew Kingc7ddc992019-08-08 14:59:25 -06001064static void validate_layout(char *image, int size)
1065{
1066 uint i, errors = 0;
1067 struct fmap *fmap;
1068 long int fmap_loc = fmap_find((uint8_t *)image, size);
1069 const frba_t *frba = find_frba(image, size);
1070
1071 if (fmap_loc < 0 || !frba)
1072 exit(EXIT_FAILURE);
1073
1074 fmap = (struct fmap *)(image + fmap_loc);
1075
1076 for (i = 0; i < max_regions; i++) {
1077 if (region_names[i].fmapname == NULL)
1078 continue;
1079
1080 region_t region = get_region(frba, i);
1081
1082 if (region.size == 0)
1083 continue;
1084
1085 const struct fmap_area *area =
1086 fmap_find_area(fmap, region_names[i].fmapname);
1087
1088 if (!area)
1089 continue;
1090
1091 if ((uint)region.base != area->offset ||
1092 (uint)region.size != area->size) {
1093 printf("Region mismatch between %s and %s\n",
1094 region_names[i].terse, area->name);
1095 printf(" Descriptor region %s:\n", region_names[i].terse);
1096 printf(" offset: 0x%08x\n", region.base);
1097 printf(" length: 0x%08x\n", region.size);
1098 printf(" FMAP area %s:\n", area->name);
1099 printf(" offset: 0x%08x\n", area->offset);
1100 printf(" length: 0x%08x\n", area->size);
1101 errors++;
1102 }
1103 }
1104
1105 if (errors > 0)
1106 exit(EXIT_FAILURE);
1107}
1108
Bill XIEfa5f9942017-09-12 11:22:29 +08001109static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001110{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001111 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001112 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001113
1114 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001115 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001116 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001117 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001118 if (new_fd < 0) {
1119 perror("Error while trying to open file");
1120 exit(EXIT_FAILURE);
1121 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001122 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001123 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001124 close(new_fd);
1125}
1126
Bill XIEfa5f9942017-09-12 11:22:29 +08001127static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001128 enum spi_frequency freq)
1129{
Bill XIE612ec0e2017-08-30 16:10:27 +08001130 fcba_t *fcba = find_fcba(image, size);
1131 if (!fcba)
1132 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001133
1134 /* clear bits 21-29 */
1135 fcba->flcomp &= ~0x3fe00000;
1136 /* Read ID and Read Status Clock Frequency */
1137 fcba->flcomp |= freq << 27;
1138 /* Write and Erase Clock Frequency */
1139 fcba->flcomp |= freq << 24;
1140 /* Fast Read Clock Frequency */
1141 fcba->flcomp |= freq << 21;
1142
1143 write_image(filename, image, size);
1144}
1145
Bill XIEfa5f9942017-09-12 11:22:29 +08001146static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001147{
Bill XIE612ec0e2017-08-30 16:10:27 +08001148 fcba_t *fcba = find_fcba(image, size);
1149 if (!fcba)
1150 exit(EXIT_FAILURE);
1151
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001152 int freq;
1153
1154 switch (ifd_version) {
1155 case IFD_VERSION_1:
1156 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;
1194 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001195 mask = 0xf;
1196 chip2_offset = 4;
1197 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001198 default:
1199 printf("error: Unknown IFD version\n");
1200 exit(EXIT_FAILURE);
1201 break;
1202 }
1203
1204 /* clear chip density for corresponding chip */
1205 switch (selected_chip) {
1206 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001207 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001208 break;
1209 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001210 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001211 break;
1212 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001213 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001214 break;
1215 }
1216
1217 /* set the new density */
1218 if (selected_chip == 1 || selected_chip == 0)
1219 fcba->flcomp |= (density); /* first chip */
1220 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001221 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001222
1223 write_image(filename, image, size);
1224}
1225
Duncan Laurie7775d672019-06-06 13:39:26 -07001226static int check_region(const frba_t *frba, unsigned int region_type)
1227{
1228 region_t region;
1229
1230 if (!frba)
1231 return 0;
1232
1233 region = get_region(frba, region_type);
1234 return !!((region.base < region.limit) && (region.size > 0));
1235}
1236
Bill XIEfa5f9942017-09-12 11:22:29 +08001237static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001238{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001239 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001240 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001241 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001242 if (!fmba)
1243 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001244
1245 if (ifd_version >= IFD_VERSION_2) {
1246 wr_shift = FLMSTR_WR_SHIFT_V2;
1247 rd_shift = FLMSTR_RD_SHIFT_V2;
1248
1249 /* Clear non-reserved bits */
1250 fmba->flmstr1 &= 0xff;
1251 fmba->flmstr2 &= 0xff;
1252 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001253 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001254 } else {
1255 wr_shift = FLMSTR_WR_SHIFT_V1;
1256 rd_shift = FLMSTR_RD_SHIFT_V1;
1257
1258 fmba->flmstr1 = 0;
1259 fmba->flmstr2 = 0;
1260 /* Requestor ID */
1261 fmba->flmstr3 = 0x118;
1262 }
1263
Andrey Petrov96ecb772016-10-31 19:31:54 -07001264 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001265 case PLATFORM_APL:
1266 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001267 /* CPU/BIOS can read descriptor and BIOS */
1268 fmba->flmstr1 |= 0x3 << rd_shift;
1269 /* CPU/BIOS can write BIOS */
1270 fmba->flmstr1 |= 0x2 << wr_shift;
1271 /* TXE can read descriptor, BIOS and Device Expansion */
1272 fmba->flmstr2 |= 0x23 << rd_shift;
1273 /* TXE can only write Device Expansion */
1274 fmba->flmstr2 |= 0x20 << wr_shift;
1275 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001276 case PLATFORM_CNL:
1277 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001278 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001279 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301280 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001281 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301282 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001283 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301284 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001285 /* CPU/BIOS can read descriptor and BIOS. */
1286 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1287 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1288 /* CPU/BIOS can write BIOS. */
1289 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1290 /* ME can read descriptor and ME. */
1291 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1292 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001293 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001294 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1295 if (check_region(frba, REGION_GBE)) {
1296 /* BIOS can read/write GbE. */
1297 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1298 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1299 /* ME can read GbE. */
1300 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1301 /* GbE can read descriptor and read/write GbE.. */
1302 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1303 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1304 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1305 }
1306 if (check_region(frba, REGION_PDR)) {
1307 /* BIOS can read/write PDR. */
1308 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1309 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1310 }
1311 if (check_region(frba, REGION_EC)) {
1312 /* BIOS can read EC. */
1313 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1314 /* EC can read descriptor and read/write EC. */
1315 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1316 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1317 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1318 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001319 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001320 case PLATFORM_DNV:
1321 /* CPU/BIOS can read descriptor and BIOS. */
1322 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1323 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1324 /* CPU/BIOS can write BIOS. */
1325 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1326 /* ME can read descriptor and ME. */
1327 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1328 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1329 /* ME can write ME. */
1330 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1331 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001332 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001333 /* CPU/BIOS can read descriptor and BIOS. */
1334 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1335 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1336 /* CPU/BIOS can write BIOS. */
1337 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1338 /* ME can read descriptor and ME. */
1339 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1340 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1341 /* ME can write ME. */
1342 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1343 if (check_region(frba, REGION_GBE)) {
1344 /* BIOS can read GbE. */
1345 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1346 /* BIOS can write GbE. */
1347 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1348 /* ME can read GbE. */
1349 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1350 /* ME can write GbE. */
1351 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1352 /* GbE can write GbE. */
1353 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1354 /* GbE can read GbE. */
1355 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1356 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001357 break;
1358 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001359
1360 write_image(filename, image, size);
1361}
1362
Usha P412679d2020-10-15 11:25:08 +05301363static void enable_cpu_read_me(const char *filename, char *image, int size)
1364{
1365 int rd_shift;
1366 fmba_t *fmba = find_fmba(image, size);
1367
1368 if (!fmba)
1369 exit(EXIT_FAILURE);
1370
1371 if (ifd_version >= IFD_VERSION_2)
1372 rd_shift = FLMSTR_RD_SHIFT_V2;
1373 else
1374 rd_shift = FLMSTR_RD_SHIFT_V1;
1375
1376 /* CPU/BIOS can read ME. */
1377 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1378
1379 write_image(filename, image, size);
1380}
1381
Bill XIEfa5f9942017-09-12 11:22:29 +08001382static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001383{
Bill XIE612ec0e2017-08-30 16:10:27 +08001384 fmba_t *fmba = find_fmba(image, size);
1385 if (!fmba)
1386 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001387
1388 if (ifd_version >= IFD_VERSION_2) {
1389 /* Access bits for each region are read: 19:8 write: 31:20 */
1390 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1391 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1392 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001393 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001394 } else {
1395 fmba->flmstr1 = 0xffff0000;
1396 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001397 /* Keep chipset specific Requester ID */
1398 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001399 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001400
1401 write_image(filename, image, size);
1402}
1403
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001404static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1405 const unsigned int value)
1406{
1407 if (!fpsba || !fdb) {
1408 fprintf(stderr, "Internal error\n");
1409 exit(EXIT_FAILURE);
1410 }
1411
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001412 /* SoC Strap, aka PSL, aka ISL */
1413 int SS = (fdb->flmap1 >> 24) & 0xff;
1414 if (strap >= SS) {
1415 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001416 exit(EXIT_FAILURE);
1417 }
1418 fpsba->pchstrp[strap] = value;
1419}
1420
Bill XIEb3e15a22017-09-07 18:34:50 +08001421/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001422static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001423{
1424 if (ifd_version >= IFD_VERSION_2) {
1425 printf("%sting the HAP bit to %s Intel ME...\n",
1426 altmedisable?"Set":"Unset",
1427 altmedisable?"disable":"enable");
1428 if (altmedisable)
1429 fpsba->pchstrp[0] |= (1 << 16);
1430 else
1431 fpsba->pchstrp[0] &= ~(1 << 16);
1432 } else {
1433 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1434 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1435 "and MCH_AltMeDisable to %s Intel ME...\n",
1436 altmedisable?"Set":"Unset",
1437 altmedisable?"disable":"enable");
1438 if (altmedisable) {
1439 /* MCH_MeDisable */
1440 fmsba->data[0] |= 1;
1441 /* MCH_AltMeDisable */
1442 fmsba->data[0] |= (1 << 7);
1443 /* ICH_MeDisable */
1444 fpsba->pchstrp[0] |= 1;
1445 } else {
1446 fmsba->data[0] &= ~1;
1447 fmsba->data[0] &= ~(1 << 7);
1448 fpsba->pchstrp[0] &= ~1;
1449 }
1450 } else {
1451 printf("%sting the AltMeDisable to %s Intel ME...\n",
1452 altmedisable?"Set":"Unset",
1453 altmedisable?"disable":"enable");
1454 if (altmedisable)
1455 fpsba->pchstrp[10] |= (1 << 7);
1456 else
1457 fpsba->pchstrp[10] &= ~(1 << 7);
1458 }
1459 }
1460}
1461
Jacob Garber595d9262019-06-27 17:33:10 -06001462static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001463 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001464{
Bill XIE612ec0e2017-08-30 16:10:27 +08001465 frba_t *frba = find_frba(image, size);
1466 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001467 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001468
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001469 region_t region = get_region(frba, region_type);
1470 if (region.size <= 0xfff) {
1471 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1472 region_name(region_type));
1473 exit(EXIT_FAILURE);
1474 }
1475
Scott Duplichanf2c98372014-12-12 21:03:06 -06001476 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001477 if (region_fd == -1) {
1478 perror("Could not open file");
1479 exit(EXIT_FAILURE);
1480 }
1481 struct stat buf;
1482 if (fstat(region_fd, &buf) == -1) {
1483 perror("Could not stat file");
1484 exit(EXIT_FAILURE);
1485 }
1486 int region_size = buf.st_size;
1487
1488 printf("File %s is %d bytes\n", region_fname, region_size);
1489
1490 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001491 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001492 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1493 " bytes. Not injecting.\n",
1494 region_name(region_type), region.size,
1495 region.size, region_size, region_size);
1496 exit(EXIT_FAILURE);
1497 }
1498
1499 int offset = 0;
1500 if ((region_type == 1) && (region_size < region.size)) {
1501 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1502 " bytes. Padding before injecting.\n",
1503 region_name(region_type), region.size,
1504 region.size, region_size, region_size);
1505 offset = region.size - region_size;
1506 memset(image + region.base, 0xff, offset);
1507 }
1508
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001509 if (size < region.base + offset + region_size) {
1510 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1511 size, region.base + offset + region_size);
1512 exit(EXIT_FAILURE);
1513 }
1514
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001515 if (read(region_fd, image + region.base + offset, region_size)
1516 != region_size) {
1517 perror("Could not read file");
1518 exit(EXIT_FAILURE);
1519 }
1520
1521 close(region_fd);
1522
1523 printf("Adding %s as the %s section of %s\n",
1524 region_fname, region_name(region_type), filename);
1525 write_image(filename, image, size);
1526}
1527
Jacob Garber595d9262019-06-27 17:33:10 -06001528static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001529{
1530 unsigned int y = 1;
1531 if (x == 0)
1532 return 0;
1533 while (y <= x)
1534 y = y << 1;
1535
1536 return y;
1537}
1538
1539/**
1540 * Determine if two memory regions overlap.
1541 *
1542 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001543 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001544 * @return 1 if the two regions overlap
1545 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001546static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001547{
Bill XIEfa5f9942017-09-12 11:22:29 +08001548 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001549 return 0;
1550
Nico Huber844eda02019-01-05 00:06:19 +01001551 /* r1 should be either completely below or completely above r2 */
1552 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001553}
1554
Jacob Garber595d9262019-06-27 17:33:10 -06001555static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001556 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001557{
1558 FILE *romlayout;
1559 char tempstr[256];
1560 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001561 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001562 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001563 region_t current_regions[MAX_REGIONS];
1564 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001565 int new_extent = 0;
1566 char *new_image;
1567
1568 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001569 frba_t *frba = find_frba(image, size);
1570 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001571 exit(EXIT_FAILURE);
1572
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001573 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001574 current_regions[i] = get_region(frba, i);
1575 new_regions[i] = get_region(frba, i);
1576 }
1577
1578 /* read new layout */
1579 romlayout = fopen(layout_fname, "r");
1580
1581 if (!romlayout) {
1582 perror("Could not read layout file.\n");
1583 exit(EXIT_FAILURE);
1584 }
1585
1586 while (!feof(romlayout)) {
1587 char *tstr1, *tstr2;
1588
Patrick Georgi802ad522014-08-09 17:12:23 +02001589 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001590 layout_region_name))
1591 continue;
1592
1593 region_number = region_num(layout_region_name);
1594 if (region_number < 0)
1595 continue;
1596
1597 tstr1 = strtok(tempstr, ":");
1598 tstr2 = strtok(NULL, ":");
1599 if (!tstr1 || !tstr2) {
1600 fprintf(stderr, "Could not parse layout file.\n");
1601 exit(EXIT_FAILURE);
1602 }
1603 new_regions[region_number].base = strtol(tstr1,
1604 (char **)NULL, 16);
1605 new_regions[region_number].limit = strtol(tstr2,
1606 (char **)NULL, 16);
1607 new_regions[region_number].size =
1608 new_regions[region_number].limit -
1609 new_regions[region_number].base + 1;
1610
1611 if (new_regions[region_number].size < 0)
1612 new_regions[region_number].size = 0;
1613 }
1614 fclose(romlayout);
1615
1616 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001617 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001618 if (new_regions[i].size == 0)
1619 continue;
1620
1621 if (new_regions[i].size < current_regions[i].size) {
1622 printf("DANGER: Region %s is shrinking.\n",
1623 region_name(i));
1624 printf(" The region will be truncated to fit.\n");
1625 printf(" This may result in an unusable image.\n");
1626 }
1627
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001628 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001629 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001630 fprintf(stderr, "Regions would overlap.\n");
1631 exit(EXIT_FAILURE);
1632 }
1633 }
1634
1635 /* detect if the image size should grow */
1636 if (new_extent < new_regions[i].limit)
1637 new_extent = new_regions[i].limit;
1638 }
1639
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001640 /* check if the image is actually a Flash Descriptor region */
1641 if (size == new_regions[0].size) {
1642 printf("The image is a single Flash Descriptor:\n");
1643 printf(" Only the descriptor will be modified\n");
1644 new_extent = size;
1645 } else {
1646 new_extent = next_pow2(new_extent - 1);
1647 if (new_extent != size) {
1648 printf("The image has changed in size.\n");
1649 printf("The old image is %d bytes.\n", size);
1650 printf("The new image is %d bytes.\n", new_extent);
1651 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001652 }
1653
1654 /* copy regions to a new image */
1655 new_image = malloc(new_extent);
1656 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001657 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001658 int copy_size = new_regions[i].size;
1659 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001660 const region_t *current = &current_regions[i];
1661 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001662
Bill XIEfa5f9942017-09-12 11:22:29 +08001663 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001664 continue;
1665
Bill XIEfa5f9942017-09-12 11:22:29 +08001666 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001667 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001668 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001669 if (i == REGION_BIOS)
1670 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001671 }
1672
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001673 if ((i == REGION_BIOS) && (new->size < current->size)) {
1674 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001675 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001676 }
1677
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001678 if (size < current->base + offset_current + copy_size) {
1679 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1680 region_name(i));
1681 continue;
1682 };
1683
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001684 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1685 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001686 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1687 offset_current, current->limit, current->size);
1688 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1689 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001690
Bill XIEfa5f9942017-09-12 11:22:29 +08001691 memcpy(new_image + new->base + offset_new,
1692 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001693 copy_size);
1694 }
1695
1696 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001697 frba = find_frba(new_image, new_extent);
1698 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001699 exit(EXIT_FAILURE);
1700
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001701 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001702 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001703 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001704
1705 write_image(filename, new_image, new_extent);
1706 free(new_image);
1707}
1708
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001709static void print_version(void)
1710{
1711 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1712 printf("Copyright (C) 2011 Google Inc.\n\n");
1713 printf
1714 ("This program is free software: you can redistribute it and/or modify\n"
1715 "it under the terms of the GNU General Public License as published by\n"
1716 "the Free Software Foundation, version 2 of the License.\n\n"
1717 "This program is distributed in the hope that it will be useful,\n"
1718 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1719 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001720 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001721}
1722
1723static void print_usage(const char *name)
1724{
1725 printf("usage: %s [-vhdix?] <filename>\n", name);
1726 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001727 " -d | --dump: dump intel firmware descriptor\n"
1728 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1729 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1730 " -x | --extract: extract intel fd modules\n"
1731 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1732 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001733 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001734 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1735 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1736 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1737 " can only be used once per run:\n"
1738 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1739 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1740 " Dual Output Fast Read Support\n"
1741 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301742 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001743 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001744 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1745 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001746 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301747 " adl - Alder Lake\n"
1748 " aplk - Apollo Lake\n"
1749 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001750 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001751 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001752 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301753 " glk - Gemini Lake\n"
1754 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001755 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301756 " jsl - Jasper Lake\n"
1757 " sklkbl - Sky Lake/Kaby Lake\n"
1758 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001759 " -S | --setpchstrap Write a PCH strap\n"
1760 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001761 " -v | --version: print the version\n"
1762 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001763 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1764 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001765 "\n");
1766}
1767
1768int main(int argc, char *argv[])
1769{
1770 int opt, option_index = 0;
1771 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001772 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001773 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301774 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001775 char *region_type_string = NULL, *region_fname = NULL;
1776 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001777 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001778 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001779 unsigned int value = 0;
1780 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001781 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001782 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1783
Bill XIEfa5f9942017-09-12 11:22:29 +08001784 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001785 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001786 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001787 {"extract", 0, NULL, 'x'},
1788 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001789 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001790 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001791 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001792 {"density", 1, NULL, 'D'},
1793 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001794 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001795 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001796 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301797 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001798 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001799 {"version", 0, NULL, 'v'},
1800 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001801 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001802 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001803 {"setpchstrap", 1, NULL, 'S'},
1804 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001805 {0, 0, 0, 0}
1806 };
1807
Usha P412679d2020-10-15 11:25:08 +05301808 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 -07001809 long_options, &option_index)) != EOF) {
1810 switch (opt) {
1811 case 'd':
1812 mode_dump = 1;
1813 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001814 case 'S':
1815 mode_setstrap = 1;
1816 pchstrap = strtoul(optarg, NULL, 0);
1817 break;
1818 case 'V':
1819 value = strtoul(optarg, NULL, 0);
1820 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001821 case 'f':
1822 mode_layout = 1;
1823 layout_fname = strdup(optarg);
1824 if (!layout_fname) {
1825 fprintf(stderr, "No layout file specified\n");
1826 print_usage(argv[0]);
1827 exit(EXIT_FAILURE);
1828 }
1829 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001830 case 'x':
1831 mode_extract = 1;
1832 break;
1833 case 'i':
1834 // separate type and file name
1835 region_type_string = strdup(optarg);
1836 region_fname = strchr(region_type_string, ':');
1837 if (!region_fname) {
1838 print_usage(argv[0]);
1839 exit(EXIT_FAILURE);
1840 }
1841 region_fname[0] = '\0';
1842 region_fname++;
1843 // Descriptor, BIOS, ME, GbE, Platform
1844 // valid type?
1845 if (!strcasecmp("Descriptor", region_type_string))
1846 region_type = 0;
1847 else if (!strcasecmp("BIOS", region_type_string))
1848 region_type = 1;
1849 else if (!strcasecmp("ME", region_type_string))
1850 region_type = 2;
1851 else if (!strcasecmp("GbE", region_type_string))
1852 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001853 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001854 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001855 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001856 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001857 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001858 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001859 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001860 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001861 else if (!strcasecmp("EC", region_type_string))
1862 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001863 else if (!strcasecmp("Device Exp2", region_type_string))
1864 region_type = 9;
1865 else if (!strcasecmp("IE", region_type_string))
1866 region_type = 10;
1867 else if (!strcasecmp("10GbE_0", region_type_string))
1868 region_type = 11;
1869 else if (!strcasecmp("10GbE_1", region_type_string))
1870 region_type = 12;
1871 else if (!strcasecmp("PTT", region_type_string))
1872 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001873 if (region_type == -1) {
1874 fprintf(stderr, "No such region type: '%s'\n\n",
1875 region_type_string);
1876 print_usage(argv[0]);
1877 exit(EXIT_FAILURE);
1878 }
1879 mode_inject = 1;
1880 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001881 case 'n':
1882 mode_newlayout = 1;
1883 layout_fname = strdup(optarg);
1884 if (!layout_fname) {
1885 fprintf(stderr, "No layout file specified\n");
1886 print_usage(argv[0]);
1887 exit(EXIT_FAILURE);
1888 }
1889 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001890 case 'O':
1891 new_filename = strdup(optarg);
1892 if (!new_filename) {
1893 fprintf(stderr, "No output filename specified\n");
1894 print_usage(argv[0]);
1895 exit(EXIT_FAILURE);
1896 }
1897 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001898 case 'D':
1899 mode_density = 1;
1900 new_density = strtoul(optarg, NULL, 0);
1901 switch (new_density) {
1902 case 512:
1903 new_density = COMPONENT_DENSITY_512KB;
1904 break;
1905 case 1:
1906 new_density = COMPONENT_DENSITY_1MB;
1907 break;
1908 case 2:
1909 new_density = COMPONENT_DENSITY_2MB;
1910 break;
1911 case 4:
1912 new_density = COMPONENT_DENSITY_4MB;
1913 break;
1914 case 8:
1915 new_density = COMPONENT_DENSITY_8MB;
1916 break;
1917 case 16:
1918 new_density = COMPONENT_DENSITY_16MB;
1919 break;
1920 case 32:
1921 new_density = COMPONENT_DENSITY_32MB;
1922 break;
1923 case 64:
1924 new_density = COMPONENT_DENSITY_64MB;
1925 break;
1926 case 0:
1927 new_density = COMPONENT_DENSITY_UNUSED;
1928 break;
1929 default:
1930 printf("error: Unknown density\n");
1931 print_usage(argv[0]);
1932 exit(EXIT_FAILURE);
1933 }
1934 break;
1935 case 'C':
1936 selected_chip = strtol(optarg, NULL, 0);
1937 if (selected_chip > 2) {
1938 fprintf(stderr, "error: Invalid chip selection\n");
1939 print_usage(argv[0]);
1940 exit(EXIT_FAILURE);
1941 }
1942 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001943 case 'M':
1944 mode_altmedisable = 1;
1945 altmedisable = strtol(optarg, NULL, 0);
1946 if (altmedisable > 1) {
1947 fprintf(stderr, "error: Illegal value\n");
1948 print_usage(argv[0]);
1949 exit(EXIT_FAILURE);
1950 }
1951 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001952 case 's':
1953 // Parse the requested SPI frequency
1954 inputfreq = strtol(optarg, NULL, 0);
1955 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001956 case 17:
1957 spifreq = SPI_FREQUENCY_17MHZ;
1958 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001959 case 20:
1960 spifreq = SPI_FREQUENCY_20MHZ;
1961 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001962 case 30:
1963 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1964 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001965 case 33:
1966 spifreq = SPI_FREQUENCY_33MHZ;
1967 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001968 case 48:
1969 spifreq = SPI_FREQUENCY_48MHZ;
1970 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001971 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001972 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001973 break;
1974 default:
1975 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1976 inputfreq);
1977 print_usage(argv[0]);
1978 exit(EXIT_FAILURE);
1979 }
1980 mode_spifreq = 1;
1981 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001982 case 'e':
1983 mode_em100 = 1;
1984 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001985 case 'l':
1986 mode_locked = 1;
1987 if (mode_unlocked == 1) {
1988 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1989 exit(EXIT_FAILURE);
1990 }
1991 break;
Usha P412679d2020-10-15 11:25:08 +05301992 case 'r':
1993 mode_read = 1;
1994 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001995 case 'u':
1996 mode_unlocked = 1;
1997 if (mode_locked == 1) {
1998 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1999 exit(EXIT_FAILURE);
2000 }
2001 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002002 case 'p':
2003 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002004 platform = PLATFORM_APL;
2005 } else if (!strcmp(optarg, "cnl")) {
2006 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002007 } else if (!strcmp(optarg, "lbg")) {
2008 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002009 } else if (!strcmp(optarg, "dnv")) {
2010 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002011 } else if (!strcmp(optarg, "ehl")) {
2012 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002013 } else if (!strcmp(optarg, "glk")) {
2014 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302015 } else if (!strcmp(optarg, "icl")) {
2016 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302017 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002018 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002019 } else if (!strcmp(optarg, "sklkbl")) {
2020 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002021 } else if (!strcmp(optarg, "tgl")) {
2022 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302023 } else if (!strcmp(optarg, "adl")) {
2024 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002025 } else if (!strcmp(optarg, "ifd2")) {
2026 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302027 } else if (!strcmp(optarg, "mtl")) {
2028 platform = PLATFORM_MTL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002029 } else {
2030 fprintf(stderr, "Unknown platform: %s\n", optarg);
2031 exit(EXIT_FAILURE);
2032 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002033 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07002034 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002035 case 't':
2036 mode_validate = 1;
2037 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002038 case 'v':
2039 print_version();
2040 exit(EXIT_SUCCESS);
2041 break;
2042 case 'h':
2043 case '?':
2044 default:
2045 print_usage(argv[0]);
2046 exit(EXIT_SUCCESS);
2047 break;
2048 }
2049 }
2050
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002051 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002052 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05002053 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002054 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002055 print_usage(argv[0]);
2056 exit(EXIT_FAILURE);
2057 }
2058
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002059 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002060 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06002061 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002062 fprintf(stderr, "You need to specify a mode.\n\n");
2063 print_usage(argv[0]);
2064 exit(EXIT_FAILURE);
2065 }
2066
2067 if (optind + 1 != argc) {
2068 fprintf(stderr, "You need to specify a file.\n\n");
2069 print_usage(argv[0]);
2070 exit(EXIT_FAILURE);
2071 }
2072
2073 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002074 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002075 if (bios_fd == -1) {
2076 perror("Could not open file");
2077 exit(EXIT_FAILURE);
2078 }
2079 struct stat buf;
2080 if (fstat(bios_fd, &buf) == -1) {
2081 perror("Could not stat file");
2082 exit(EXIT_FAILURE);
2083 }
2084 int size = buf.st_size;
2085
2086 printf("File %s is %d bytes\n", filename, size);
2087
2088 char *image = malloc(size);
2089 if (!image) {
2090 printf("Out of memory.\n");
2091 exit(EXIT_FAILURE);
2092 }
2093
2094 if (read(bios_fd, image, size) != size) {
2095 perror("Could not read file");
2096 exit(EXIT_FAILURE);
2097 }
2098
2099 close(bios_fd);
2100
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002101 // generate new filename
2102 if (new_filename == NULL) {
2103 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2104 if (!new_filename) {
2105 printf("Out of memory.\n");
2106 exit(EXIT_FAILURE);
2107 }
2108 // - 5: leave room for ".new\0"
2109 strcpy(new_filename, filename);
2110 strcat(new_filename, ".new");
2111 }
2112
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002113 check_ifd_version(image, size);
2114
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002115 if (mode_dump)
2116 dump_fd(image, size);
2117
Chris Douglass03ce0142014-02-26 13:30:13 -05002118 if (mode_layout)
2119 dump_layout(image, size, layout_fname);
2120
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002121 if (mode_extract)
2122 write_regions(image, size);
2123
Mathew Kingc7ddc992019-08-08 14:59:25 -06002124 if (mode_validate)
2125 validate_layout(image, size);
2126
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002127 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002128 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002129 region_fname);
2130
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002131 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002132 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002133
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002134 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002135 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002136
Jan Tatjefa317512016-03-11 00:52:07 +01002137 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002138 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002139
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002140 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002141 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002142
Alexander Couzensd12ea112016-09-10 13:33:05 +02002143 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002144 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002145
Usha P412679d2020-10-15 11:25:08 +05302146 if (mode_read)
2147 enable_cpu_read_me(new_filename, image, size);
2148
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002149 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002150 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002151
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002152 if (mode_setstrap) {
2153 fpsba_t *fpsba = find_fpsba(image, size);
2154 const fdbar_t *fdb = find_fd(image, size);
2155 set_pchstrap(fpsba, fdb, pchstrap, value);
2156 write_image(new_filename, image, size);
2157 }
2158
Bill XIEb3e15a22017-09-07 18:34:50 +08002159 if (mode_altmedisable) {
2160 fpsba_t *fpsba = find_fpsba(image, size);
2161 fmsba_t *fmsba = find_fmsba(image, size);
2162 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002163 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002164 }
2165
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002166 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002167 free(image);
2168
2169 return 0;
2170}