blob: bc62b4859f185c3498b4a53135ca90c2d852a531 [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 Banikca82e612022-01-20 18:51:21 +0530251 case PLATFORM_MTL:
Subrata Banik8c082e52021-06-10 23:02:29 +0530252 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
253 case PLATFORM_ICL:
254 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800255 case PLATFORM_LBG:
256 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500257 case PLATFORM_DNV:
258 return CHIPSET_DENVERTON;
Subrata Banik8c082e52021-06-10 23:02:29 +0530259 default:
260 return CHIPSET_PCH_UNKNOWN;
261 }
262}
263
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700264/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700265 * Some newer platforms have re-defined the FCBA field that was used to
266 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
267 * have the required FCBA field, but are IFD v2 and return true if current
268 * platform is one of them.
269 */
270static int is_platform_ifd_2(void)
271{
272 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530273 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700274 PLATFORM_GLK,
275 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800276 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500277 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530278 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700279 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530280 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700281 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530282 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200283 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800284 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530285 PLATFORM_MTL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700286 };
287 unsigned int i;
288
289 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
290 if (platform == ifd_2_platforms[i])
291 return 1;
292 }
293
294 return 0;
295}
296
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700297static void check_ifd_version(char *image, int size)
298{
Subrata Banik8c082e52021-06-10 23:02:29 +0530299 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700300 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530301 chipset = ifd2_platform_to_chipset(platform);
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700302 max_regions = MAX_REGIONS;
Subrata Banik8c082e52021-06-10 23:02:29 +0530303 } else {
304 ifd_version = IFD_VERSION_1;
305 chipset = ifd1_guess_chipset(image, size);
306 max_regions = MAX_REGIONS_OLD;
307 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700308}
309
Bill XIEfa5f9942017-09-12 11:22:29 +0800310static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700311{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500312 int base_mask;
313 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700314 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700315 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500316
317 if (ifd_version >= IFD_VERSION_2)
318 base_mask = 0x7fff;
319 else
320 base_mask = 0xfff;
321
322 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700323
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400324 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800325 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700326 exit (EXIT_FAILURE);
327 }
328
Bill XIE4651d452017-09-12 11:54:48 +0800329 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700330 region.base = (flreg & base_mask) << 12;
331 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700332 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500333
Chris Douglass03ce0142014-02-26 13:30:13 -0500334 if (region.size < 0)
335 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700336
337 return region;
338}
339
Bill XIEfa5f9942017-09-12 11:22:29 +0800340static void set_region(frba_t *frba, unsigned int region_type,
341 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500342{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400343 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800344 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500345 exit (EXIT_FAILURE);
346 }
Bill XIE4651d452017-09-12 11:54:48 +0800347
348 frba->flreg[region_type] =
349 (((region->limit >> 12) & 0x7fff) << 16) |
350 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500351}
352
Bill XIEfa5f9942017-09-12 11:22:29 +0800353static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700354{
Bill XIEfa5f9942017-09-12 11:22:29 +0800355 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700356 fprintf(stderr, "Invalid region type.\n");
357 exit (EXIT_FAILURE);
358 }
359
Chris Douglass03ce0142014-02-26 13:30:13 -0500360 return region_names[region_type].pretty;
361}
362
Bill XIEfa5f9942017-09-12 11:22:29 +0800363static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500364{
Bill XIEfa5f9942017-09-12 11:22:29 +0800365 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500366 fprintf(stderr, "Invalid region type.\n");
367 exit (EXIT_FAILURE);
368 }
369
370 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700371}
372
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500373static int region_num(const char *name)
374{
Bill XIEfa5f9942017-09-12 11:22:29 +0800375 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500376
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200377 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500378 if (strcasecmp(name, region_names[i].pretty) == 0)
379 return i;
380 if (strcasecmp(name, region_names[i].terse) == 0)
381 return i;
382 }
383
384 return -1;
385}
386
Bill XIEfa5f9942017-09-12 11:22:29 +0800387static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700388{
Bill XIEfa5f9942017-09-12 11:22:29 +0800389 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700390 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700391 exit (EXIT_FAILURE);
392 }
393
Bill XIE1bf65062017-09-12 11:31:37 +0800394 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700395}
396
Bill XIEfa5f9942017-09-12 11:22:29 +0800397static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700398{
399 region_t region = get_region(frba, num);
400 printf(" Flash Region %d (%s): %08x - %08x %s\n",
401 num, region_name(num), region.base, region.limit,
402 region.size < 1 ? "(unused)" : "");
403}
404
Bill XIEfa5f9942017-09-12 11:22:29 +0800405static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
406 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500407{
408 region_t region = get_region(frba, num);
409 snprintf(buf, bufsize, "%08x:%08x %s\n",
410 region.base, region.limit, region_name_short(num));
411}
412
Bill XIEfa5f9942017-09-12 11:22:29 +0800413static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700414{
Bill XIE4651d452017-09-12 11:54:48 +0800415 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530416 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700417 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800418 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530419 region = get_region(frba, i);
420 /* Skip unused & reserved Flash Region */
421 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
422 continue;
423
Bill XIE4651d452017-09-12 11:54:48 +0800424 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
425 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700426 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700427}
428
Bill XIEfa5f9942017-09-12 11:22:29 +0800429static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500430{
431 char buf[LAYOUT_LINELEN];
432 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800433 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500434
435 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
436 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
437 if (layout_fd == -1) {
438 perror("Could not open file");
439 exit(EXIT_FAILURE);
440 }
441
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200442 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200443 region_t region = get_region(frba, i);
444 /* is region invalid? */
445 if (region.size < 1)
446 continue;
447
Chris Douglass03ce0142014-02-26 13:30:13 -0500448 dump_region_layout(buf, bufsize, i, frba);
449 if (write(layout_fd, buf, strlen(buf)) < 0) {
450 perror("Could not write to file");
451 exit(EXIT_FAILURE);
452 }
453 }
454 close(layout_fd);
455 printf("Wrote layout to %s\n", layout_fname);
456}
457
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530458static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700459{
460 switch (freq) {
461 case SPI_FREQUENCY_20MHZ:
462 printf("20MHz");
463 break;
464 case SPI_FREQUENCY_33MHZ:
465 printf("33MHz");
466 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700467 case SPI_FREQUENCY_48MHZ:
468 printf("48MHz");
469 break;
470 case SPI_FREQUENCY_50MHZ_30MHZ:
471 switch (ifd_version) {
472 case IFD_VERSION_1:
473 printf("50MHz");
474 break;
475 case IFD_VERSION_2:
476 printf("30MHz");
477 break;
478 }
479 break;
480 case SPI_FREQUENCY_17MHZ:
481 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700482 break;
483 default:
484 printf("unknown<%x>MHz", freq);
485 }
486}
487
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530488static void _decode_spi_frequency_500_series(unsigned int freq)
489{
490 switch (freq) {
491 case SPI_FREQUENCY_100MHZ:
492 printf("100MHz");
493 break;
494 case SPI_FREQUENCY_50MHZ:
495 printf("50MHz");
496 break;
497 case SPI_FREQUENCY_500SERIES_33MHZ:
498 printf("33MHz");
499 break;
500 case SPI_FREQUENCY_25MHZ:
501 printf("25MHz");
502 break;
503 case SPI_FREQUENCY_14MHZ:
504 printf("14MHz");
505 break;
506 default:
507 printf("unknown<%x>MHz", freq);
508 }
509}
510
511static void decode_spi_frequency(unsigned int freq)
512{
Subrata Banika5f47812020-09-29 11:43:01 +0530513 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530514 _decode_spi_frequency_500_series(freq);
515 else
516 _decode_spi_frequency(freq);
517}
518
Subrata Banike5d39922020-08-26 16:01:42 +0530519static void _decode_espi_frequency(unsigned int freq)
520{
521 switch (freq) {
522 case ESPI_FREQUENCY_20MHZ:
523 printf("20MHz");
524 break;
525 case ESPI_FREQUENCY_24MHZ:
526 printf("24MHz");
527 break;
528 case ESPI_FREQUENCY_30MHZ:
529 printf("30MHz");
530 break;
531 case ESPI_FREQUENCY_48MHZ:
532 printf("48MHz");
533 break;
534 case ESPI_FREQUENCY_60MHZ:
535 printf("60MHz");
536 break;
537 case ESPI_FREQUENCY_17MHZ:
538 printf("17MHz");
539 break;
540 default:
541 printf("unknown<%x>MHz", freq);
542 }
543}
544
545static void _decode_espi_frequency_500_series(unsigned int freq)
546{
547 switch (freq) {
548 case ESPI_FREQUENCY_500SERIES_20MHZ:
549 printf("20MHz");
550 break;
551 case ESPI_FREQUENCY_500SERIES_24MHZ:
552 printf("24MHz");
553 break;
554 case ESPI_FREQUENCY_500SERIES_25MHZ:
555 printf("25MHz");
556 break;
557 case ESPI_FREQUENCY_500SERIES_48MHZ:
558 printf("48MHz");
559 break;
560 case ESPI_FREQUENCY_500SERIES_60MHZ:
561 printf("60MHz");
562 break;
563 default:
564 printf("unknown<%x>MHz", freq);
565 }
566}
567
568static void decode_espi_frequency(unsigned int freq)
569{
Subrata Banika5f47812020-09-29 11:43:01 +0530570 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530571 _decode_espi_frequency_500_series(freq);
572 else
573 _decode_espi_frequency(freq);
574}
575
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700576static void decode_component_density(unsigned int density)
577{
578 switch (density) {
579 case COMPONENT_DENSITY_512KB:
580 printf("512KB");
581 break;
582 case COMPONENT_DENSITY_1MB:
583 printf("1MB");
584 break;
585 case COMPONENT_DENSITY_2MB:
586 printf("2MB");
587 break;
588 case COMPONENT_DENSITY_4MB:
589 printf("4MB");
590 break;
591 case COMPONENT_DENSITY_8MB:
592 printf("8MB");
593 break;
594 case COMPONENT_DENSITY_16MB:
595 printf("16MB");
596 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700597 case COMPONENT_DENSITY_32MB:
598 printf("32MB");
599 break;
600 case COMPONENT_DENSITY_64MB:
601 printf("64MB");
602 break;
603 case COMPONENT_DENSITY_UNUSED:
604 printf("UNUSED");
605 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700606 default:
607 printf("unknown<%x>MB", density);
608 }
609}
610
Subrata Banik26058dc2020-08-26 15:12:16 +0530611static int is_platform_with_pch(void)
612{
613 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
614 return 1;
615
616 return 0;
617}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530618
619/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
620static int is_platform_with_100x_series_pch(void)
621{
622 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530623 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530624 return 1;
625
626 return 0;
627}
628
Subrata Banike5d39922020-08-26 16:01:42 +0530629static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700630{
Subrata Banike5d39922020-08-26 16:01:42 +0530631 unsigned int freq;
632
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700633 printf("\nFound Component Section\n");
634 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700635 printf(" Dual Output Fast Read Support: %ssupported\n",
636 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700637 printf(" Read ID/Read Status Clock Frequency: ");
638 decode_spi_frequency((fcba->flcomp >> 27) & 7);
639 printf("\n Write/Erase Clock Frequency: ");
640 decode_spi_frequency((fcba->flcomp >> 24) & 7);
641 printf("\n Fast Read Clock Frequency: ");
642 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700643 printf("\n Fast Read Support: %ssupported",
644 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530645 if (is_platform_with_100x_series_pch() &&
646 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
647 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530648 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530649 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
650 else
651 freq = (fcba->flcomp >> 17) & 7;
652 decode_espi_frequency(freq);
653 } else {
654 printf("\n Read Clock Frequency: ");
655 decode_spi_frequency((fcba->flcomp >> 17) & 7);
656 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700657
658 switch (ifd_version) {
659 case IFD_VERSION_1:
660 printf("\n Component 2 Density: ");
661 decode_component_density((fcba->flcomp >> 3) & 7);
662 printf("\n Component 1 Density: ");
663 decode_component_density(fcba->flcomp & 7);
664 break;
665 case IFD_VERSION_2:
666 printf("\n Component 2 Density: ");
667 decode_component_density((fcba->flcomp >> 4) & 0xf);
668 printf("\n Component 1 Density: ");
669 decode_component_density(fcba->flcomp & 0xf);
670 break;
671 }
672
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700673 printf("\n");
674 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700675 printf(" Invalid Instruction 3: 0x%02x\n",
676 (fcba->flill >> 24) & 0xff);
677 printf(" Invalid Instruction 2: 0x%02x\n",
678 (fcba->flill >> 16) & 0xff);
679 printf(" Invalid Instruction 1: 0x%02x\n",
680 (fcba->flill >> 8) & 0xff);
681 printf(" Invalid Instruction 0: 0x%02x\n",
682 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530683 if (is_platform_with_100x_series_pch()) {
684 printf("FLILL1 0x%08x\n", fcba->flpb);
685 printf(" Invalid Instruction 7: 0x%02x\n",
686 (fcba->flpb >> 24) & 0xff);
687 printf(" Invalid Instruction 6: 0x%02x\n",
688 (fcba->flpb >> 16) & 0xff);
689 printf(" Invalid Instruction 5: 0x%02x\n",
690 (fcba->flpb >> 8) & 0xff);
691 printf(" Invalid Instruction 4: 0x%02x\n",
692 fcba->flpb & 0xff);
693 } else {
694 printf("FLPB 0x%08x\n", fcba->flpb);
695 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
696 (fcba->flpb & 0xfff) << 12);
697 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700698}
699
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200700static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700701{
Bill XIE4651d452017-09-12 11:54:48 +0800702 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200703 /* SoC Strap Length, aka PSL, aka ISL */
704 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
705
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700706 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200707 for (i = 0; i < SSL; i++)
708 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800709
710 if (ifd_version >= IFD_VERSION_2) {
711 printf("HAP bit is %sset\n",
712 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
713 } else if (chipset >= CHIPSET_ICH8
714 && chipset <= CHIPSET_ICH10) {
715 printf("ICH_MeDisable bit is %sset\n",
716 fpsba->pchstrp[0] & 1 ? "" : "not ");
717 } else {
718 printf("AltMeDisable bit is %sset\n",
719 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
720 }
721
Bill XIE4651d452017-09-12 11:54:48 +0800722 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700723}
724
725static void decode_flmstr(uint32_t flmstr)
726{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700727 int wr_shift, rd_shift;
728 if (ifd_version >= IFD_VERSION_2) {
729 wr_shift = FLMSTR_WR_SHIFT_V2;
730 rd_shift = FLMSTR_RD_SHIFT_V2;
731 } else {
732 wr_shift = FLMSTR_WR_SHIFT_V1;
733 rd_shift = FLMSTR_RD_SHIFT_V1;
734 }
735
736 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500737 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700738 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700739 (flmstr & (1 << (wr_shift + 8))) ?
740 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700741 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700742 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500743 if (PLATFORM_HAS_GBE_REGION) {
744 printf(" GbE Region Write Access: %s\n",
745 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
746 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700747 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700748 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700749 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700750 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700751 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700752 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500753 if (PLATFORM_HAS_10GBE_0_REGION) {
754 printf(" 10GbE_0 Write Access: %s\n",
755 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
756 }
757 if (PLATFORM_HAS_10GBE_1_REGION) {
758 printf(" 10GbE_1 Write Access: %s\n",
759 (flmstr & (1 << 4)) ? "enabled" : "disabled");
760 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700761
Jeff Dalyabd4b962022-01-06 00:52:30 -0500762 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700763 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700764 (flmstr & (1 << (rd_shift + 8))) ?
765 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700766 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700767 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500768 if (PLATFORM_HAS_GBE_REGION) {
769 printf(" GbE Region Read Access: %s\n",
770 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
771 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700772 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700773 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700774 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700775 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700776 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700777 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500778 if (PLATFORM_HAS_10GBE_0_REGION) {
779 printf(" 10GbE_0 Read Access: %s\n",
780 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
781 }
782 if (PLATFORM_HAS_10GBE_1_REGION) {
783 printf(" 10GbE_1 Read Access: %s\n",
784 (flmstr & (1 << 0)) ? "enabled" : "disabled");
785 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700786
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700787 /* Requestor ID doesn't exist for ifd 2 */
788 if (ifd_version < IFD_VERSION_2)
789 printf(" Requester ID: 0x%04x\n\n",
790 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700791}
792
Bill XIEfa5f9942017-09-12 11:22:29 +0800793static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700794{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700795 printf("Found Master Section\n");
796 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
797 decode_flmstr(fmba->flmstr1);
798 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
799 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500800 if (PLATFORM_HAS_GBE_REGION) {
801 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
802 decode_flmstr(fmba->flmstr3);
803 if (ifd_version >= IFD_VERSION_2) {
804 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
805 decode_flmstr(fmba->flmstr5);
806 }
807 } else {
808 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
809 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700810 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700811}
812
Bill XIEfa5f9942017-09-12 11:22:29 +0800813static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700814{
Bill XIE612ec0e2017-08-30 16:10:27 +0800815 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700816 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800817 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
818 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800819
820 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
821 printf("MCH_MeDisable bit is %sset\n",
822 fmsba->data[0] & 1 ? "" : "not ");
823 printf("MCH_AltMeDisable bit is %sset\n",
824 fmsba->data[0] & (1 << 7) ? "" : "not ");
825 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700826}
827
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700828static void dump_jid(uint32_t jid)
829{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100830 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700831 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100832 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200833 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100834 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200835 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700836}
837
838static void dump_vscc(uint32_t vscc)
839{
840 printf(" Lower Erase Opcode: 0x%02x\n",
841 vscc >> 24);
842 printf(" Lower Write Enable on Write Status: 0x%02x\n",
843 vscc & (1 << 20) ? 0x06 : 0x50);
844 printf(" Lower Write Status Required: %s\n",
845 vscc & (1 << 19) ? "Yes" : "No");
846 printf(" Lower Write Granularity: %d bytes\n",
847 vscc & (1 << 18) ? 64 : 1);
848 printf(" Lower Block / Sector Erase Size: ");
849 switch ((vscc >> 16) & 0x3) {
850 case 0:
851 printf("256 Byte\n");
852 break;
853 case 1:
854 printf("4KB\n");
855 break;
856 case 2:
857 printf("8KB\n");
858 break;
859 case 3:
860 printf("64KB\n");
861 break;
862 }
863
864 printf(" Upper Erase Opcode: 0x%02x\n",
865 (vscc >> 8) & 0xff);
866 printf(" Upper Write Enable on Write Status: 0x%02x\n",
867 vscc & (1 << 4) ? 0x06 : 0x50);
868 printf(" Upper Write Status Required: %s\n",
869 vscc & (1 << 3) ? "Yes" : "No");
870 printf(" Upper Write Granularity: %d bytes\n",
871 vscc & (1 << 2) ? 64 : 1);
872 printf(" Upper Block / Sector Erase Size: ");
873 switch (vscc & 0x3) {
874 case 0:
875 printf("256 Byte\n");
876 break;
877 case 1:
878 printf("4KB\n");
879 break;
880 case 2:
881 printf("8KB\n");
882 break;
883 case 3:
884 printf("64KB\n");
885 break;
886 }
887}
888
Bill XIEfa5f9942017-09-12 11:22:29 +0800889static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700890{
891 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200892 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
893 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700894
895 printf("ME VSCC table:\n");
896 for (i = 0; i < num; i++) {
897 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
898 dump_jid(vtba->entry[i].jid);
899 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
900 dump_vscc(vtba->entry[i].vscc);
901 }
902 printf("\n");
903}
904
Bill XIEfa5f9942017-09-12 11:22:29 +0800905static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700906{
907 int i, j;
908 printf("OEM Section:\n");
909 for (i = 0; i < 4; i++) {
910 printf("%02x:", i << 4);
911 for (j = 0; j < 16; j++)
912 printf(" %02x", oem[(i<<4)+j]);
913 printf ("\n");
914 }
915 printf ("\n");
916}
917
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700918static void dump_fd(char *image, int size)
919{
Bill XIE612ec0e2017-08-30 16:10:27 +0800920 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700921 if (!fdb)
922 exit(EXIT_FAILURE);
923
Subrata Banik26058dc2020-08-26 15:12:16 +0530924 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
925 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700926 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530927 if (!is_platform_with_100x_series_pch())
928 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700929 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
930 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
931 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
932
933 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530934 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
935 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700936 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
937 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
938 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
939
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530940 if (!is_platform_with_100x_series_pch()) {
941 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
942 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
943 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
944 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700945
Subrata Banika5f47812020-09-29 11:43:01 +0530946 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530947 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
948 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
949 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
950 }
951
Stefan Tauner0d226142018-08-05 18:56:53 +0200952 char *flumap = find_flumap(image, size);
953 uint32_t flumap1 = *(uint32_t *)flumap;
954 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700955 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200956 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700957 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200958 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700959 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200960 (image + ((flumap1 & 0xff) << 4)),
961 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800962 dump_oem((const uint8_t *)image + 0xf00);
963
964 const frba_t *frba = find_frba(image, size);
965 const fcba_t *fcba = find_fcba(image, size);
966 const fpsba_t *fpsba = find_fpsba(image, size);
967 const fmba_t *fmba = find_fmba(image, size);
968 const fmsba_t *fmsba = find_fmsba(image, size);
969
970 if (frba && fcba && fpsba && fmba && fmsba) {
971 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530972 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200973 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800974 dump_fmba(fmba);
975 dump_fmsba(fmsba);
976 } else {
977 printf("FD is corrupted!\n");
978 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700979}
980
Bill XIEfa5f9942017-09-12 11:22:29 +0800981static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500982{
Bill XIE612ec0e2017-08-30 16:10:27 +0800983 const frba_t *frba = find_frba(image, size);
984 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500985 exit(EXIT_FAILURE);
986
Bill XIE612ec0e2017-08-30 16:10:27 +0800987 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500988}
989
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700990static void write_regions(char *image, int size)
991{
Bill XIEfa5f9942017-09-12 11:22:29 +0800992 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800993 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700994
Bill XIE612ec0e2017-08-30 16:10:27 +0800995 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700996 exit(EXIT_FAILURE);
997
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700998 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700999 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001000 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001001 if (region.size > 0) {
1002 int region_fd;
1003 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -06001004 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001005 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001006 if (region_fd < 0) {
1007 perror("Error while trying to open file");
1008 exit(EXIT_FAILURE);
1009 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001010 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001011 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001012 close(region_fd);
1013 }
1014 }
1015}
1016
Mathew Kingc7ddc992019-08-08 14:59:25 -06001017static void validate_layout(char *image, int size)
1018{
1019 uint i, errors = 0;
1020 struct fmap *fmap;
1021 long int fmap_loc = fmap_find((uint8_t *)image, size);
1022 const frba_t *frba = find_frba(image, size);
1023
1024 if (fmap_loc < 0 || !frba)
1025 exit(EXIT_FAILURE);
1026
1027 fmap = (struct fmap *)(image + fmap_loc);
1028
1029 for (i = 0; i < max_regions; i++) {
1030 if (region_names[i].fmapname == NULL)
1031 continue;
1032
1033 region_t region = get_region(frba, i);
1034
1035 if (region.size == 0)
1036 continue;
1037
1038 const struct fmap_area *area =
1039 fmap_find_area(fmap, region_names[i].fmapname);
1040
1041 if (!area)
1042 continue;
1043
1044 if ((uint)region.base != area->offset ||
1045 (uint)region.size != area->size) {
1046 printf("Region mismatch between %s and %s\n",
1047 region_names[i].terse, area->name);
1048 printf(" Descriptor region %s:\n", region_names[i].terse);
1049 printf(" offset: 0x%08x\n", region.base);
1050 printf(" length: 0x%08x\n", region.size);
1051 printf(" FMAP area %s:\n", area->name);
1052 printf(" offset: 0x%08x\n", area->offset);
1053 printf(" length: 0x%08x\n", area->size);
1054 errors++;
1055 }
1056 }
1057
1058 if (errors > 0)
1059 exit(EXIT_FAILURE);
1060}
1061
Bill XIEfa5f9942017-09-12 11:22:29 +08001062static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001063{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001064 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001065 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001066
1067 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001068 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001069 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001070 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001071 if (new_fd < 0) {
1072 perror("Error while trying to open file");
1073 exit(EXIT_FAILURE);
1074 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001075 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001076 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001077 close(new_fd);
1078}
1079
Bill XIEfa5f9942017-09-12 11:22:29 +08001080static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001081 enum spi_frequency freq)
1082{
Bill XIE612ec0e2017-08-30 16:10:27 +08001083 fcba_t *fcba = find_fcba(image, size);
1084 if (!fcba)
1085 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001086
1087 /* clear bits 21-29 */
1088 fcba->flcomp &= ~0x3fe00000;
1089 /* Read ID and Read Status Clock Frequency */
1090 fcba->flcomp |= freq << 27;
1091 /* Write and Erase Clock Frequency */
1092 fcba->flcomp |= freq << 24;
1093 /* Fast Read Clock Frequency */
1094 fcba->flcomp |= freq << 21;
1095
1096 write_image(filename, image, size);
1097}
1098
Bill XIEfa5f9942017-09-12 11:22:29 +08001099static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001100{
Bill XIE612ec0e2017-08-30 16:10:27 +08001101 fcba_t *fcba = find_fcba(image, size);
1102 if (!fcba)
1103 exit(EXIT_FAILURE);
1104
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001105 int freq;
1106
1107 switch (ifd_version) {
1108 case IFD_VERSION_1:
1109 freq = SPI_FREQUENCY_20MHZ;
1110 break;
1111 case IFD_VERSION_2:
1112 freq = SPI_FREQUENCY_17MHZ;
1113 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001114 default:
1115 freq = SPI_FREQUENCY_17MHZ;
1116 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001117 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001118
1119 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001120 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001121}
1122
Bill XIEfa5f9942017-09-12 11:22:29 +08001123static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001124 unsigned int density)
1125{
Bill XIE612ec0e2017-08-30 16:10:27 +08001126 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001127 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001128 if (!fcba)
1129 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001130
1131 printf("Setting chip density to ");
1132 decode_component_density(density);
1133 printf("\n");
1134
1135 switch (ifd_version) {
1136 case IFD_VERSION_1:
1137 /* fail if selected density is not supported by this version */
1138 if ( (density == COMPONENT_DENSITY_32MB) ||
1139 (density == COMPONENT_DENSITY_64MB) ||
1140 (density == COMPONENT_DENSITY_UNUSED) ) {
1141 printf("error: Selected density not supported in IFD version 1.\n");
1142 exit(EXIT_FAILURE);
1143 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001144 mask = 0x7;
1145 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001146 break;
1147 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001148 mask = 0xf;
1149 chip2_offset = 4;
1150 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001151 default:
1152 printf("error: Unknown IFD version\n");
1153 exit(EXIT_FAILURE);
1154 break;
1155 }
1156
1157 /* clear chip density for corresponding chip */
1158 switch (selected_chip) {
1159 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001160 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001161 break;
1162 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001163 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001164 break;
1165 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001166 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001167 break;
1168 }
1169
1170 /* set the new density */
1171 if (selected_chip == 1 || selected_chip == 0)
1172 fcba->flcomp |= (density); /* first chip */
1173 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001174 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001175
1176 write_image(filename, image, size);
1177}
1178
Duncan Laurie7775d672019-06-06 13:39:26 -07001179static int check_region(const frba_t *frba, unsigned int region_type)
1180{
1181 region_t region;
1182
1183 if (!frba)
1184 return 0;
1185
1186 region = get_region(frba, region_type);
1187 return !!((region.base < region.limit) && (region.size > 0));
1188}
1189
Bill XIEfa5f9942017-09-12 11:22:29 +08001190static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001191{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001192 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001193 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001194 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001195 if (!fmba)
1196 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001197
1198 if (ifd_version >= IFD_VERSION_2) {
1199 wr_shift = FLMSTR_WR_SHIFT_V2;
1200 rd_shift = FLMSTR_RD_SHIFT_V2;
1201
1202 /* Clear non-reserved bits */
1203 fmba->flmstr1 &= 0xff;
1204 fmba->flmstr2 &= 0xff;
1205 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001206 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001207 } else {
1208 wr_shift = FLMSTR_WR_SHIFT_V1;
1209 rd_shift = FLMSTR_RD_SHIFT_V1;
1210
1211 fmba->flmstr1 = 0;
1212 fmba->flmstr2 = 0;
1213 /* Requestor ID */
1214 fmba->flmstr3 = 0x118;
1215 }
1216
Andrey Petrov96ecb772016-10-31 19:31:54 -07001217 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001218 case PLATFORM_APL:
1219 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001220 /* CPU/BIOS can read descriptor and BIOS */
1221 fmba->flmstr1 |= 0x3 << rd_shift;
1222 /* CPU/BIOS can write BIOS */
1223 fmba->flmstr1 |= 0x2 << wr_shift;
1224 /* TXE can read descriptor, BIOS and Device Expansion */
1225 fmba->flmstr2 |= 0x23 << rd_shift;
1226 /* TXE can only write Device Expansion */
1227 fmba->flmstr2 |= 0x20 << wr_shift;
1228 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001229 case PLATFORM_CNL:
1230 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001231 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001232 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301233 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001234 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301235 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001236 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301237 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001238 /* CPU/BIOS can read descriptor and BIOS. */
1239 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1240 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1241 /* CPU/BIOS can write BIOS. */
1242 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1243 /* ME can read descriptor and ME. */
1244 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1245 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001246 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001247 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1248 if (check_region(frba, REGION_GBE)) {
1249 /* BIOS can read/write GbE. */
1250 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1251 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1252 /* ME can read GbE. */
1253 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1254 /* GbE can read descriptor and read/write GbE.. */
1255 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1256 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1257 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1258 }
1259 if (check_region(frba, REGION_PDR)) {
1260 /* BIOS can read/write PDR. */
1261 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1262 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1263 }
1264 if (check_region(frba, REGION_EC)) {
1265 /* BIOS can read EC. */
1266 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1267 /* EC can read descriptor and read/write EC. */
1268 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1269 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1270 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1271 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001272 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001273 case PLATFORM_DNV:
1274 /* CPU/BIOS can read descriptor and BIOS. */
1275 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1276 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1277 /* CPU/BIOS can write BIOS. */
1278 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1279 /* ME can read descriptor and ME. */
1280 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1281 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1282 /* ME can write ME. */
1283 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1284 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001285 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001286 /* CPU/BIOS can read descriptor and BIOS. */
1287 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1288 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1289 /* CPU/BIOS can write BIOS. */
1290 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1291 /* ME can read descriptor and ME. */
1292 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1293 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1294 /* ME can write ME. */
1295 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1296 if (check_region(frba, REGION_GBE)) {
1297 /* BIOS can read GbE. */
1298 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1299 /* BIOS can write GbE. */
1300 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1301 /* ME can read GbE. */
1302 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1303 /* ME can write GbE. */
1304 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1305 /* GbE can write GbE. */
1306 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1307 /* GbE can read GbE. */
1308 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1309 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001310 break;
1311 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001312
1313 write_image(filename, image, size);
1314}
1315
Usha P412679d2020-10-15 11:25:08 +05301316static void enable_cpu_read_me(const char *filename, char *image, int size)
1317{
1318 int rd_shift;
1319 fmba_t *fmba = find_fmba(image, size);
1320
1321 if (!fmba)
1322 exit(EXIT_FAILURE);
1323
1324 if (ifd_version >= IFD_VERSION_2)
1325 rd_shift = FLMSTR_RD_SHIFT_V2;
1326 else
1327 rd_shift = FLMSTR_RD_SHIFT_V1;
1328
1329 /* CPU/BIOS can read ME. */
1330 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1331
1332 write_image(filename, image, size);
1333}
1334
Bill XIEfa5f9942017-09-12 11:22:29 +08001335static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001336{
Bill XIE612ec0e2017-08-30 16:10:27 +08001337 fmba_t *fmba = find_fmba(image, size);
1338 if (!fmba)
1339 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001340
1341 if (ifd_version >= IFD_VERSION_2) {
1342 /* Access bits for each region are read: 19:8 write: 31:20 */
1343 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1344 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1345 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001346 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001347 } else {
1348 fmba->flmstr1 = 0xffff0000;
1349 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001350 /* Keep chipset specific Requester ID */
1351 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001352 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001353
1354 write_image(filename, image, size);
1355}
1356
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001357static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1358 const unsigned int value)
1359{
1360 if (!fpsba || !fdb) {
1361 fprintf(stderr, "Internal error\n");
1362 exit(EXIT_FAILURE);
1363 }
1364
1365 /* SoC Strap Length, aka PSL, aka ISL */
1366 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1367 if (strap >= SSL) {
1368 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1369 exit(EXIT_FAILURE);
1370 }
1371 fpsba->pchstrp[strap] = value;
1372}
1373
Bill XIEb3e15a22017-09-07 18:34:50 +08001374/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001375static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001376{
1377 if (ifd_version >= IFD_VERSION_2) {
1378 printf("%sting the HAP bit to %s Intel ME...\n",
1379 altmedisable?"Set":"Unset",
1380 altmedisable?"disable":"enable");
1381 if (altmedisable)
1382 fpsba->pchstrp[0] |= (1 << 16);
1383 else
1384 fpsba->pchstrp[0] &= ~(1 << 16);
1385 } else {
1386 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1387 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1388 "and MCH_AltMeDisable to %s Intel ME...\n",
1389 altmedisable?"Set":"Unset",
1390 altmedisable?"disable":"enable");
1391 if (altmedisable) {
1392 /* MCH_MeDisable */
1393 fmsba->data[0] |= 1;
1394 /* MCH_AltMeDisable */
1395 fmsba->data[0] |= (1 << 7);
1396 /* ICH_MeDisable */
1397 fpsba->pchstrp[0] |= 1;
1398 } else {
1399 fmsba->data[0] &= ~1;
1400 fmsba->data[0] &= ~(1 << 7);
1401 fpsba->pchstrp[0] &= ~1;
1402 }
1403 } else {
1404 printf("%sting the AltMeDisable to %s Intel ME...\n",
1405 altmedisable?"Set":"Unset",
1406 altmedisable?"disable":"enable");
1407 if (altmedisable)
1408 fpsba->pchstrp[10] |= (1 << 7);
1409 else
1410 fpsba->pchstrp[10] &= ~(1 << 7);
1411 }
1412 }
1413}
1414
Jacob Garber595d9262019-06-27 17:33:10 -06001415static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001416 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001417{
Bill XIE612ec0e2017-08-30 16:10:27 +08001418 frba_t *frba = find_frba(image, size);
1419 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001420 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001421
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001422 region_t region = get_region(frba, region_type);
1423 if (region.size <= 0xfff) {
1424 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1425 region_name(region_type));
1426 exit(EXIT_FAILURE);
1427 }
1428
Scott Duplichanf2c98372014-12-12 21:03:06 -06001429 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001430 if (region_fd == -1) {
1431 perror("Could not open file");
1432 exit(EXIT_FAILURE);
1433 }
1434 struct stat buf;
1435 if (fstat(region_fd, &buf) == -1) {
1436 perror("Could not stat file");
1437 exit(EXIT_FAILURE);
1438 }
1439 int region_size = buf.st_size;
1440
1441 printf("File %s is %d bytes\n", region_fname, region_size);
1442
1443 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001444 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001445 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1446 " bytes. Not injecting.\n",
1447 region_name(region_type), region.size,
1448 region.size, region_size, region_size);
1449 exit(EXIT_FAILURE);
1450 }
1451
1452 int offset = 0;
1453 if ((region_type == 1) && (region_size < region.size)) {
1454 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1455 " bytes. Padding before injecting.\n",
1456 region_name(region_type), region.size,
1457 region.size, region_size, region_size);
1458 offset = region.size - region_size;
1459 memset(image + region.base, 0xff, offset);
1460 }
1461
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001462 if (size < region.base + offset + region_size) {
1463 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1464 size, region.base + offset + region_size);
1465 exit(EXIT_FAILURE);
1466 }
1467
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001468 if (read(region_fd, image + region.base + offset, region_size)
1469 != region_size) {
1470 perror("Could not read file");
1471 exit(EXIT_FAILURE);
1472 }
1473
1474 close(region_fd);
1475
1476 printf("Adding %s as the %s section of %s\n",
1477 region_fname, region_name(region_type), filename);
1478 write_image(filename, image, size);
1479}
1480
Jacob Garber595d9262019-06-27 17:33:10 -06001481static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001482{
1483 unsigned int y = 1;
1484 if (x == 0)
1485 return 0;
1486 while (y <= x)
1487 y = y << 1;
1488
1489 return y;
1490}
1491
1492/**
1493 * Determine if two memory regions overlap.
1494 *
1495 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001496 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001497 * @return 1 if the two regions overlap
1498 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001499static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001500{
Bill XIEfa5f9942017-09-12 11:22:29 +08001501 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001502 return 0;
1503
Nico Huber844eda02019-01-05 00:06:19 +01001504 /* r1 should be either completely below or completely above r2 */
1505 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001506}
1507
Jacob Garber595d9262019-06-27 17:33:10 -06001508static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001509 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001510{
1511 FILE *romlayout;
1512 char tempstr[256];
1513 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001514 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001515 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001516 region_t current_regions[MAX_REGIONS];
1517 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001518 int new_extent = 0;
1519 char *new_image;
1520
1521 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001522 frba_t *frba = find_frba(image, size);
1523 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001524 exit(EXIT_FAILURE);
1525
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001526 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001527 current_regions[i] = get_region(frba, i);
1528 new_regions[i] = get_region(frba, i);
1529 }
1530
1531 /* read new layout */
1532 romlayout = fopen(layout_fname, "r");
1533
1534 if (!romlayout) {
1535 perror("Could not read layout file.\n");
1536 exit(EXIT_FAILURE);
1537 }
1538
1539 while (!feof(romlayout)) {
1540 char *tstr1, *tstr2;
1541
Patrick Georgi802ad522014-08-09 17:12:23 +02001542 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001543 layout_region_name))
1544 continue;
1545
1546 region_number = region_num(layout_region_name);
1547 if (region_number < 0)
1548 continue;
1549
1550 tstr1 = strtok(tempstr, ":");
1551 tstr2 = strtok(NULL, ":");
1552 if (!tstr1 || !tstr2) {
1553 fprintf(stderr, "Could not parse layout file.\n");
1554 exit(EXIT_FAILURE);
1555 }
1556 new_regions[region_number].base = strtol(tstr1,
1557 (char **)NULL, 16);
1558 new_regions[region_number].limit = strtol(tstr2,
1559 (char **)NULL, 16);
1560 new_regions[region_number].size =
1561 new_regions[region_number].limit -
1562 new_regions[region_number].base + 1;
1563
1564 if (new_regions[region_number].size < 0)
1565 new_regions[region_number].size = 0;
1566 }
1567 fclose(romlayout);
1568
1569 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001570 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001571 if (new_regions[i].size == 0)
1572 continue;
1573
1574 if (new_regions[i].size < current_regions[i].size) {
1575 printf("DANGER: Region %s is shrinking.\n",
1576 region_name(i));
1577 printf(" The region will be truncated to fit.\n");
1578 printf(" This may result in an unusable image.\n");
1579 }
1580
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001581 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001582 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001583 fprintf(stderr, "Regions would overlap.\n");
1584 exit(EXIT_FAILURE);
1585 }
1586 }
1587
1588 /* detect if the image size should grow */
1589 if (new_extent < new_regions[i].limit)
1590 new_extent = new_regions[i].limit;
1591 }
1592
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001593 /* check if the image is actually a Flash Descriptor region */
1594 if (size == new_regions[0].size) {
1595 printf("The image is a single Flash Descriptor:\n");
1596 printf(" Only the descriptor will be modified\n");
1597 new_extent = size;
1598 } else {
1599 new_extent = next_pow2(new_extent - 1);
1600 if (new_extent != size) {
1601 printf("The image has changed in size.\n");
1602 printf("The old image is %d bytes.\n", size);
1603 printf("The new image is %d bytes.\n", new_extent);
1604 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001605 }
1606
1607 /* copy regions to a new image */
1608 new_image = malloc(new_extent);
1609 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001610 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001611 int copy_size = new_regions[i].size;
1612 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001613 const region_t *current = &current_regions[i];
1614 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001615
Bill XIEfa5f9942017-09-12 11:22:29 +08001616 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001617 continue;
1618
Bill XIEfa5f9942017-09-12 11:22:29 +08001619 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001620 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001621 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001622 if (i == REGION_BIOS)
1623 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001624 }
1625
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001626 if ((i == REGION_BIOS) && (new->size < current->size)) {
1627 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001628 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001629 }
1630
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001631 if (size < current->base + offset_current + copy_size) {
1632 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1633 region_name(i));
1634 continue;
1635 };
1636
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001637 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1638 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001639 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1640 offset_current, current->limit, current->size);
1641 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1642 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001643
Bill XIEfa5f9942017-09-12 11:22:29 +08001644 memcpy(new_image + new->base + offset_new,
1645 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001646 copy_size);
1647 }
1648
1649 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001650 frba = find_frba(new_image, new_extent);
1651 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001652 exit(EXIT_FAILURE);
1653
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001654 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001655 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001656 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001657
1658 write_image(filename, new_image, new_extent);
1659 free(new_image);
1660}
1661
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001662static void print_version(void)
1663{
1664 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1665 printf("Copyright (C) 2011 Google Inc.\n\n");
1666 printf
1667 ("This program is free software: you can redistribute it and/or modify\n"
1668 "it under the terms of the GNU General Public License as published by\n"
1669 "the Free Software Foundation, version 2 of the License.\n\n"
1670 "This program is distributed in the hope that it will be useful,\n"
1671 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1672 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001673 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001674}
1675
1676static void print_usage(const char *name)
1677{
1678 printf("usage: %s [-vhdix?] <filename>\n", name);
1679 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001680 " -d | --dump: dump intel firmware descriptor\n"
1681 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1682 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1683 " -x | --extract: extract intel fd modules\n"
1684 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1685 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001686 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001687 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1688 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1689 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1690 " can only be used once per run:\n"
1691 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1692 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1693 " Dual Output Fast Read Support\n"
1694 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301695 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001696 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001697 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1698 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001699 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301700 " adl - Alder Lake\n"
1701 " aplk - Apollo Lake\n"
1702 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001703 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001704 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001705 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301706 " glk - Gemini Lake\n"
1707 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001708 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301709 " jsl - Jasper Lake\n"
1710 " sklkbl - Sky Lake/Kaby Lake\n"
1711 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001712 " -S | --setpchstrap Write a PCH strap\n"
1713 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001714 " -v | --version: print the version\n"
1715 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001716 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1717 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001718 "\n");
1719}
1720
1721int main(int argc, char *argv[])
1722{
1723 int opt, option_index = 0;
1724 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001725 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001726 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301727 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001728 char *region_type_string = NULL, *region_fname = NULL;
1729 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001730 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001731 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001732 unsigned int value = 0;
1733 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001734 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001735 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1736
Bill XIEfa5f9942017-09-12 11:22:29 +08001737 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001738 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001739 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001740 {"extract", 0, NULL, 'x'},
1741 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001742 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001743 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001744 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001745 {"density", 1, NULL, 'D'},
1746 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001747 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001748 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001749 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301750 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001751 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001752 {"version", 0, NULL, 'v'},
1753 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001754 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001755 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001756 {"setpchstrap", 1, NULL, 'S'},
1757 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001758 {0, 0, 0, 0}
1759 };
1760
Usha P412679d2020-10-15 11:25:08 +05301761 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 -07001762 long_options, &option_index)) != EOF) {
1763 switch (opt) {
1764 case 'd':
1765 mode_dump = 1;
1766 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001767 case 'S':
1768 mode_setstrap = 1;
1769 pchstrap = strtoul(optarg, NULL, 0);
1770 break;
1771 case 'V':
1772 value = strtoul(optarg, NULL, 0);
1773 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001774 case 'f':
1775 mode_layout = 1;
1776 layout_fname = strdup(optarg);
1777 if (!layout_fname) {
1778 fprintf(stderr, "No layout file specified\n");
1779 print_usage(argv[0]);
1780 exit(EXIT_FAILURE);
1781 }
1782 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001783 case 'x':
1784 mode_extract = 1;
1785 break;
1786 case 'i':
1787 // separate type and file name
1788 region_type_string = strdup(optarg);
1789 region_fname = strchr(region_type_string, ':');
1790 if (!region_fname) {
1791 print_usage(argv[0]);
1792 exit(EXIT_FAILURE);
1793 }
1794 region_fname[0] = '\0';
1795 region_fname++;
1796 // Descriptor, BIOS, ME, GbE, Platform
1797 // valid type?
1798 if (!strcasecmp("Descriptor", region_type_string))
1799 region_type = 0;
1800 else if (!strcasecmp("BIOS", region_type_string))
1801 region_type = 1;
1802 else if (!strcasecmp("ME", region_type_string))
1803 region_type = 2;
1804 else if (!strcasecmp("GbE", region_type_string))
1805 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001806 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001807 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001808 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001809 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001810 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001811 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001812 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001813 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001814 else if (!strcasecmp("EC", region_type_string))
1815 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001816 else if (!strcasecmp("Device Exp2", region_type_string))
1817 region_type = 9;
1818 else if (!strcasecmp("IE", region_type_string))
1819 region_type = 10;
1820 else if (!strcasecmp("10GbE_0", region_type_string))
1821 region_type = 11;
1822 else if (!strcasecmp("10GbE_1", region_type_string))
1823 region_type = 12;
1824 else if (!strcasecmp("PTT", region_type_string))
1825 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001826 if (region_type == -1) {
1827 fprintf(stderr, "No such region type: '%s'\n\n",
1828 region_type_string);
1829 print_usage(argv[0]);
1830 exit(EXIT_FAILURE);
1831 }
1832 mode_inject = 1;
1833 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001834 case 'n':
1835 mode_newlayout = 1;
1836 layout_fname = strdup(optarg);
1837 if (!layout_fname) {
1838 fprintf(stderr, "No layout file specified\n");
1839 print_usage(argv[0]);
1840 exit(EXIT_FAILURE);
1841 }
1842 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001843 case 'O':
1844 new_filename = strdup(optarg);
1845 if (!new_filename) {
1846 fprintf(stderr, "No output filename specified\n");
1847 print_usage(argv[0]);
1848 exit(EXIT_FAILURE);
1849 }
1850 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001851 case 'D':
1852 mode_density = 1;
1853 new_density = strtoul(optarg, NULL, 0);
1854 switch (new_density) {
1855 case 512:
1856 new_density = COMPONENT_DENSITY_512KB;
1857 break;
1858 case 1:
1859 new_density = COMPONENT_DENSITY_1MB;
1860 break;
1861 case 2:
1862 new_density = COMPONENT_DENSITY_2MB;
1863 break;
1864 case 4:
1865 new_density = COMPONENT_DENSITY_4MB;
1866 break;
1867 case 8:
1868 new_density = COMPONENT_DENSITY_8MB;
1869 break;
1870 case 16:
1871 new_density = COMPONENT_DENSITY_16MB;
1872 break;
1873 case 32:
1874 new_density = COMPONENT_DENSITY_32MB;
1875 break;
1876 case 64:
1877 new_density = COMPONENT_DENSITY_64MB;
1878 break;
1879 case 0:
1880 new_density = COMPONENT_DENSITY_UNUSED;
1881 break;
1882 default:
1883 printf("error: Unknown density\n");
1884 print_usage(argv[0]);
1885 exit(EXIT_FAILURE);
1886 }
1887 break;
1888 case 'C':
1889 selected_chip = strtol(optarg, NULL, 0);
1890 if (selected_chip > 2) {
1891 fprintf(stderr, "error: Invalid chip selection\n");
1892 print_usage(argv[0]);
1893 exit(EXIT_FAILURE);
1894 }
1895 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001896 case 'M':
1897 mode_altmedisable = 1;
1898 altmedisable = strtol(optarg, NULL, 0);
1899 if (altmedisable > 1) {
1900 fprintf(stderr, "error: Illegal value\n");
1901 print_usage(argv[0]);
1902 exit(EXIT_FAILURE);
1903 }
1904 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001905 case 's':
1906 // Parse the requested SPI frequency
1907 inputfreq = strtol(optarg, NULL, 0);
1908 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001909 case 17:
1910 spifreq = SPI_FREQUENCY_17MHZ;
1911 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001912 case 20:
1913 spifreq = SPI_FREQUENCY_20MHZ;
1914 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001915 case 30:
1916 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1917 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001918 case 33:
1919 spifreq = SPI_FREQUENCY_33MHZ;
1920 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001921 case 48:
1922 spifreq = SPI_FREQUENCY_48MHZ;
1923 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001924 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001925 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001926 break;
1927 default:
1928 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1929 inputfreq);
1930 print_usage(argv[0]);
1931 exit(EXIT_FAILURE);
1932 }
1933 mode_spifreq = 1;
1934 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001935 case 'e':
1936 mode_em100 = 1;
1937 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001938 case 'l':
1939 mode_locked = 1;
1940 if (mode_unlocked == 1) {
1941 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1942 exit(EXIT_FAILURE);
1943 }
1944 break;
Usha P412679d2020-10-15 11:25:08 +05301945 case 'r':
1946 mode_read = 1;
1947 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001948 case 'u':
1949 mode_unlocked = 1;
1950 if (mode_locked == 1) {
1951 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1952 exit(EXIT_FAILURE);
1953 }
1954 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001955 case 'p':
1956 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001957 platform = PLATFORM_APL;
1958 } else if (!strcmp(optarg, "cnl")) {
1959 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08001960 } else if (!strcmp(optarg, "lbg")) {
1961 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001962 } else if (!strcmp(optarg, "dnv")) {
1963 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001964 } else if (!strcmp(optarg, "ehl")) {
1965 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001966 } else if (!strcmp(optarg, "glk")) {
1967 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301968 } else if (!strcmp(optarg, "icl")) {
1969 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301970 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001971 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001972 } else if (!strcmp(optarg, "sklkbl")) {
1973 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001974 } else if (!strcmp(optarg, "tgl")) {
1975 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301976 } else if (!strcmp(optarg, "adl")) {
1977 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001978 } else if (!strcmp(optarg, "ifd2")) {
1979 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05301980 } else if (!strcmp(optarg, "mtl")) {
1981 platform = PLATFORM_MTL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001982 } else {
1983 fprintf(stderr, "Unknown platform: %s\n", optarg);
1984 exit(EXIT_FAILURE);
1985 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001986 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001987 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001988 case 't':
1989 mode_validate = 1;
1990 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001991 case 'v':
1992 print_version();
1993 exit(EXIT_SUCCESS);
1994 break;
1995 case 'h':
1996 case '?':
1997 default:
1998 print_usage(argv[0]);
1999 exit(EXIT_SUCCESS);
2000 break;
2001 }
2002 }
2003
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002004 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002005 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05002006 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002007 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002008 print_usage(argv[0]);
2009 exit(EXIT_FAILURE);
2010 }
2011
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002012 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002013 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06002014 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002015 fprintf(stderr, "You need to specify a mode.\n\n");
2016 print_usage(argv[0]);
2017 exit(EXIT_FAILURE);
2018 }
2019
2020 if (optind + 1 != argc) {
2021 fprintf(stderr, "You need to specify a file.\n\n");
2022 print_usage(argv[0]);
2023 exit(EXIT_FAILURE);
2024 }
2025
2026 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002027 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002028 if (bios_fd == -1) {
2029 perror("Could not open file");
2030 exit(EXIT_FAILURE);
2031 }
2032 struct stat buf;
2033 if (fstat(bios_fd, &buf) == -1) {
2034 perror("Could not stat file");
2035 exit(EXIT_FAILURE);
2036 }
2037 int size = buf.st_size;
2038
2039 printf("File %s is %d bytes\n", filename, size);
2040
2041 char *image = malloc(size);
2042 if (!image) {
2043 printf("Out of memory.\n");
2044 exit(EXIT_FAILURE);
2045 }
2046
2047 if (read(bios_fd, image, size) != size) {
2048 perror("Could not read file");
2049 exit(EXIT_FAILURE);
2050 }
2051
2052 close(bios_fd);
2053
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002054 // generate new filename
2055 if (new_filename == NULL) {
2056 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2057 if (!new_filename) {
2058 printf("Out of memory.\n");
2059 exit(EXIT_FAILURE);
2060 }
2061 // - 5: leave room for ".new\0"
2062 strcpy(new_filename, filename);
2063 strcat(new_filename, ".new");
2064 }
2065
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002066 check_ifd_version(image, size);
2067
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002068 if (mode_dump)
2069 dump_fd(image, size);
2070
Chris Douglass03ce0142014-02-26 13:30:13 -05002071 if (mode_layout)
2072 dump_layout(image, size, layout_fname);
2073
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002074 if (mode_extract)
2075 write_regions(image, size);
2076
Mathew Kingc7ddc992019-08-08 14:59:25 -06002077 if (mode_validate)
2078 validate_layout(image, size);
2079
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002080 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002081 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002082 region_fname);
2083
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002084 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002085 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002086
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002087 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002088 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002089
Jan Tatjefa317512016-03-11 00:52:07 +01002090 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002091 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002092
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002093 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002094 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002095
Alexander Couzensd12ea112016-09-10 13:33:05 +02002096 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002097 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002098
Usha P412679d2020-10-15 11:25:08 +05302099 if (mode_read)
2100 enable_cpu_read_me(new_filename, image, size);
2101
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002102 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002103 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002104
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002105 if (mode_setstrap) {
2106 fpsba_t *fpsba = find_fpsba(image, size);
2107 const fdbar_t *fdb = find_fd(image, size);
2108 set_pchstrap(fpsba, fdb, pchstrap, value);
2109 write_image(new_filename, image, size);
2110 }
2111
Bill XIEb3e15a22017-09-07 18:34:50 +08002112 if (mode_altmedisable) {
2113 fpsba_t *fpsba = find_fpsba(image, size);
2114 fmsba_t *fmsba = find_fmsba(image, size);
2115 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002116 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002117 }
2118
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002119 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002120 free(image);
2121
2122 return 0;
2123}