blob: a5c0b6977aeace2c1485622eb2d9f64d67991819 [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
Duncan Laurie1f7fd722015-06-22 11:14:48 -070047static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080048static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080049static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010050static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070051static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050052
Duncan Laurie1f7fd722015-06-22 11:14:48 -070053static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060054 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
55 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
56 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
57 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
58 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
Jeff Daly3623eca2022-01-05 23:51:40 -050059 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
60 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
61 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060062 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050063 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
64 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
65 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
66 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
67 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
68 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
69 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050070};
71
Bill XIEb3e15a22017-09-07 18:34:50 +080072/* port from flashrom */
73static const char *const ich_chipset_names[] = {
74 "Unknown ICH",
75 "ICH",
76 "ICH2345",
77 "ICH6",
78 "SCH U",
79 "Atom E6xx",
80 "Atom S1220 S1240 S1260",
81 "ICH7",
82 "ICH8",
83 "ICH9",
84 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053085 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080086 "5 series Ibex Peak",
87 "6 series Cougar Point",
88 "7 series Panther Point",
89 "8 series Lynx Point",
90 "Baytrail",
91 "8 series Lynx Point LP",
92 "8 series Wellsburg",
93 "9 series Wildcat Point",
94 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053095 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053096 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053097 "Jasper Lake: N6xxx, N51xx, N45xx",
98 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053099 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +0530100 "300 series Cannon Point",
101 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +0530102 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +0800103 "C620 series Lewisburg",
104 NULL
105};
106
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700107static fdbar_t *find_fd(char *image, int size)
108{
109 int i, found = 0;
110
111 /* Scan for FD signature */
112 for (i = 0; i < (size - 4); i += 4) {
113 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
114 found = 1;
115 break; // signature found.
116 }
117 }
118
119 if (!found) {
120 printf("No Flash Descriptor found in this image\n");
121 return NULL;
122 }
123
Bill XIE612ec0e2017-08-30 16:10:27 +0800124 fdbar_t *fdb = (fdbar_t *) (image + i);
125 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
126}
127
Stefan Tauner0d226142018-08-05 18:56:53 +0200128static char *find_flumap(char *image, int size)
129{
130 /* The upper map is located in the word before the 256B-long OEM section
131 * at the end of the 4kB-long flash descriptor. In the official
132 * documentation this is defined as FDBAR + 0xEFC. However, starting
133 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
134 * has moved 16 bytes back to offset 0x10 of the image. Although
135 * official documentation still maintains the offset relative to FDBAR
136 * this is wrong and a simple fixed offset from the start of the image
137 * works.
138 */
139 char *flumap = image + 4096 - 256 - 4;
140 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
141}
142
Bill XIE612ec0e2017-08-30 16:10:27 +0800143static fcba_t *find_fcba(char *image, int size)
144{
145 fdbar_t *fdb = find_fd(image, size);
146 if (!fdb)
147 return NULL;
148 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
149 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
150
151}
152
153static fmba_t *find_fmba(char *image, int size)
154{
155 fdbar_t *fdb = find_fd(image, size);
156 if (!fdb)
157 return NULL;
158 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
159 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
160}
161
162static frba_t *find_frba(char *image, int size)
163{
164 fdbar_t *fdb = find_fd(image, size);
165 if (!fdb)
166 return NULL;
167 frba_t *frba =
168 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
169 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
170}
171
172static fpsba_t *find_fpsba(char *image, int size)
173{
174 fdbar_t *fdb = find_fd(image, size);
175 if (!fdb)
176 return NULL;
177 fpsba_t *fpsba =
178 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200179
180 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
181 if ((((char *)fpsba) + SSL) >= (image + size))
182 return NULL;
183 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800184}
185
186static fmsba_t *find_fmsba(char *image, int size)
187{
188 fdbar_t *fdb = find_fd(image, size);
189 if (!fdb)
190 return NULL;
191 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
192 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700193}
194
Bill XIEb3e15a22017-09-07 18:34:50 +0800195/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530196static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800197{
Subrata Banik8c082e52021-06-10 23:02:29 +0530198 const fdbar_t *fdb = find_fd(image, size);
199 if (!fdb)
200 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800201 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
202 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
203 uint32_t isl = (fdb->flmap1 >> 24);
204 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
Subrata Banik89db2252020-08-26 14:49:17 +0530205
206 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800207 if (iccriba == 0x00) {
208 if (msl == 0 && isl <= 2)
209 return CHIPSET_ICH8;
210 else if (isl <= 2)
211 return CHIPSET_ICH9;
212 else if (isl <= 10)
213 return CHIPSET_ICH10;
214 else if (isl <= 16)
215 return CHIPSET_5_SERIES_IBEX_PEAK;
216 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
217 return CHIPSET_5_SERIES_IBEX_PEAK;
218 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
219 if (msl == 0 && isl <= 17)
220 return CHIPSET_BAYTRAIL;
221 else if (msl <= 1 && isl <= 18)
222 return CHIPSET_6_SERIES_COUGAR_POINT;
223 else if (msl <= 1 && isl <= 21)
224 return CHIPSET_8_SERIES_LYNX_POINT;
225 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
226 return CHIPSET_9_SERIES_WILDCAT_POINT;
227 } else if (nm == 6) {
228 return CHIPSET_C620_SERIES_LEWISBURG;
Bill XIEb3e15a22017-09-07 18:34:50 +0800229 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200230 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800231}
232
Subrata Banik8c082e52021-06-10 23:02:29 +0530233static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
234{
235 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530236 case PLATFORM_APL:
237 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530238 case PLATFORM_GLK:
239 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
240 case PLATFORM_JSL:
241 return CHIPSET_N_SERIES_JASPER_LAKE;
242 case PLATFORM_EHL:
243 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200244 case PLATFORM_SKLKBL:
245 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530246 case PLATFORM_CNL:
247 return CHIPSET_300_SERIES_CANNON_POINT;
248 case PLATFORM_TGL:
249 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800250 case PLATFORM_IFD2:
Subrata Banik8c082e52021-06-10 23:02:29 +0530251 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
252 case PLATFORM_ICL:
253 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800254 case PLATFORM_LBG:
255 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500256 case PLATFORM_DNV:
257 return CHIPSET_DENVERTON;
Subrata Banik8c082e52021-06-10 23:02:29 +0530258 default:
259 return CHIPSET_PCH_UNKNOWN;
260 }
261}
262
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700263/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700264 * Some newer platforms have re-defined the FCBA field that was used to
265 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
266 * have the required FCBA field, but are IFD v2 and return true if current
267 * platform is one of them.
268 */
269static int is_platform_ifd_2(void)
270{
271 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530272 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700273 PLATFORM_GLK,
274 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800275 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500276 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530277 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700278 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530279 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700280 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530281 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200282 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800283 PLATFORM_IFD2,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700284 };
285 unsigned int i;
286
287 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
288 if (platform == ifd_2_platforms[i])
289 return 1;
290 }
291
292 return 0;
293}
294
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700295static void check_ifd_version(char *image, int size)
296{
Subrata Banik8c082e52021-06-10 23:02:29 +0530297 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700298 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530299 chipset = ifd2_platform_to_chipset(platform);
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700300 max_regions = MAX_REGIONS;
Subrata Banik8c082e52021-06-10 23:02:29 +0530301 } else {
302 ifd_version = IFD_VERSION_1;
303 chipset = ifd1_guess_chipset(image, size);
304 max_regions = MAX_REGIONS_OLD;
305 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700306}
307
Bill XIEfa5f9942017-09-12 11:22:29 +0800308static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700309{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500310 int base_mask;
311 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700312 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700313 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500314
315 if (ifd_version >= IFD_VERSION_2)
316 base_mask = 0x7fff;
317 else
318 base_mask = 0xfff;
319
320 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700321
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400322 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800323 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700324 exit (EXIT_FAILURE);
325 }
326
Bill XIE4651d452017-09-12 11:54:48 +0800327 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700328 region.base = (flreg & base_mask) << 12;
329 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700330 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500331
Chris Douglass03ce0142014-02-26 13:30:13 -0500332 if (region.size < 0)
333 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700334
335 return region;
336}
337
Bill XIEfa5f9942017-09-12 11:22:29 +0800338static void set_region(frba_t *frba, unsigned int region_type,
339 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500340{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400341 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800342 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500343 exit (EXIT_FAILURE);
344 }
Bill XIE4651d452017-09-12 11:54:48 +0800345
346 frba->flreg[region_type] =
347 (((region->limit >> 12) & 0x7fff) << 16) |
348 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500349}
350
Bill XIEfa5f9942017-09-12 11:22:29 +0800351static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700352{
Bill XIEfa5f9942017-09-12 11:22:29 +0800353 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700354 fprintf(stderr, "Invalid region type.\n");
355 exit (EXIT_FAILURE);
356 }
357
Chris Douglass03ce0142014-02-26 13:30:13 -0500358 return region_names[region_type].pretty;
359}
360
Bill XIEfa5f9942017-09-12 11:22:29 +0800361static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500362{
Bill XIEfa5f9942017-09-12 11:22:29 +0800363 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500364 fprintf(stderr, "Invalid region type.\n");
365 exit (EXIT_FAILURE);
366 }
367
368 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700369}
370
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500371static int region_num(const char *name)
372{
Bill XIEfa5f9942017-09-12 11:22:29 +0800373 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500374
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200375 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500376 if (strcasecmp(name, region_names[i].pretty) == 0)
377 return i;
378 if (strcasecmp(name, region_names[i].terse) == 0)
379 return i;
380 }
381
382 return -1;
383}
384
Bill XIEfa5f9942017-09-12 11:22:29 +0800385static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700386{
Bill XIEfa5f9942017-09-12 11:22:29 +0800387 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700388 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700389 exit (EXIT_FAILURE);
390 }
391
Bill XIE1bf65062017-09-12 11:31:37 +0800392 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700393}
394
Bill XIEfa5f9942017-09-12 11:22:29 +0800395static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700396{
397 region_t region = get_region(frba, num);
398 printf(" Flash Region %d (%s): %08x - %08x %s\n",
399 num, region_name(num), region.base, region.limit,
400 region.size < 1 ? "(unused)" : "");
401}
402
Bill XIEfa5f9942017-09-12 11:22:29 +0800403static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
404 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500405{
406 region_t region = get_region(frba, num);
407 snprintf(buf, bufsize, "%08x:%08x %s\n",
408 region.base, region.limit, region_name_short(num));
409}
410
Bill XIEfa5f9942017-09-12 11:22:29 +0800411static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700412{
Bill XIE4651d452017-09-12 11:54:48 +0800413 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530414 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700415 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800416 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530417 region = get_region(frba, i);
418 /* Skip unused & reserved Flash Region */
419 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
420 continue;
421
Bill XIE4651d452017-09-12 11:54:48 +0800422 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
423 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700424 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700425}
426
Bill XIEfa5f9942017-09-12 11:22:29 +0800427static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500428{
429 char buf[LAYOUT_LINELEN];
430 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800431 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500432
433 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
434 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
435 if (layout_fd == -1) {
436 perror("Could not open file");
437 exit(EXIT_FAILURE);
438 }
439
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200440 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200441 region_t region = get_region(frba, i);
442 /* is region invalid? */
443 if (region.size < 1)
444 continue;
445
Chris Douglass03ce0142014-02-26 13:30:13 -0500446 dump_region_layout(buf, bufsize, i, frba);
447 if (write(layout_fd, buf, strlen(buf)) < 0) {
448 perror("Could not write to file");
449 exit(EXIT_FAILURE);
450 }
451 }
452 close(layout_fd);
453 printf("Wrote layout to %s\n", layout_fname);
454}
455
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530456static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700457{
458 switch (freq) {
459 case SPI_FREQUENCY_20MHZ:
460 printf("20MHz");
461 break;
462 case SPI_FREQUENCY_33MHZ:
463 printf("33MHz");
464 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700465 case SPI_FREQUENCY_48MHZ:
466 printf("48MHz");
467 break;
468 case SPI_FREQUENCY_50MHZ_30MHZ:
469 switch (ifd_version) {
470 case IFD_VERSION_1:
471 printf("50MHz");
472 break;
473 case IFD_VERSION_2:
474 printf("30MHz");
475 break;
476 }
477 break;
478 case SPI_FREQUENCY_17MHZ:
479 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700480 break;
481 default:
482 printf("unknown<%x>MHz", freq);
483 }
484}
485
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530486static void _decode_spi_frequency_500_series(unsigned int freq)
487{
488 switch (freq) {
489 case SPI_FREQUENCY_100MHZ:
490 printf("100MHz");
491 break;
492 case SPI_FREQUENCY_50MHZ:
493 printf("50MHz");
494 break;
495 case SPI_FREQUENCY_500SERIES_33MHZ:
496 printf("33MHz");
497 break;
498 case SPI_FREQUENCY_25MHZ:
499 printf("25MHz");
500 break;
501 case SPI_FREQUENCY_14MHZ:
502 printf("14MHz");
503 break;
504 default:
505 printf("unknown<%x>MHz", freq);
506 }
507}
508
509static void decode_spi_frequency(unsigned int freq)
510{
Subrata Banika5f47812020-09-29 11:43:01 +0530511 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530512 _decode_spi_frequency_500_series(freq);
513 else
514 _decode_spi_frequency(freq);
515}
516
Subrata Banike5d39922020-08-26 16:01:42 +0530517static void _decode_espi_frequency(unsigned int freq)
518{
519 switch (freq) {
520 case ESPI_FREQUENCY_20MHZ:
521 printf("20MHz");
522 break;
523 case ESPI_FREQUENCY_24MHZ:
524 printf("24MHz");
525 break;
526 case ESPI_FREQUENCY_30MHZ:
527 printf("30MHz");
528 break;
529 case ESPI_FREQUENCY_48MHZ:
530 printf("48MHz");
531 break;
532 case ESPI_FREQUENCY_60MHZ:
533 printf("60MHz");
534 break;
535 case ESPI_FREQUENCY_17MHZ:
536 printf("17MHz");
537 break;
538 default:
539 printf("unknown<%x>MHz", freq);
540 }
541}
542
543static void _decode_espi_frequency_500_series(unsigned int freq)
544{
545 switch (freq) {
546 case ESPI_FREQUENCY_500SERIES_20MHZ:
547 printf("20MHz");
548 break;
549 case ESPI_FREQUENCY_500SERIES_24MHZ:
550 printf("24MHz");
551 break;
552 case ESPI_FREQUENCY_500SERIES_25MHZ:
553 printf("25MHz");
554 break;
555 case ESPI_FREQUENCY_500SERIES_48MHZ:
556 printf("48MHz");
557 break;
558 case ESPI_FREQUENCY_500SERIES_60MHZ:
559 printf("60MHz");
560 break;
561 default:
562 printf("unknown<%x>MHz", freq);
563 }
564}
565
566static void decode_espi_frequency(unsigned int freq)
567{
Subrata Banika5f47812020-09-29 11:43:01 +0530568 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530569 _decode_espi_frequency_500_series(freq);
570 else
571 _decode_espi_frequency(freq);
572}
573
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700574static void decode_component_density(unsigned int density)
575{
576 switch (density) {
577 case COMPONENT_DENSITY_512KB:
578 printf("512KB");
579 break;
580 case COMPONENT_DENSITY_1MB:
581 printf("1MB");
582 break;
583 case COMPONENT_DENSITY_2MB:
584 printf("2MB");
585 break;
586 case COMPONENT_DENSITY_4MB:
587 printf("4MB");
588 break;
589 case COMPONENT_DENSITY_8MB:
590 printf("8MB");
591 break;
592 case COMPONENT_DENSITY_16MB:
593 printf("16MB");
594 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700595 case COMPONENT_DENSITY_32MB:
596 printf("32MB");
597 break;
598 case COMPONENT_DENSITY_64MB:
599 printf("64MB");
600 break;
601 case COMPONENT_DENSITY_UNUSED:
602 printf("UNUSED");
603 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700604 default:
605 printf("unknown<%x>MB", density);
606 }
607}
608
Subrata Banik26058dc2020-08-26 15:12:16 +0530609static int is_platform_with_pch(void)
610{
611 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
612 return 1;
613
614 return 0;
615}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530616
617/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
618static int is_platform_with_100x_series_pch(void)
619{
620 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530621 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530622 return 1;
623
624 return 0;
625}
626
Subrata Banike5d39922020-08-26 16:01:42 +0530627static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700628{
Subrata Banike5d39922020-08-26 16:01:42 +0530629 unsigned int freq;
630
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700631 printf("\nFound Component Section\n");
632 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700633 printf(" Dual Output Fast Read Support: %ssupported\n",
634 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700635 printf(" Read ID/Read Status Clock Frequency: ");
636 decode_spi_frequency((fcba->flcomp >> 27) & 7);
637 printf("\n Write/Erase Clock Frequency: ");
638 decode_spi_frequency((fcba->flcomp >> 24) & 7);
639 printf("\n Fast Read Clock Frequency: ");
640 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700641 printf("\n Fast Read Support: %ssupported",
642 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530643 if (is_platform_with_100x_series_pch() &&
644 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
645 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530646 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530647 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
648 else
649 freq = (fcba->flcomp >> 17) & 7;
650 decode_espi_frequency(freq);
651 } else {
652 printf("\n Read Clock Frequency: ");
653 decode_spi_frequency((fcba->flcomp >> 17) & 7);
654 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700655
656 switch (ifd_version) {
657 case IFD_VERSION_1:
658 printf("\n Component 2 Density: ");
659 decode_component_density((fcba->flcomp >> 3) & 7);
660 printf("\n Component 1 Density: ");
661 decode_component_density(fcba->flcomp & 7);
662 break;
663 case IFD_VERSION_2:
664 printf("\n Component 2 Density: ");
665 decode_component_density((fcba->flcomp >> 4) & 0xf);
666 printf("\n Component 1 Density: ");
667 decode_component_density(fcba->flcomp & 0xf);
668 break;
669 }
670
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700671 printf("\n");
672 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700673 printf(" Invalid Instruction 3: 0x%02x\n",
674 (fcba->flill >> 24) & 0xff);
675 printf(" Invalid Instruction 2: 0x%02x\n",
676 (fcba->flill >> 16) & 0xff);
677 printf(" Invalid Instruction 1: 0x%02x\n",
678 (fcba->flill >> 8) & 0xff);
679 printf(" Invalid Instruction 0: 0x%02x\n",
680 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530681 if (is_platform_with_100x_series_pch()) {
682 printf("FLILL1 0x%08x\n", fcba->flpb);
683 printf(" Invalid Instruction 7: 0x%02x\n",
684 (fcba->flpb >> 24) & 0xff);
685 printf(" Invalid Instruction 6: 0x%02x\n",
686 (fcba->flpb >> 16) & 0xff);
687 printf(" Invalid Instruction 5: 0x%02x\n",
688 (fcba->flpb >> 8) & 0xff);
689 printf(" Invalid Instruction 4: 0x%02x\n",
690 fcba->flpb & 0xff);
691 } else {
692 printf("FLPB 0x%08x\n", fcba->flpb);
693 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
694 (fcba->flpb & 0xfff) << 12);
695 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700696}
697
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200698static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700699{
Bill XIE4651d452017-09-12 11:54:48 +0800700 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200701 /* SoC Strap Length, aka PSL, aka ISL */
702 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
703
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700704 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200705 for (i = 0; i < SSL; i++)
706 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800707
708 if (ifd_version >= IFD_VERSION_2) {
709 printf("HAP bit is %sset\n",
710 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
711 } else if (chipset >= CHIPSET_ICH8
712 && chipset <= CHIPSET_ICH10) {
713 printf("ICH_MeDisable bit is %sset\n",
714 fpsba->pchstrp[0] & 1 ? "" : "not ");
715 } else {
716 printf("AltMeDisable bit is %sset\n",
717 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
718 }
719
Bill XIE4651d452017-09-12 11:54:48 +0800720 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700721}
722
723static void decode_flmstr(uint32_t flmstr)
724{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700725 int wr_shift, rd_shift;
726 if (ifd_version >= IFD_VERSION_2) {
727 wr_shift = FLMSTR_WR_SHIFT_V2;
728 rd_shift = FLMSTR_RD_SHIFT_V2;
729 } else {
730 wr_shift = FLMSTR_WR_SHIFT_V1;
731 rd_shift = FLMSTR_RD_SHIFT_V1;
732 }
733
734 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500735 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700736 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700737 (flmstr & (1 << (wr_shift + 8))) ?
738 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700739 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700740 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500741 if (PLATFORM_HAS_GBE_REGION) {
742 printf(" GbE Region Write Access: %s\n",
743 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
744 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700745 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700746 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700747 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700748 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700749 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700750 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500751 if (PLATFORM_HAS_10GBE_0_REGION) {
752 printf(" 10GbE_0 Write Access: %s\n",
753 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
754 }
755 if (PLATFORM_HAS_10GBE_1_REGION) {
756 printf(" 10GbE_1 Write Access: %s\n",
757 (flmstr & (1 << 4)) ? "enabled" : "disabled");
758 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700759
Jeff Dalyabd4b962022-01-06 00:52:30 -0500760 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700761 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700762 (flmstr & (1 << (rd_shift + 8))) ?
763 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700764 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700765 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500766 if (PLATFORM_HAS_GBE_REGION) {
767 printf(" GbE Region Read Access: %s\n",
768 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
769 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700770 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700771 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700772 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700773 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700774 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700775 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500776 if (PLATFORM_HAS_10GBE_0_REGION) {
777 printf(" 10GbE_0 Read Access: %s\n",
778 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
779 }
780 if (PLATFORM_HAS_10GBE_1_REGION) {
781 printf(" 10GbE_1 Read Access: %s\n",
782 (flmstr & (1 << 0)) ? "enabled" : "disabled");
783 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700784
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700785 /* Requestor ID doesn't exist for ifd 2 */
786 if (ifd_version < IFD_VERSION_2)
787 printf(" Requester ID: 0x%04x\n\n",
788 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700789}
790
Bill XIEfa5f9942017-09-12 11:22:29 +0800791static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700792{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700793 printf("Found Master Section\n");
794 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
795 decode_flmstr(fmba->flmstr1);
796 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
797 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500798 if (PLATFORM_HAS_GBE_REGION) {
799 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
800 decode_flmstr(fmba->flmstr3);
801 if (ifd_version >= IFD_VERSION_2) {
802 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
803 decode_flmstr(fmba->flmstr5);
804 }
805 } else {
806 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
807 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700808 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700809}
810
Bill XIEfa5f9942017-09-12 11:22:29 +0800811static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700812{
Bill XIE612ec0e2017-08-30 16:10:27 +0800813 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700814 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800815 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
816 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800817
818 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
819 printf("MCH_MeDisable bit is %sset\n",
820 fmsba->data[0] & 1 ? "" : "not ");
821 printf("MCH_AltMeDisable bit is %sset\n",
822 fmsba->data[0] & (1 << 7) ? "" : "not ");
823 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700824}
825
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700826static void dump_jid(uint32_t jid)
827{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100828 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700829 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100830 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200831 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100832 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200833 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700834}
835
836static void dump_vscc(uint32_t vscc)
837{
838 printf(" Lower Erase Opcode: 0x%02x\n",
839 vscc >> 24);
840 printf(" Lower Write Enable on Write Status: 0x%02x\n",
841 vscc & (1 << 20) ? 0x06 : 0x50);
842 printf(" Lower Write Status Required: %s\n",
843 vscc & (1 << 19) ? "Yes" : "No");
844 printf(" Lower Write Granularity: %d bytes\n",
845 vscc & (1 << 18) ? 64 : 1);
846 printf(" Lower Block / Sector Erase Size: ");
847 switch ((vscc >> 16) & 0x3) {
848 case 0:
849 printf("256 Byte\n");
850 break;
851 case 1:
852 printf("4KB\n");
853 break;
854 case 2:
855 printf("8KB\n");
856 break;
857 case 3:
858 printf("64KB\n");
859 break;
860 }
861
862 printf(" Upper Erase Opcode: 0x%02x\n",
863 (vscc >> 8) & 0xff);
864 printf(" Upper Write Enable on Write Status: 0x%02x\n",
865 vscc & (1 << 4) ? 0x06 : 0x50);
866 printf(" Upper Write Status Required: %s\n",
867 vscc & (1 << 3) ? "Yes" : "No");
868 printf(" Upper Write Granularity: %d bytes\n",
869 vscc & (1 << 2) ? 64 : 1);
870 printf(" Upper Block / Sector Erase Size: ");
871 switch (vscc & 0x3) {
872 case 0:
873 printf("256 Byte\n");
874 break;
875 case 1:
876 printf("4KB\n");
877 break;
878 case 2:
879 printf("8KB\n");
880 break;
881 case 3:
882 printf("64KB\n");
883 break;
884 }
885}
886
Bill XIEfa5f9942017-09-12 11:22:29 +0800887static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700888{
889 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200890 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
891 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700892
893 printf("ME VSCC table:\n");
894 for (i = 0; i < num; i++) {
895 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
896 dump_jid(vtba->entry[i].jid);
897 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
898 dump_vscc(vtba->entry[i].vscc);
899 }
900 printf("\n");
901}
902
Bill XIEfa5f9942017-09-12 11:22:29 +0800903static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700904{
905 int i, j;
906 printf("OEM Section:\n");
907 for (i = 0; i < 4; i++) {
908 printf("%02x:", i << 4);
909 for (j = 0; j < 16; j++)
910 printf(" %02x", oem[(i<<4)+j]);
911 printf ("\n");
912 }
913 printf ("\n");
914}
915
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700916static void dump_fd(char *image, int size)
917{
Bill XIE612ec0e2017-08-30 16:10:27 +0800918 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700919 if (!fdb)
920 exit(EXIT_FAILURE);
921
Subrata Banik26058dc2020-08-26 15:12:16 +0530922 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
923 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700924 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530925 if (!is_platform_with_100x_series_pch())
926 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700927 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
928 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
929 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
930
931 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530932 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
933 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700934 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
935 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
936 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
937
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530938 if (!is_platform_with_100x_series_pch()) {
939 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
940 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
941 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
942 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700943
Subrata Banika5f47812020-09-29 11:43:01 +0530944 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530945 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
946 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
947 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
948 }
949
Stefan Tauner0d226142018-08-05 18:56:53 +0200950 char *flumap = find_flumap(image, size);
951 uint32_t flumap1 = *(uint32_t *)flumap;
952 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700953 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200954 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700955 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200956 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700957 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200958 (image + ((flumap1 & 0xff) << 4)),
959 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800960 dump_oem((const uint8_t *)image + 0xf00);
961
962 const frba_t *frba = find_frba(image, size);
963 const fcba_t *fcba = find_fcba(image, size);
964 const fpsba_t *fpsba = find_fpsba(image, size);
965 const fmba_t *fmba = find_fmba(image, size);
966 const fmsba_t *fmsba = find_fmsba(image, size);
967
968 if (frba && fcba && fpsba && fmba && fmsba) {
969 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530970 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200971 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800972 dump_fmba(fmba);
973 dump_fmsba(fmsba);
974 } else {
975 printf("FD is corrupted!\n");
976 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700977}
978
Bill XIEfa5f9942017-09-12 11:22:29 +0800979static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500980{
Bill XIE612ec0e2017-08-30 16:10:27 +0800981 const frba_t *frba = find_frba(image, size);
982 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500983 exit(EXIT_FAILURE);
984
Bill XIE612ec0e2017-08-30 16:10:27 +0800985 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500986}
987
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700988static void write_regions(char *image, int size)
989{
Bill XIEfa5f9942017-09-12 11:22:29 +0800990 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800991 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700992
Bill XIE612ec0e2017-08-30 16:10:27 +0800993 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700994 exit(EXIT_FAILURE);
995
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700996 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700997 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700998 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700999 if (region.size > 0) {
1000 int region_fd;
1001 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -06001002 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001003 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001004 if (region_fd < 0) {
1005 perror("Error while trying to open file");
1006 exit(EXIT_FAILURE);
1007 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001008 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001009 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001010 close(region_fd);
1011 }
1012 }
1013}
1014
Mathew Kingc7ddc992019-08-08 14:59:25 -06001015static void validate_layout(char *image, int size)
1016{
1017 uint i, errors = 0;
1018 struct fmap *fmap;
1019 long int fmap_loc = fmap_find((uint8_t *)image, size);
1020 const frba_t *frba = find_frba(image, size);
1021
1022 if (fmap_loc < 0 || !frba)
1023 exit(EXIT_FAILURE);
1024
1025 fmap = (struct fmap *)(image + fmap_loc);
1026
1027 for (i = 0; i < max_regions; i++) {
1028 if (region_names[i].fmapname == NULL)
1029 continue;
1030
1031 region_t region = get_region(frba, i);
1032
1033 if (region.size == 0)
1034 continue;
1035
1036 const struct fmap_area *area =
1037 fmap_find_area(fmap, region_names[i].fmapname);
1038
1039 if (!area)
1040 continue;
1041
1042 if ((uint)region.base != area->offset ||
1043 (uint)region.size != area->size) {
1044 printf("Region mismatch between %s and %s\n",
1045 region_names[i].terse, area->name);
1046 printf(" Descriptor region %s:\n", region_names[i].terse);
1047 printf(" offset: 0x%08x\n", region.base);
1048 printf(" length: 0x%08x\n", region.size);
1049 printf(" FMAP area %s:\n", area->name);
1050 printf(" offset: 0x%08x\n", area->offset);
1051 printf(" length: 0x%08x\n", area->size);
1052 errors++;
1053 }
1054 }
1055
1056 if (errors > 0)
1057 exit(EXIT_FAILURE);
1058}
1059
Bill XIEfa5f9942017-09-12 11:22:29 +08001060static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001061{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001062 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001063 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001064
1065 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001066 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001067 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001068 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001069 if (new_fd < 0) {
1070 perror("Error while trying to open file");
1071 exit(EXIT_FAILURE);
1072 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001073 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001074 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001075 close(new_fd);
1076}
1077
Bill XIEfa5f9942017-09-12 11:22:29 +08001078static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001079 enum spi_frequency freq)
1080{
Bill XIE612ec0e2017-08-30 16:10:27 +08001081 fcba_t *fcba = find_fcba(image, size);
1082 if (!fcba)
1083 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001084
1085 /* clear bits 21-29 */
1086 fcba->flcomp &= ~0x3fe00000;
1087 /* Read ID and Read Status Clock Frequency */
1088 fcba->flcomp |= freq << 27;
1089 /* Write and Erase Clock Frequency */
1090 fcba->flcomp |= freq << 24;
1091 /* Fast Read Clock Frequency */
1092 fcba->flcomp |= freq << 21;
1093
1094 write_image(filename, image, size);
1095}
1096
Bill XIEfa5f9942017-09-12 11:22:29 +08001097static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001098{
Bill XIE612ec0e2017-08-30 16:10:27 +08001099 fcba_t *fcba = find_fcba(image, size);
1100 if (!fcba)
1101 exit(EXIT_FAILURE);
1102
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001103 int freq;
1104
1105 switch (ifd_version) {
1106 case IFD_VERSION_1:
1107 freq = SPI_FREQUENCY_20MHZ;
1108 break;
1109 case IFD_VERSION_2:
1110 freq = SPI_FREQUENCY_17MHZ;
1111 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001112 default:
1113 freq = SPI_FREQUENCY_17MHZ;
1114 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001115 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001116
1117 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001118 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001119}
1120
Bill XIEfa5f9942017-09-12 11:22:29 +08001121static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001122 unsigned int density)
1123{
Bill XIE612ec0e2017-08-30 16:10:27 +08001124 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001125 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001126 if (!fcba)
1127 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001128
1129 printf("Setting chip density to ");
1130 decode_component_density(density);
1131 printf("\n");
1132
1133 switch (ifd_version) {
1134 case IFD_VERSION_1:
1135 /* fail if selected density is not supported by this version */
1136 if ( (density == COMPONENT_DENSITY_32MB) ||
1137 (density == COMPONENT_DENSITY_64MB) ||
1138 (density == COMPONENT_DENSITY_UNUSED) ) {
1139 printf("error: Selected density not supported in IFD version 1.\n");
1140 exit(EXIT_FAILURE);
1141 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001142 mask = 0x7;
1143 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001144 break;
1145 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001146 mask = 0xf;
1147 chip2_offset = 4;
1148 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001149 default:
1150 printf("error: Unknown IFD version\n");
1151 exit(EXIT_FAILURE);
1152 break;
1153 }
1154
1155 /* clear chip density for corresponding chip */
1156 switch (selected_chip) {
1157 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001158 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001159 break;
1160 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001161 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001162 break;
1163 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001164 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001165 break;
1166 }
1167
1168 /* set the new density */
1169 if (selected_chip == 1 || selected_chip == 0)
1170 fcba->flcomp |= (density); /* first chip */
1171 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001172 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001173
1174 write_image(filename, image, size);
1175}
1176
Duncan Laurie7775d672019-06-06 13:39:26 -07001177static int check_region(const frba_t *frba, unsigned int region_type)
1178{
1179 region_t region;
1180
1181 if (!frba)
1182 return 0;
1183
1184 region = get_region(frba, region_type);
1185 return !!((region.base < region.limit) && (region.size > 0));
1186}
1187
Bill XIEfa5f9942017-09-12 11:22:29 +08001188static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001189{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001190 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001191 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001192 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001193 if (!fmba)
1194 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001195
1196 if (ifd_version >= IFD_VERSION_2) {
1197 wr_shift = FLMSTR_WR_SHIFT_V2;
1198 rd_shift = FLMSTR_RD_SHIFT_V2;
1199
1200 /* Clear non-reserved bits */
1201 fmba->flmstr1 &= 0xff;
1202 fmba->flmstr2 &= 0xff;
1203 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001204 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001205 } else {
1206 wr_shift = FLMSTR_WR_SHIFT_V1;
1207 rd_shift = FLMSTR_RD_SHIFT_V1;
1208
1209 fmba->flmstr1 = 0;
1210 fmba->flmstr2 = 0;
1211 /* Requestor ID */
1212 fmba->flmstr3 = 0x118;
1213 }
1214
Andrey Petrov96ecb772016-10-31 19:31:54 -07001215 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001216 case PLATFORM_APL:
1217 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001218 /* CPU/BIOS can read descriptor and BIOS */
1219 fmba->flmstr1 |= 0x3 << rd_shift;
1220 /* CPU/BIOS can write BIOS */
1221 fmba->flmstr1 |= 0x2 << wr_shift;
1222 /* TXE can read descriptor, BIOS and Device Expansion */
1223 fmba->flmstr2 |= 0x23 << rd_shift;
1224 /* TXE can only write Device Expansion */
1225 fmba->flmstr2 |= 0x20 << wr_shift;
1226 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001227 case PLATFORM_CNL:
1228 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001229 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001230 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301231 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001232 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301233 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001234 case PLATFORM_IFD2:
Duncan Laurie7775d672019-06-06 13:39:26 -07001235 /* CPU/BIOS can read descriptor and BIOS. */
1236 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1237 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1238 /* CPU/BIOS can write BIOS. */
1239 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1240 /* ME can read descriptor and ME. */
1241 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1242 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001243 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001244 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1245 if (check_region(frba, REGION_GBE)) {
1246 /* BIOS can read/write GbE. */
1247 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1248 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1249 /* ME can read GbE. */
1250 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1251 /* GbE can read descriptor and read/write GbE.. */
1252 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1253 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1254 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1255 }
1256 if (check_region(frba, REGION_PDR)) {
1257 /* BIOS can read/write PDR. */
1258 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1259 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1260 }
1261 if (check_region(frba, REGION_EC)) {
1262 /* BIOS can read EC. */
1263 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1264 /* EC can read descriptor and read/write EC. */
1265 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1266 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1267 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1268 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001269 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001270 case PLATFORM_DNV:
1271 /* CPU/BIOS can read descriptor and BIOS. */
1272 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1273 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1274 /* CPU/BIOS can write BIOS. */
1275 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1276 /* ME can read descriptor and ME. */
1277 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1278 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1279 /* ME can write ME. */
1280 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1281 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001282 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001283 /* CPU/BIOS can read descriptor and BIOS. */
1284 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1285 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1286 /* CPU/BIOS can write BIOS. */
1287 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1288 /* ME can read descriptor and ME. */
1289 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1290 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1291 /* ME can write ME. */
1292 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1293 if (check_region(frba, REGION_GBE)) {
1294 /* BIOS can read GbE. */
1295 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1296 /* BIOS can write GbE. */
1297 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1298 /* ME can read GbE. */
1299 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1300 /* ME can write GbE. */
1301 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1302 /* GbE can write GbE. */
1303 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1304 /* GbE can read GbE. */
1305 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1306 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001307 break;
1308 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001309
1310 write_image(filename, image, size);
1311}
1312
Usha P412679d2020-10-15 11:25:08 +05301313static void enable_cpu_read_me(const char *filename, char *image, int size)
1314{
1315 int rd_shift;
1316 fmba_t *fmba = find_fmba(image, size);
1317
1318 if (!fmba)
1319 exit(EXIT_FAILURE);
1320
1321 if (ifd_version >= IFD_VERSION_2)
1322 rd_shift = FLMSTR_RD_SHIFT_V2;
1323 else
1324 rd_shift = FLMSTR_RD_SHIFT_V1;
1325
1326 /* CPU/BIOS can read ME. */
1327 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1328
1329 write_image(filename, image, size);
1330}
1331
Bill XIEfa5f9942017-09-12 11:22:29 +08001332static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001333{
Bill XIE612ec0e2017-08-30 16:10:27 +08001334 fmba_t *fmba = find_fmba(image, size);
1335 if (!fmba)
1336 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001337
1338 if (ifd_version >= IFD_VERSION_2) {
1339 /* Access bits for each region are read: 19:8 write: 31:20 */
1340 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1341 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1342 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001343 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001344 } else {
1345 fmba->flmstr1 = 0xffff0000;
1346 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001347 /* Keep chipset specific Requester ID */
1348 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001349 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001350
1351 write_image(filename, image, size);
1352}
1353
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001354static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1355 const unsigned int value)
1356{
1357 if (!fpsba || !fdb) {
1358 fprintf(stderr, "Internal error\n");
1359 exit(EXIT_FAILURE);
1360 }
1361
1362 /* SoC Strap Length, aka PSL, aka ISL */
1363 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1364 if (strap >= SSL) {
1365 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1366 exit(EXIT_FAILURE);
1367 }
1368 fpsba->pchstrp[strap] = value;
1369}
1370
Bill XIEb3e15a22017-09-07 18:34:50 +08001371/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001372static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001373{
1374 if (ifd_version >= IFD_VERSION_2) {
1375 printf("%sting the HAP bit to %s Intel ME...\n",
1376 altmedisable?"Set":"Unset",
1377 altmedisable?"disable":"enable");
1378 if (altmedisable)
1379 fpsba->pchstrp[0] |= (1 << 16);
1380 else
1381 fpsba->pchstrp[0] &= ~(1 << 16);
1382 } else {
1383 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1384 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1385 "and MCH_AltMeDisable to %s Intel ME...\n",
1386 altmedisable?"Set":"Unset",
1387 altmedisable?"disable":"enable");
1388 if (altmedisable) {
1389 /* MCH_MeDisable */
1390 fmsba->data[0] |= 1;
1391 /* MCH_AltMeDisable */
1392 fmsba->data[0] |= (1 << 7);
1393 /* ICH_MeDisable */
1394 fpsba->pchstrp[0] |= 1;
1395 } else {
1396 fmsba->data[0] &= ~1;
1397 fmsba->data[0] &= ~(1 << 7);
1398 fpsba->pchstrp[0] &= ~1;
1399 }
1400 } else {
1401 printf("%sting the AltMeDisable to %s Intel ME...\n",
1402 altmedisable?"Set":"Unset",
1403 altmedisable?"disable":"enable");
1404 if (altmedisable)
1405 fpsba->pchstrp[10] |= (1 << 7);
1406 else
1407 fpsba->pchstrp[10] &= ~(1 << 7);
1408 }
1409 }
1410}
1411
Jacob Garber595d9262019-06-27 17:33:10 -06001412static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001413 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001414{
Bill XIE612ec0e2017-08-30 16:10:27 +08001415 frba_t *frba = find_frba(image, size);
1416 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001417 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001418
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001419 region_t region = get_region(frba, region_type);
1420 if (region.size <= 0xfff) {
1421 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1422 region_name(region_type));
1423 exit(EXIT_FAILURE);
1424 }
1425
Scott Duplichanf2c98372014-12-12 21:03:06 -06001426 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001427 if (region_fd == -1) {
1428 perror("Could not open file");
1429 exit(EXIT_FAILURE);
1430 }
1431 struct stat buf;
1432 if (fstat(region_fd, &buf) == -1) {
1433 perror("Could not stat file");
1434 exit(EXIT_FAILURE);
1435 }
1436 int region_size = buf.st_size;
1437
1438 printf("File %s is %d bytes\n", region_fname, region_size);
1439
1440 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001441 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001442 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1443 " bytes. Not injecting.\n",
1444 region_name(region_type), region.size,
1445 region.size, region_size, region_size);
1446 exit(EXIT_FAILURE);
1447 }
1448
1449 int offset = 0;
1450 if ((region_type == 1) && (region_size < region.size)) {
1451 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1452 " bytes. Padding before injecting.\n",
1453 region_name(region_type), region.size,
1454 region.size, region_size, region_size);
1455 offset = region.size - region_size;
1456 memset(image + region.base, 0xff, offset);
1457 }
1458
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001459 if (size < region.base + offset + region_size) {
1460 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1461 size, region.base + offset + region_size);
1462 exit(EXIT_FAILURE);
1463 }
1464
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001465 if (read(region_fd, image + region.base + offset, region_size)
1466 != region_size) {
1467 perror("Could not read file");
1468 exit(EXIT_FAILURE);
1469 }
1470
1471 close(region_fd);
1472
1473 printf("Adding %s as the %s section of %s\n",
1474 region_fname, region_name(region_type), filename);
1475 write_image(filename, image, size);
1476}
1477
Jacob Garber595d9262019-06-27 17:33:10 -06001478static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001479{
1480 unsigned int y = 1;
1481 if (x == 0)
1482 return 0;
1483 while (y <= x)
1484 y = y << 1;
1485
1486 return y;
1487}
1488
1489/**
1490 * Determine if two memory regions overlap.
1491 *
1492 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001493 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001494 * @return 1 if the two regions overlap
1495 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001496static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001497{
Bill XIEfa5f9942017-09-12 11:22:29 +08001498 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001499 return 0;
1500
Nico Huber844eda02019-01-05 00:06:19 +01001501 /* r1 should be either completely below or completely above r2 */
1502 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001503}
1504
Jacob Garber595d9262019-06-27 17:33:10 -06001505static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001506 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001507{
1508 FILE *romlayout;
1509 char tempstr[256];
1510 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001511 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001512 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001513 region_t current_regions[MAX_REGIONS];
1514 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001515 int new_extent = 0;
1516 char *new_image;
1517
1518 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001519 frba_t *frba = find_frba(image, size);
1520 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001521 exit(EXIT_FAILURE);
1522
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001523 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001524 current_regions[i] = get_region(frba, i);
1525 new_regions[i] = get_region(frba, i);
1526 }
1527
1528 /* read new layout */
1529 romlayout = fopen(layout_fname, "r");
1530
1531 if (!romlayout) {
1532 perror("Could not read layout file.\n");
1533 exit(EXIT_FAILURE);
1534 }
1535
1536 while (!feof(romlayout)) {
1537 char *tstr1, *tstr2;
1538
Patrick Georgi802ad522014-08-09 17:12:23 +02001539 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001540 layout_region_name))
1541 continue;
1542
1543 region_number = region_num(layout_region_name);
1544 if (region_number < 0)
1545 continue;
1546
1547 tstr1 = strtok(tempstr, ":");
1548 tstr2 = strtok(NULL, ":");
1549 if (!tstr1 || !tstr2) {
1550 fprintf(stderr, "Could not parse layout file.\n");
1551 exit(EXIT_FAILURE);
1552 }
1553 new_regions[region_number].base = strtol(tstr1,
1554 (char **)NULL, 16);
1555 new_regions[region_number].limit = strtol(tstr2,
1556 (char **)NULL, 16);
1557 new_regions[region_number].size =
1558 new_regions[region_number].limit -
1559 new_regions[region_number].base + 1;
1560
1561 if (new_regions[region_number].size < 0)
1562 new_regions[region_number].size = 0;
1563 }
1564 fclose(romlayout);
1565
1566 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001567 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001568 if (new_regions[i].size == 0)
1569 continue;
1570
1571 if (new_regions[i].size < current_regions[i].size) {
1572 printf("DANGER: Region %s is shrinking.\n",
1573 region_name(i));
1574 printf(" The region will be truncated to fit.\n");
1575 printf(" This may result in an unusable image.\n");
1576 }
1577
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001578 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001579 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001580 fprintf(stderr, "Regions would overlap.\n");
1581 exit(EXIT_FAILURE);
1582 }
1583 }
1584
1585 /* detect if the image size should grow */
1586 if (new_extent < new_regions[i].limit)
1587 new_extent = new_regions[i].limit;
1588 }
1589
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001590 /* check if the image is actually a Flash Descriptor region */
1591 if (size == new_regions[0].size) {
1592 printf("The image is a single Flash Descriptor:\n");
1593 printf(" Only the descriptor will be modified\n");
1594 new_extent = size;
1595 } else {
1596 new_extent = next_pow2(new_extent - 1);
1597 if (new_extent != size) {
1598 printf("The image has changed in size.\n");
1599 printf("The old image is %d bytes.\n", size);
1600 printf("The new image is %d bytes.\n", new_extent);
1601 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001602 }
1603
1604 /* copy regions to a new image */
1605 new_image = malloc(new_extent);
1606 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001607 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001608 int copy_size = new_regions[i].size;
1609 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001610 const region_t *current = &current_regions[i];
1611 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001612
Bill XIEfa5f9942017-09-12 11:22:29 +08001613 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001614 continue;
1615
Bill XIEfa5f9942017-09-12 11:22:29 +08001616 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001617 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001618 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001619 if (i == REGION_BIOS)
1620 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001621 }
1622
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001623 if ((i == REGION_BIOS) && (new->size < current->size)) {
1624 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001625 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001626 }
1627
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001628 if (size < current->base + offset_current + copy_size) {
1629 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1630 region_name(i));
1631 continue;
1632 };
1633
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001634 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1635 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001636 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1637 offset_current, current->limit, current->size);
1638 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1639 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001640
Bill XIEfa5f9942017-09-12 11:22:29 +08001641 memcpy(new_image + new->base + offset_new,
1642 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001643 copy_size);
1644 }
1645
1646 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001647 frba = find_frba(new_image, new_extent);
1648 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001649 exit(EXIT_FAILURE);
1650
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001651 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001652 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001653 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001654
1655 write_image(filename, new_image, new_extent);
1656 free(new_image);
1657}
1658
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001659static void print_version(void)
1660{
1661 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1662 printf("Copyright (C) 2011 Google Inc.\n\n");
1663 printf
1664 ("This program is free software: you can redistribute it and/or modify\n"
1665 "it under the terms of the GNU General Public License as published by\n"
1666 "the Free Software Foundation, version 2 of the License.\n\n"
1667 "This program is distributed in the hope that it will be useful,\n"
1668 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1669 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001670 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001671}
1672
1673static void print_usage(const char *name)
1674{
1675 printf("usage: %s [-vhdix?] <filename>\n", name);
1676 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001677 " -d | --dump: dump intel firmware descriptor\n"
1678 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1679 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1680 " -x | --extract: extract intel fd modules\n"
1681 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1682 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001683 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001684 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1685 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1686 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1687 " can only be used once per run:\n"
1688 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1689 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1690 " Dual Output Fast Read Support\n"
1691 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301692 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001693 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001694 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1695 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001696 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301697 " adl - Alder Lake\n"
1698 " aplk - Apollo Lake\n"
1699 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001700 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001701 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001702 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301703 " glk - Gemini Lake\n"
1704 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001705 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301706 " jsl - Jasper Lake\n"
1707 " sklkbl - Sky Lake/Kaby Lake\n"
1708 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001709 " -S | --setpchstrap Write a PCH strap\n"
1710 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001711 " -v | --version: print the version\n"
1712 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001713 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1714 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001715 "\n");
1716}
1717
1718int main(int argc, char *argv[])
1719{
1720 int opt, option_index = 0;
1721 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001722 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001723 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301724 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001725 char *region_type_string = NULL, *region_fname = NULL;
1726 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001727 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001728 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001729 unsigned int value = 0;
1730 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001731 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001732 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1733
Bill XIEfa5f9942017-09-12 11:22:29 +08001734 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001735 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001736 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001737 {"extract", 0, NULL, 'x'},
1738 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001739 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001740 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001741 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001742 {"density", 1, NULL, 'D'},
1743 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001744 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001745 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001746 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301747 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001748 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001749 {"version", 0, NULL, 'v'},
1750 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001751 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001752 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001753 {"setpchstrap", 1, NULL, 'S'},
1754 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001755 {0, 0, 0, 0}
1756 };
1757
Usha P412679d2020-10-15 11:25:08 +05301758 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 -07001759 long_options, &option_index)) != EOF) {
1760 switch (opt) {
1761 case 'd':
1762 mode_dump = 1;
1763 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001764 case 'S':
1765 mode_setstrap = 1;
1766 pchstrap = strtoul(optarg, NULL, 0);
1767 break;
1768 case 'V':
1769 value = strtoul(optarg, NULL, 0);
1770 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001771 case 'f':
1772 mode_layout = 1;
1773 layout_fname = strdup(optarg);
1774 if (!layout_fname) {
1775 fprintf(stderr, "No layout file specified\n");
1776 print_usage(argv[0]);
1777 exit(EXIT_FAILURE);
1778 }
1779 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001780 case 'x':
1781 mode_extract = 1;
1782 break;
1783 case 'i':
1784 // separate type and file name
1785 region_type_string = strdup(optarg);
1786 region_fname = strchr(region_type_string, ':');
1787 if (!region_fname) {
1788 print_usage(argv[0]);
1789 exit(EXIT_FAILURE);
1790 }
1791 region_fname[0] = '\0';
1792 region_fname++;
1793 // Descriptor, BIOS, ME, GbE, Platform
1794 // valid type?
1795 if (!strcasecmp("Descriptor", region_type_string))
1796 region_type = 0;
1797 else if (!strcasecmp("BIOS", region_type_string))
1798 region_type = 1;
1799 else if (!strcasecmp("ME", region_type_string))
1800 region_type = 2;
1801 else if (!strcasecmp("GbE", region_type_string))
1802 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001803 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001804 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001805 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001806 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001807 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001808 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001809 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001810 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001811 else if (!strcasecmp("EC", region_type_string))
1812 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001813 else if (!strcasecmp("Device Exp2", region_type_string))
1814 region_type = 9;
1815 else if (!strcasecmp("IE", region_type_string))
1816 region_type = 10;
1817 else if (!strcasecmp("10GbE_0", region_type_string))
1818 region_type = 11;
1819 else if (!strcasecmp("10GbE_1", region_type_string))
1820 region_type = 12;
1821 else if (!strcasecmp("PTT", region_type_string))
1822 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001823 if (region_type == -1) {
1824 fprintf(stderr, "No such region type: '%s'\n\n",
1825 region_type_string);
1826 print_usage(argv[0]);
1827 exit(EXIT_FAILURE);
1828 }
1829 mode_inject = 1;
1830 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001831 case 'n':
1832 mode_newlayout = 1;
1833 layout_fname = strdup(optarg);
1834 if (!layout_fname) {
1835 fprintf(stderr, "No layout file specified\n");
1836 print_usage(argv[0]);
1837 exit(EXIT_FAILURE);
1838 }
1839 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001840 case 'O':
1841 new_filename = strdup(optarg);
1842 if (!new_filename) {
1843 fprintf(stderr, "No output filename specified\n");
1844 print_usage(argv[0]);
1845 exit(EXIT_FAILURE);
1846 }
1847 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001848 case 'D':
1849 mode_density = 1;
1850 new_density = strtoul(optarg, NULL, 0);
1851 switch (new_density) {
1852 case 512:
1853 new_density = COMPONENT_DENSITY_512KB;
1854 break;
1855 case 1:
1856 new_density = COMPONENT_DENSITY_1MB;
1857 break;
1858 case 2:
1859 new_density = COMPONENT_DENSITY_2MB;
1860 break;
1861 case 4:
1862 new_density = COMPONENT_DENSITY_4MB;
1863 break;
1864 case 8:
1865 new_density = COMPONENT_DENSITY_8MB;
1866 break;
1867 case 16:
1868 new_density = COMPONENT_DENSITY_16MB;
1869 break;
1870 case 32:
1871 new_density = COMPONENT_DENSITY_32MB;
1872 break;
1873 case 64:
1874 new_density = COMPONENT_DENSITY_64MB;
1875 break;
1876 case 0:
1877 new_density = COMPONENT_DENSITY_UNUSED;
1878 break;
1879 default:
1880 printf("error: Unknown density\n");
1881 print_usage(argv[0]);
1882 exit(EXIT_FAILURE);
1883 }
1884 break;
1885 case 'C':
1886 selected_chip = strtol(optarg, NULL, 0);
1887 if (selected_chip > 2) {
1888 fprintf(stderr, "error: Invalid chip selection\n");
1889 print_usage(argv[0]);
1890 exit(EXIT_FAILURE);
1891 }
1892 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001893 case 'M':
1894 mode_altmedisable = 1;
1895 altmedisable = strtol(optarg, NULL, 0);
1896 if (altmedisable > 1) {
1897 fprintf(stderr, "error: Illegal value\n");
1898 print_usage(argv[0]);
1899 exit(EXIT_FAILURE);
1900 }
1901 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001902 case 's':
1903 // Parse the requested SPI frequency
1904 inputfreq = strtol(optarg, NULL, 0);
1905 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001906 case 17:
1907 spifreq = SPI_FREQUENCY_17MHZ;
1908 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001909 case 20:
1910 spifreq = SPI_FREQUENCY_20MHZ;
1911 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001912 case 30:
1913 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1914 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001915 case 33:
1916 spifreq = SPI_FREQUENCY_33MHZ;
1917 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001918 case 48:
1919 spifreq = SPI_FREQUENCY_48MHZ;
1920 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001921 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001922 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001923 break;
1924 default:
1925 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1926 inputfreq);
1927 print_usage(argv[0]);
1928 exit(EXIT_FAILURE);
1929 }
1930 mode_spifreq = 1;
1931 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001932 case 'e':
1933 mode_em100 = 1;
1934 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001935 case 'l':
1936 mode_locked = 1;
1937 if (mode_unlocked == 1) {
1938 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1939 exit(EXIT_FAILURE);
1940 }
1941 break;
Usha P412679d2020-10-15 11:25:08 +05301942 case 'r':
1943 mode_read = 1;
1944 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001945 case 'u':
1946 mode_unlocked = 1;
1947 if (mode_locked == 1) {
1948 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1949 exit(EXIT_FAILURE);
1950 }
1951 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001952 case 'p':
1953 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001954 platform = PLATFORM_APL;
1955 } else if (!strcmp(optarg, "cnl")) {
1956 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08001957 } else if (!strcmp(optarg, "lbg")) {
1958 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001959 } else if (!strcmp(optarg, "dnv")) {
1960 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001961 } else if (!strcmp(optarg, "ehl")) {
1962 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001963 } else if (!strcmp(optarg, "glk")) {
1964 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301965 } else if (!strcmp(optarg, "icl")) {
1966 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301967 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001968 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001969 } else if (!strcmp(optarg, "sklkbl")) {
1970 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001971 } else if (!strcmp(optarg, "tgl")) {
1972 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301973 } else if (!strcmp(optarg, "adl")) {
1974 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001975 } else if (!strcmp(optarg, "ifd2")) {
1976 platform = PLATFORM_IFD2;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001977 } else {
1978 fprintf(stderr, "Unknown platform: %s\n", optarg);
1979 exit(EXIT_FAILURE);
1980 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001981 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001982 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001983 case 't':
1984 mode_validate = 1;
1985 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001986 case 'v':
1987 print_version();
1988 exit(EXIT_SUCCESS);
1989 break;
1990 case 'h':
1991 case '?':
1992 default:
1993 print_usage(argv[0]);
1994 exit(EXIT_SUCCESS);
1995 break;
1996 }
1997 }
1998
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001999 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002000 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05002001 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002002 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002003 print_usage(argv[0]);
2004 exit(EXIT_FAILURE);
2005 }
2006
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002007 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002008 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06002009 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002010 fprintf(stderr, "You need to specify a mode.\n\n");
2011 print_usage(argv[0]);
2012 exit(EXIT_FAILURE);
2013 }
2014
2015 if (optind + 1 != argc) {
2016 fprintf(stderr, "You need to specify a file.\n\n");
2017 print_usage(argv[0]);
2018 exit(EXIT_FAILURE);
2019 }
2020
2021 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002022 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002023 if (bios_fd == -1) {
2024 perror("Could not open file");
2025 exit(EXIT_FAILURE);
2026 }
2027 struct stat buf;
2028 if (fstat(bios_fd, &buf) == -1) {
2029 perror("Could not stat file");
2030 exit(EXIT_FAILURE);
2031 }
2032 int size = buf.st_size;
2033
2034 printf("File %s is %d bytes\n", filename, size);
2035
2036 char *image = malloc(size);
2037 if (!image) {
2038 printf("Out of memory.\n");
2039 exit(EXIT_FAILURE);
2040 }
2041
2042 if (read(bios_fd, image, size) != size) {
2043 perror("Could not read file");
2044 exit(EXIT_FAILURE);
2045 }
2046
2047 close(bios_fd);
2048
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002049 // generate new filename
2050 if (new_filename == NULL) {
2051 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2052 if (!new_filename) {
2053 printf("Out of memory.\n");
2054 exit(EXIT_FAILURE);
2055 }
2056 // - 5: leave room for ".new\0"
2057 strcpy(new_filename, filename);
2058 strcat(new_filename, ".new");
2059 }
2060
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002061 check_ifd_version(image, size);
2062
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002063 if (mode_dump)
2064 dump_fd(image, size);
2065
Chris Douglass03ce0142014-02-26 13:30:13 -05002066 if (mode_layout)
2067 dump_layout(image, size, layout_fname);
2068
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002069 if (mode_extract)
2070 write_regions(image, size);
2071
Mathew Kingc7ddc992019-08-08 14:59:25 -06002072 if (mode_validate)
2073 validate_layout(image, size);
2074
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002075 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002076 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002077 region_fname);
2078
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002079 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002080 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002081
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002082 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002083 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002084
Jan Tatjefa317512016-03-11 00:52:07 +01002085 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002086 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002087
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002088 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002089 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002090
Alexander Couzensd12ea112016-09-10 13:33:05 +02002091 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002092 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002093
Usha P412679d2020-10-15 11:25:08 +05302094 if (mode_read)
2095 enable_cpu_read_me(new_filename, image, size);
2096
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002097 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002098 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002099
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002100 if (mode_setstrap) {
2101 fpsba_t *fpsba = find_fpsba(image, size);
2102 const fdbar_t *fdb = find_fd(image, size);
2103 set_pchstrap(fpsba, fdb, pchstrap, value);
2104 write_image(new_filename, image, size);
2105 }
2106
Bill XIEb3e15a22017-09-07 18:34:50 +08002107 if (mode_altmedisable) {
2108 fpsba_t *fpsba = find_fpsba(image, size);
2109 fmsba_t *fmsba = find_fmsba(image, size);
2110 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002111 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002112 }
2113
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002114 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002115 free(image);
2116
2117 return 0;
2118}